OpenCV with Python - 3

Content

See more

Introduction

In today’s tutorial, we’re going to talk about how to crop the image. Also, add additional infomation on the images such as lines, retangle and text. Furthermore, we ‘are going to know how to change the perspective of the image.

Resize and crop

We have already mentioned how to resize the image. However, in some special event, we want to random crop our image or crop the image at the center to get the specific information.

For example, when we train the classification model and want to improve the performance, we may try to do the random crop to get different kinds of images. (In fact, most of the deep learning library have built-in function to finish the job.)

Essentially put, image is a matrix will value in it. Therefore, if we want to crop the image, we can just focus on one part of the matrix and only get those values. The only thing should be noticed is the matrix was start from top-left corner.

  • Function in OpenCV
    import cv2
    
    img = cv2.imread("resources/food.jpg")
    
    '''
    # Crop the image
    target region: (height, width)
    height pixel: 500~900
    width pixel: 300~1000
    '''
    img_cropped = img[500:900, 300:1000]
    
    # Show the image
    cv2.imshow("Image", img)
    cv2.imshow("Cropped image", img_cropped)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)
    Origin image

Cropped image

Draw on the image

We’re going to demonstrate how to use the function.

  • Circle

    • cv2.circle(img, origin, radius, color, thickness)
      • img: Image to draw
      • origin: Pixel to be the origin.
      • radius: Radius of the circle.
      • color: Color of the circle. ==(RGB)==
      • thickness: Thickness of the circle. To fill the circle put cv2.FILLED.
        # Example
        cv2.circle(img_cir, (250, 250), 100, (255, 0, 255), 3)
        cv2.circle(img_cir, (250, 250), 100, (255, 0, 255), cv2.FILLED)
  • Rectangle

    • cv2.rectangle(img, upper_left, lower_right, color, thickness)
      • img: Image to add rectangle.
      • upper_left: Top-left corner of the rectangle. ==(Place of the matrix)==
      • lower_right: Down-right corner of the rectangle. ==(Place of the matrix)==
      • color: Color of rectangle.
      • thickness: Thickness of rectangle. To fill the circle put cv2.FILLED.
        # Example
        cv2.rectangle(img_rec, (0, 0), (250, 350), (0, 0, 255), 3)
        cv2.rectangle(img_rec, (250, 350), (250, 350), (255, 0, 0), cv2.FILLED)
  • Line

    • cv2.line(img, start_point, end_point, color, thickness)

      • img: Image to add line.
      • start_point: Position to start line. ==(Place of the matrix)==
      • end_point: Position to end line. ==(Place of the matrix)==
      • color: Color of line.
      • thickness: Thickness of line.
        cv2.line(img_line, (0, 0), (img.shape[1], img.shape[0]), (0, 255, 0), 3)
  • Text

    • cv2.putText(img, text, start_place, font type, scale, color, thickness)
      • text: Text to be put on.
      • start_point: buttom-left corner of the text. ==(Place of the matrix)==
      • font type: The type of the text.
      • scale: Scale of the text.
        cv2.putText(img_text, "OpenCV", (300, 100), 
                    cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 3)
  • Demostration*

import cv2
import numpy as np

'''
# Create a black image
0: black
255: white
'''
img_black = np.zeros((512, 512), np.uint8)

# Create color image, need 3 channels
img_blue = np.zeros((512, 512, 3), np.uint8)
img_blue[:] = [255, 0, 0]

'''
Try out
img_blue[200:300, 300, 400] = [255, 0, 0]
'''

# Add green line
img_line = np.zeros((512, 512, 3), np.uint8)
cv2.line(img_line, (0, 0), (img.shape[1], img.shape[0]), (0, 255, 0), 3)

## Add rectangle
img_rec = np.zeros((512, 512, 3), np.uint8)
cv2.rectangle(img_rec, (0, 0), (250, 350), (0, 0, 255), 3)
cv2.rectangle(img_rec, (250, 350), (img.shape[1], img.shape[0]), (255, 0, 0), cv2.FILLED)

## Add Circle
img_cir = np.zeros((512, 512, 3), np.uint8)
cv2.circle(img_cir, (250, 250), 100, (255, 0, 255), cv2.FILLED)

