Search code examples
pythonnumpyimage-manipulationimage-rotation

Getting a incorrect picture output when running my self-made rotation algorithm


In order to better understand how image manipulation works, I've decided to create my own image rotation algorithm rather than using cv2.rotate() However, I'm encountering a weird picture cropping and pixel misplacement issue.

I think it may have something to do with my padding, but there may be other errors

import cv2

import math

import numpy as np
# Load & Show original image
img = cv2.imread('Lena.png', 0)
cv2.imshow('Original', img)

# Variable declarations
h = img.shape[0]  # Also known as rows

w = img.shape[1]  # Also known as columns

cX = h / 2 #Image Center X

cY = w / 2 #Image Center Y

theta = math.radians(100) #Change to adjust rotation angle

imgArray = np.array((img))

imgArray = np.pad(imgArray,pad_width=((100,100),(100,100)),mode='constant',constant_values=0) 
  #Add padding in an attempt to prevent image cropping

# loop pixel by pixel in image
for x in range(h + 1):

 for y in range(w + 1):

  try:
   TX = int((x-cX)*math.cos(theta)+(y-cY)*math.sin(theta)+cX) #Rotation formula 

   TY = int(-(x-cX)*math.sin(theta)+(y-cY)*math.cos(theta)+cY) #Rotation formula

   imgArray[x,y] = img[TX,TY]

  except IndexError as error:

   print(error)

cv2.imshow('Rotated', imgArray)

cv2.waitKey(0)

Edit:

I think the misplaced image position may have something to do with lack of proper origin point, however I cannot seem to find a functioning solution to that problem.


Solution

  • Though I didn't dive in the math part of the domain, but based on the given information I think the matrix rotating formula should work like this:

    UPDATE:

    As I promised I dived a bit into the domain and got to the solution you can see as follows. The main trick that I've swapped the source and destination indices in the looping too, so the rounding doesn't mean any problem ever:

    import cv2
    import math
    import numpy as np
    
    
    # Load & Show original image
    img = cv2.imread('/home/george/Downloads/lena.png', 0)
    cv2.imshow('Original', img)
    
    
    # Variable declarations
    h = img.shape[0]  # Also known as rows
    w = img.shape[1]  # Also known as columns
    
    p = 120
    h += 2 * p 
    w += 2 * p
    
    cX = h / 2 #Image Center X
    cY = h / 2 #Image Center Y
    
    theta = math.radians(45) #Change to adjust rotation angle
    
    imgArray = np.zeros_like((img))  
    
    #Add padding in an attempt to prevent image cropping
    imgArray = np.pad(imgArray, pad_width=p, mode='constant', constant_values=0)   
    img = np.pad(img, pad_width=p, mode='constant', constant_values=0)   
    
    # loop pixel by pixel in image
    for TX in range(h + 1):
        for TY in range(w + 1):
            try:
                x = int( +(TX - cX) * math.cos(theta) + (TY - cY) * math.sin(theta) + cX) #Rotation formula 
                y = int( -(TX - cX) * math.sin(theta) + (TY - cY) * math.cos(theta) + cY) #Rotation formula
    
                imgArray[TX, TY] = img[x, y]
    
            except IndexError as error:
               pass
    #           print(error)
    
    cv2.imshow('Rotated', imgArray)
    cv2.waitKey(0)
    exit()
    

    enter image description here

    Note: See usr2564301 comment too, if you want to dive deeper in the domain.