[Python] Image rotation: model for angle detection using pytorch

Discussão em 'Python' iniciado por Stack, Abril 7, 2025.

  1. Stack

    Stack Membro Participativo

    Basically I am trying to create a model that will detect angle on which a specific image is rotated. Also I have a dataset of 1500 documents resulting with images rotated on

    random.sample([0, 90, -90, 180], 2)


    and each of this angles has variation of

    random.uniform(-10, 10)


    resulting in ~4k rotated images.

    So I've come up with current model to predict sin and cos of the desired angle:

    class CnnRotateRegression(nn.Module):
    def __init__(self):
    super(CnnRotateRegression, self).__init__()
    self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
    self.conv2 = nn.Conv2d(64, 128, kernel_size=3)
    self.conv3 = nn.Conv2d(128, 256, kernel_size=3)
    self.conv4 = nn.Conv2d(256, 512, kernel_size=3)
    self.conv5 = nn.Conv2d(512, 512, kernel_size=3)

    self.bn1 = nn.BatchNorm2d(64)
    self.bn2 = nn.BatchNorm2d(128)
    self.bn3 = nn.BatchNorm2d(256)
    self.bn4 = nn.BatchNorm2d(512)
    self.bn5 = nn.BatchNorm2d(512)

    self.activation = nn.ReLU()
    self.pool = nn.AvgPool2d(kernel_size=2)
    self.pool2 = nn.AdaptiveAvgPool2d((8,8))

    self.linear_l1 = nn.Linear(512*8*8, 512)
    self.linear_l2 = nn.Linear(512, 256)
    self.linear_l3 = nn.Linear(256, 2) # sin + cos

    def forward(self, x):
    x = self.activation(self.pool(self.bn1(self.conv1(x))))
    x = self.activation(self.pool(self.bn2(self.conv2(x))))
    x = self.activation(self.pool(self.bn3(self.conv3(x))))
    x = self.activation(self.pool(self.bn4(self.conv4(x))))
    x = self.activation(self.pool(self.bn5(self.conv5(x))))

    x = self.pool2(x)
    x = x.view(x.size(0), -1)

    x = self.activation(self.linear_l1(x))
    x = self.activation(self.linear_l2(x))
    x = self.linear_l3(x)

    x = F.normalize(x, p=2, dim=1)

    return x


    training part:

    model = CnnRotateRegression()
    model = model.to(device)

    loss_function = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    num_of_epochs = 11


    for epoch in range(num_of_epochs):
    model.train()
    running_loss = 0.0
    for images, labels in tqdm(train_Loader, desc="training loop"):

    images, labels = images.to(device), labels.to(device).float()

    angles = angle_to_sin_cos(labels)
    norm_angles = F.normalize(angles, p=2, dim=1)

    optimizer.zero_grad()
    outputs = model(images)
    loss = loss_function(outputs, norm_angles)
    loss.backward()
    optimizer.step()

    running_loss += loss.item()
    train_loss = running_loss / len(train_Loader)


    functions to convert sin and cos to angle and vice versa:

    def angle_to_sin_cos(angle):
    tensor_angle = angle.clone().detach()
    radian = tensor_angle * torch.pi / 180.0
    return torch.stack([torch.cos(radian), torch.sin(radian)], dim=1)

    def sin_cos_to_angle(outputs):
    cos_val, sin_val = outputs[:, 0], outputs[:, 1]
    angle_rad = torch.atan2(sin_val, cos_val)
    angle_deg = angle_rad * (180 / torch.pi)
    return angle_deg


    My model performs poorly in determining small angles in range +-10 degrees. What would You suggest to improve/enhance to achieve better "small-degree" prediction? Thank you in advance!

    Continue reading...

Compartilhe esta Página