avatarZahid Parvez

Summary

The webpage provides a comprehensive guide on performing geometric transformations such as translation, scaling, rotation, affine, and perspective transformations on images using OpenCV in Python.

Abstract

The webpage titled "Geometric Transformations using OpenCV (python)" discusses the application of various image manipulation techniques. It explains that geometric transformations are essential for tasks like rescaling images for different screens, aligning features across images, augmenting data for machine learning, and programmatic sprite animation. The article emphasizes that images are represented as matrices and clarifies the dimensions' terminology, with 'x' corresponding to width (number of columns) and 'y' to height (number of rows). The page details the process of translation (shifting an image by x and y offsets), scaling (resizing the image by a factor or to specific dimensions), and rotation (turning the image by an angle), including the use of transformation matrices and interpolation methods. It also covers affine transformations that preserve line parallelism and perspective transformations that maintain straight lines but alter the image's rotation and scale. The article provides Python functions for each transformation, demonstrating their implementation and showing the output images. It concludes by offering a link to the complete code on GitHub for readers to access and use.

Opinions

  • The author considers geometric transformations to be a fundamental aspect of image processing with a wide range of practical applications.
  • The article suggests that understanding the matrix representation of images is crucial for applying geometric transformations effectively.
  • The author values the preservation of image quality during scaling, highlighting the importance of interpolation methods.
  • The inclusion of a GitHub link indicates the author's support for open-source sharing and community learning.
  • The use of Python functions and their outputs in the article demonstrates the author's didactic approach, aiming to provide clear and practical examples for readers to understand and apply the concepts.

Geometric Transformations using OpenCV (python)

Geometric transformations are a common image processing technique that have numerous applications, such as rescaling images for different screen sizes, aligning features on different images, augmenting data for machine learning, animating sprites programmatically, etc..

Remember that images are represented as matrices, oftentimes resources on the internet, software documentation, and other sources will refer to the dimensions of the image using different terms. It's important to keep the following in mind:

  • x = width = number of columns
  • y = height = number of rows

Translation

Translation is the process of moving an image from its original location by shifting it in x and y directions. To carry out this operation, you need to specify how much movement in the x and y direction is required (lets call this tx, ty).

A transformation matrix will then need to be created. Given tx and ty, a transformation matrix M can be defined as:

Lets define a python function for this transformation:

def ImageTranslation(image, xOffset, yOffset):
    # Translate the image by x and y offset
    # image - input image as a matrix
    # xOffset - offset in x direction
    # yOffset - offset in y direction

    # define the transformation matrix m
    M = np.float32([[1,0,xOffset],[0,1,yOffset]])
    
    # preform the image Translation and return the results
    return cv2.warpAffine(image,M,(image.shape[1], image.shape[0]))

# Translate the image by 200 pixels in the x directrion and 100 in the y direction
translated_im = ImageTranslation(original_im,200,100)

# Show the results 
DisplayImageComparison(original_im, translated_im,"Translated image")
Image translation output

Scaling

Scaling is the process of resizing the image, that is, changing the width and height of the image. This process preserves the orientation of the image. The new size of the image can be defined in 2 ways, either by specifying a scaling factor or by specifying the width and height of the desired image.

When scaling images, the concept of interpolation is essential. this is because when resizing an image, the algorithm will need to determine how to fill in missing values (upscaling) or which values to discard (downscaling) in order to produce a more natural-looking result. If you want to find out more about the various options available, check out this story here on image interpolation in OpenCV.

Lets define a python function that scales the images based on a scaling factor:

def ScaleImageByRatio(image, xScale, yScale, interpolationMethod = cv2.INTER_LINEAR):
    # Scale the image using a scaling factor
    # image - input image as a matrix
    # xScale - scale factor for the x axis (width) 
    # yScale - scale factor for the y axis (height)
    # interpolationMethod - interpolation method used
    
    return cv2.resize(image,None,fx=xScale, fy=yScale, interpolation = interpolationMethod)

# Scale the image 1.5 times on the x axis, and .5 times on the y axis
scaled_im = ScaleImageByRatio(original_im,1.5,.5)

# Show the results 
DisplayImageComparison(original_im, scaled_im,"Scaled image")
Image scaling output (scaling factor)

Lets define a python function that scales the images based the desired dimensions:

def ScaleImageToSize(image, newWidth, newHeight, interpolationMethod = cv2.INTER_LINEAR):
    # Scale the image to a given size
    # image - input image as a matrix
    # newWidth - new Width for the imamge (x axis) 
    # newHeight - new height for the image (y axis)
    # interpolationMethod - interpolation method used
    
    return cv2.resize(image,(newWidth, newHeight), interpolation = interpolationMethod)

