Search code examples
pythonimage-processingcomputer-visionobject-detectiondata-augmentation

Rotate polygons without cutting edges


I am writing an augmentation code to rotate annotated polygons inside images. I wrote a code but it's not working right. Just Copy paste the code and you can get the results. Thank you for helping me out.

Image:

enter image description here

Need to rotate the image as well as a polygon for respective angle. Currently, I am not able to rotate the polygon

enter image description here

The image is rotated but the polygon is still in its place.

I tried This code. It rotates the polygon but not at the right position

import math
from PIL import Image, ImageDraw
from PIL import ImagePath 
from PIL import Image
import matplotlib.pyplot as plt
from math import sin, cos, radians
import requests
from io import BytesIO

def rotatePolygon(polygon, degrees, height, width):
    """ 
    Description:
    
        Rotate polygon the given angle about its center. 
        
    Input:
        polygon (list of tuples)  : list of tuples with (x,y) cordinates 
                                    e.g [(1,2), (2,3), (4,5)]
        
        degrees int               : Rotation Degrees
    
    Output:
    
        polygon (list of tuples)  : Polygon rotated on angle(degrees)
                                e.g [(1,2), (2,3), (4,5)]
    
    """
    # Convert angle to radians
    theta = radians(degrees)  
    
    # Getting sin and cos with respect to theta
    cosang, sinang = cos(theta), sin(theta) 

    # find center point of Polygon to use as pivot
    y, x = [i for i in zip(*polygon)]
    
    # find center point of Polygon to use as pivot
    
    cx = width / 2
    cy = height / 2
    
    # Rotating every point
    new_points = []
    for x, y in zip(x, y):
        tx, ty = x-cx, y-cy
        new_x = (tx*cosang + ty*sinang) + cx
        new_y = (-tx*sinang + ty*cosang) + cy
        new_points.append((new_y, new_x))
    return new_points



# Polygon
xy = [(85, 384), (943, 374), (969, 474), (967, 527), (12, 540), (7, 490)]
degrees = 270


# Getting Image from URL
try:
    img = Image.open("polygon_image.png")
except:
    url = "https://github.com/SohaibAnwaar/Mask---RCNN-Polygons-/blob/main/2_image_augmentation/extras/problamatic_image.jpg?raw=true"
    response = requests.get(url)
    img = Image.open(BytesIO(response.content))
    img.save("polygon_image.png")



# Rotating Image
rotated_image = img.rotate(degrees,expand = True)
h, w = img.size

print("NotRotated", xy)
rotated_xy = rotatePolygon(xy, 360 - (degrees), h, w)



# Ploting Rotated Image
img1 = ImageDraw.Draw(rotated_image)  
img1.polygon(rotated_xy, fill ="#FFF000", outline ="blue") 


# Ploting Straight Image
img1 = ImageDraw.Draw(img)  
img1.polygon(xy, fill ="#FFF000", outline ="blue") 

plt.imshow(rotated_image)
plt.show()


plt.imshow(img)
plt.show()

Solution

  • Rotation equations are:

    xnew = x * cos(theta) - y * sin(theta)
    ynew = x * sin(theta) + y * cos(theta)
    

    only mistake you are doing is this:

    new_x = (tx*cosang - ty*sinang) + cy
    new_y = (tx*sinang + ty*cosang) + cx
    

    After rotating image, cx and cy should be changed

    Your complete code is as below:

    import math
    import numpy as np
    from PIL import Image, ImageDraw
    from PIL import ImagePath 
    from PIL import Image
    import matplotlib.pyplot as plt
    from math import sin, cos, radians
    import requests
    from io import BytesIO
    
    def rotatePolygon(polygon, degrees, height, width):
        """ 
        Description:
        
            Rotate polygon the given angle about its center. 
            
        Input:
            polygon (list of tuples)  : list of tuples with (x,y) cordinates 
                                        e.g [(1,2), (2,3), (4,5)]
            
            degrees int               : Rotation Degrees
        
        Output:
        
            polygon (list of tuples)  : Polygon rotated on angle(degrees)
                                    e.g [(1,2), (2,3), (4,5)]
        
        """
        # Convert angle to radians
        theta = radians(degrees)
        
        # Getting sin and cos with respect to theta
        cosang, sinang = cos(theta), sin(theta) 
    
        # find center point of Polygon to use as pivot
        y, x = [i for i in zip(*polygon)]
        
        # find center point of Polygon to use as pivot
        
        cx1 = width[0] / 2
        cy1 = height[0] / 2
        cx2 = width[1] / 2
        cy2 = height[1] / 2
        
        # Rotating every point
        new_points = []
        for x, y in zip(x, y):
            tx, ty = x-cx1, y-cy1
            new_x = (tx*cosang - ty*sinang) + cx2
            new_y = (tx*sinang + ty*cosang) + cy2
            new_points.append((new_y, new_x))
        return new_points
    
    
    
    # Polygon
    xy = [(85, 384), (943, 374), (969, 474), (967, 527), (12, 540), (7, 490)]
    degrees = 270
    
    
    # Getting Image from URL
    try:
        img = Image.open("polygon_image.png")
    except:
        url = "https://github.com/SohaibAnwaar/Mask---RCNN-Polygons-/blob/main/2_image_augmentation/extras/problamatic_image.jpg?raw=true"
        response = requests.get(url)
        img = Image.open(BytesIO(response.content))
        img.save("polygon_image.png")
    
    
    
    # Rotating Image
    rotated_image = img.rotate(degrees,expand = True)
    h1, w1 = img.size
    h2, w2 = rotated_image.size
    
    print("NotRotated", xy)
    rotated_xy = rotatePolygon(xy, degrees, [h1,h2], [w1,w2])
    
    
    
    # Ploting Rotated Image
    img1 = ImageDraw.Draw(rotated_image)  
    img1.polygon(rotated_xy, fill ="#FFF000", outline ="blue") 
    
    
    # Ploting Straight Image
    img1 = ImageDraw.Draw(img)  
    img1.polygon(xy, fill ="#FFF000", outline ="blue") 
    
    plt.imshow(rotated_image)
    plt.show()
    
    
    plt.imshow(img)
    plt.show()