## Add Text
img_text = np.zeros((512, 512, 3), np.uint8)
cv2.putText(img_text, "OpenCV", (300, 100), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 3)

# Show the result
cv2.imshow("Black image", img_black)
cv2.imshow("Blue image", img_blue)
cv2.imshow("Line", img_line)
cv2.imshow("Rectangle", img_rec)
cv2.imshow("Circle", img_cir)
cv2.imshow("Text", img_text)


cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

Perspective

To get the specific part of the image, we have to change the perspective of the image. For example, we have lots of pockers.


We only want to get the Ace in the image.


Let’s see how we achieve the result. In order to change the perspective, we should first know all four vertexs of the target. After that, we have to determine the new size of the image. Then we can do the transform.

You can use different application such as Photoshop or just the image viewer in your computer to find out the vertex. The order of pst1(in below code session) doesn’t matter. However, you should be aware the order of pst2 should have the right transformation w.r.t. pst1.

import cv2
import numpy as np

img = cv2.imread("resources/pocker.jpg")

cv2.imshow("Image", img)

# New size of the output
width, height = 250, 350

'''
pst1: old position
pst2: new position 
transform pst1 -> pst2
'''
pts1 = np.float32([[239, 103], [356, 146], [179, 277], [296, 320]])
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])

# Transformation matrix
matrix = cv2.getPerspectiveTransform(pts1, pts2)

# Get the new image
img_output = cv2.warpPerspective(img, matrix, (width, height))

cv2.imshow("New image", img_output)

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

Try to break the correct transformation or change the order to see the result by yourself!

For instance:

# Break the correct transformation
pts1 = np.float32([[356, 146], [239, 103], [179, 277], [296, 320]])
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])

#-------------------#

# Change the order but still with right transformation
pts1 = np.float32([[356, 146], [239, 103], [179, 277], [296, 320]])
pts2 = np.float32([[width, 0], [0, 0], [0, height], [width, height]])

Join the image

To show different kinds of images in one result or feel tedious to type cv2.imshow(...) we can stack the images together.

  • np.hstack()

    We use numpy function to stack the image. You can make a list of images to be the input.

    import cv2
    import numpy as np
    
    img = cv2.imread("resources/food.jpg")
    
    # horizotal stack
    img_hor = np.hstack((img, img))
    
    # Show the result
    cv2.imshow("Horizontal image", img_hor)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)
  • np.vstack()

    Same as np.hstack(), but with the vertical result.

    import cv2
    import numpy as np
    
    img = cv2.imread("resources/food.jpg")
    
    # Vertival stack
    img_ver = np.vstack((img, img))
    
    # Show the result
    cv2.imshow("Vertical image", img_ver)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)
  • Self-define function

    To first scale the image and stack the images with multilayers, we can write our own function. ==The code below is came from MURTAZA’S WORKSHOP.==

    '''
    The code below came from MURTAZA'S WORKSHOP
    '''
    
    def stackImages(scale, imgArray):
    '''
    scale: New scale of the image
    imgArray: Images to stack.
    '''
    
    rows = len(imgArray)
    cols = len(imgArray[0])
    
    # Check whether we have multilayers
    rowsAvailable = isinstance(imgArray[0], list)
    
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    
    if rowsAvailable:
        for x in range (0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
                    
                if len(imgArray[x][y].shape) == 2: 
                    imgArray[x][y]= cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)
                    
        imageBlank = np.zeros((height, width, 3), np.uint8)
        
        hor = [imageBlank] * rows
        
        # First put each horizontal image to its horizontal place
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        
        # Stack each array to the vertical format
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
                
            if len(imgArray[x].shape) == 2: 
                imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
                
        hor = np.hstack(imgArray)
        ver = hor
        
    return ver
    import cv2
    import numpy as np
    
    img = cv2.imread('resources/beauty.jpg')
    img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
    # Stack image
    img_stack = stackImages(0.5, [[img, img_gray, img],[img, img, img]])
    
    # Show the image
    cv2.imshow("ImageStack",img_stack)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)

Reference

  1. MURTAZA’S WORKSHOP
  2. LEARN OPENCV in 3 HOURS with Python (2020)

Comments

Unable to load Disqus, please make sure your network can access.