# Scale the to 200 (width) x 400 (height)
scaled_im = ScaleImageToSize(original_im,200,400)

# Show the results 
DisplayImageComparison(original_im, scaled_im,"Scaled image")
Image scaling output (defined dimentions)

Rotation

Rotate the image given an angle. The image can be rotated on the midpoint by defining the following transformation matrix (where Θ is the angle of rotation):

OpenCV also allows us to easily preform a similarity transform, we will take advantage of this in the implimentation of the function. In a similiraty transform a midpoint for the rotation can be defined (i.e. the rotation isn’t always from the centre of the image), as well as a way to scale the image in the rotation process. This can be done by setting up the following transformation matrix:

where:

Lets define a python function that preforms a similarity transform (rotate, translates [default is midpoint], scales [default is no scaling]) on the iamge:

def RotateImage(image, angleOfRotation, midPoint = None, scale = 1 ):
    # Preform a similarity transform on the image
    # image - input image as a matrix
    # angleOfRotation - angel of rotation for the output
    # midpoint for the rotation as a (x,y) tuple, defult is centre of image
    # scaling factor for the output
    
    rows,cols = image.shape[:2]
    
    if not midPoint:
        midPoint = (cols/2, rows/2)
    
    M = cv2.getRotationMatrix2D(midPoint,angleOfRotation,scale)
    return cv2.warpAffine(image,M,(cols,rows))

# Rotate the image 20 degrees at the midpoint
rotated_im = ImageTranslation(RotateImage(original_im,20),10,20)

# Show the results 
DisplayImageComparison(original_im, rotated_im,"Rotated image (midpoint)")
Image rotation output (midpoint in middle of image)
# Rotate the image 30 degrees at the pixel 10 (x), 20 (y) and scale the image to .8
rotated_im = RotateImage(original_im,30,(10,20),.5)

# Show the results 
DisplayImageComparison(original_im, rotated_im,"Rotated and scaled image (10 (x), 20 (y))")
Similarity transform output with shifted midpoint and .5x scale

Affine Transformation

Affine transformations preserve the parallelism of lines in an image. To apply a transformation, we need three points from the input image and their corresponding locations in the output image.

In this transform parallelism is preserved, however image rotation and scale is altered to get to the desired output

def AffineTransform(image,orignPoints, destPoints):
    # Preform a affine transform on the image
    # image - input image as a matrix
    # orignPoints - list of list containing original 3 points for the transformation i.e. [[x1,y1],[x2,y2],[x3,y3]]
    # destPoints - list of list containing destination of the 3 points original points i.e. [[x1,y1],[x2,y2],[x3,y3]]
    rows,cols = image.shape[:2]
    origin = np.float32(orignPoints)
    dest = np.float32(destPoints)

    M = cv2.getAffineTransform(origin,dest)

    return cv2.warpAffine(image,M,(cols,rows))

# Perform an affine transform where the 0th pixel from the top and left are shifted by 5
affine_im = AffineTransform(original_im,[[0,0],[0,10],[10,0]],[[0,0],[5,10],[10,5]])

# Show the results 
DisplayImageComparison(original_im, affine_im,"Affine transform")
Affine transform output

Perspective Transformation

To perform perspective transformations, you need a 3x3 transformation matrix. Perspective transformations preserve straight lines — that is, they remain unchanged once the transformation has been made. To find the transformation matrix for this image, you need to know the coordinates of four points on the input image and their corresponding points on the output image. Among these 4 points, 3 of them should not be collinear.

def PerspectiveTransform(image,orignPoints, destPoints):
    # Preform a perspective transform on the image
    # image - input image as a matrix
    # orignPoints - list of list containing original 4 points for the transformation i.e. [[x1,y1],[x2,y2],[x3,y3]]
    # destPoints - list of list containing destination of the 4 points original points i.e. [[x1,y1],[x2,y2],[x3,y3]]
    rows,cols = image.shape[:2]
    origin = np.float32(orignPoints)
    dest = np.float32(destPoints)

    M = cv2.getPerspectiveTransform(origin,dest)

    return cv2.warpPerspective(image,M,(cols,rows))

# Perform a perspective transform where the right side of the image is sticky (points 500,0 and 500,500)
# The left side has been pinched in the y axis by 200 px.
perspective_im = PerspectiveTransform(original_im,[[500,0],[500,500],[0,0],[0,500]],[[500,0],[500,500],[0,100],[0,400]])

# Show the results 
DisplayImageComparison(original_im, perspective_im,"Perspective transform")
Output of the perspective transformation

If you would like to get a copy of the code used in this article, it can be found here on Github.

Opencv
Image Processing
Python
Transformation
Recommended from ReadMedium