How to Detect Shapes in Python Using OpenCV?

Posted in /  

How to Detect Shapes in Python Using OpenCV?
vinaykhatri

Vinay Khatri
Last updated on April 19, 2024

    Detecting shapes from an image is one of the coolest things you can perform with Python and OpenCV. There are many methods and techniques available in the OpenCV library to detect shapes in an image, and for most of them, we first find out the edges in the image and then detect its shape.

    We can either use canny edge or contours methods to find edges in an image, and then according to the edge detection, we can name the shape.

    In this Python tutorial, we will walk you through the different Python scripts to detect shapes in an image using OpenCV. Moreover, we will use the Python OpenCV library and use the contour edge detection method to detect the shapes in the image.

    So let's start with installing the OpenCV library for the Python environment.

    Install Python OpenCV

    OpenCV is one of the most popular Python image processing libraries. We can easily install this library for our Python environment using the following Python pip install terminal command:

    pip install opencv-python

    For this tutorial, we will be using the following image and detecting the shape from this image only. shape.png

    How to Detect Shapes in Python Using OpenCV?

    1) Detect a Circle in an Image Using OpenCV in Python

    import cv2 as cv
    #import image
    image = cv.imread("shape.png")
    
    #convert image into greyscale mode
    gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    
    #find threshold of the image
    _, thrash = cv.threshold(gray_image, 240, 255, cv.THRESH_BINARY)
    contours, _ = cv.findContours(thrash, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    
    for contour in contours:
        shape = cv.approxPolyDP(contour, 0.01*cv.arcLength(contour, True), True)
        x_cor = shape.ravel()[0]
        y_cor = shape.ravel()[1]-15
        
        if len(shape) >12:
            cv.drawContours(image, [shape], 0, (0,0,255), 4)
            cv.putText(image, "Circle", (x_cor, y_cor), cv.FONT_HERSHEY_COMPLEX, 0.5, (0,0,255))
            
    cv.imshow("Shape", image)
    cv.waitKey(0)
    cv.destroyAllWindows()

    Output

    Behind the code

    • In the first line of the program, we have imported the OpenCV cv2 module as cv .
    • The imread() method loads the "shape.png" image in our script.
    • The cv.cvtColor(image, cv.COLOR_BGR2GRAY) statement converts the loaded BGR image into a grayscale image because we do not need color intensities to detect shapes.
    • The cv.threshold(gray_image, 240, 255, cv.THRESH_BINARY) function finds out the threshold frequency of the grayscale image, gray_image , for further image processing. 240 is the threshold value, and 255 is the maximum threshold value.
    • cv.findContours(thrash, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) is the function that will find out all the contours present in the grayscale image based on the thresholds. To know more about the OpenCV counter, click here .
    • After finding all the contours, we loop over every contour and detect the shape.
    • The cv.approxPolyDP() function returns all the polygons curve based on the contour with precision. Both the True parameters specify the close contour and curve.
    • ravel()[0] and ravel()[1] functions return the x and y coordinates of the contour, and we will use these two coordinates to write the shape name.
    • The approxPolyDP() function returns the approximate curves. Using the len() function, we can find out the total number of curves present in that close loop. A circle can have an infinite number of curved edges as arcs, but for this tutorial, we have specified that if the shape has more than 12 curves or edges, it should be treated as a circle.
    • The drawContours(image, [shape], 0, (0,0,255), 4) function will draw the contours over the original image (0,0,255) color code and 4 border thickness.
    • The putText() function will write the shape name over the detected shape.

    2) Detect Square and Rectangle in an Image Using OpenCV

    Similar to the above program, we can find out the square and rectangle shapes in an image. Both squares and rectangles have the same number of edges, but using the aspect ratio, we can find out whether the shape is a square or a rectangle.

    import cv2 as cv
    image = cv.imread("shape.png")
    #convert image into greyscale mode
    gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    
    #find threshold of the image
    _, thrash = cv.threshold(gray_image, 240, 255, cv.THRESH_BINARY)
    contours, _ = cv.findContours(thrash, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    
    for contour in contours:
        shape = cv.approxPolyDP(contour, 0.01*cv.arcLength(contour, True), True)
        x_cor = shape.ravel()[0]
        y_cor = shape.ravel()[1]
        
        if len(shape) ==4:
            #shape cordinates
            x,y,w,h = cv.boundingRect(shape)
    
            #width:height
            aspectRatio = float(w)/h
            cv.drawContours(image, [shape], 0, (0,255,0), 4)
            if aspectRatio >= 0.9 and aspectRatio <=1.1:
                cv.putText(image, "Square", (x_cor, y_cor), cv.FONT_HERSHEY_COMPLEX, 0.5, (0,0,0))
            else:
                cv.putText(image, "Rectangle", (x_cor, y_cor), cv.FONT_HERSHEY_COMPLEX, 0.5, (255,0,0))
            
    cv.imshow("Shape", image)
    cv.waitKey(0)
    cv.destroyAllWindows()

    Output

    Behind the code The above square and rectangle shape detection code is similar to the circle detection program. The only difference is that here we have detected the shape if it has len(shape)==4 , and to differentiate a square from a rectangle, we have found out the width and height aspect ratio. Although for a perfect square, the aspect ratio should be 1, here we have considered some noises and treated the shape as a square if its aspect ratio lies between 0.9 to 1.1.

    3) Detect Triangle and Polygon in an Image Using OpenCV in Python

    Now let's detect polygon and triangle shapes in an image. The code will remain mostly the same as in the previous program. We only need to specify an if...elif condition, where if the shape length is 3, it would be a triangle, and if the shape length is 5, it would be a polygon.

    import cv2 as cv
    image = cv.imread("shape.png")
    #convert image into greyscale mode
    gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    
    #find threshold of the image
    _, thrash = cv.threshold(gray_image, 240, 255, cv.THRESH_BINARY)
    contours, _ = cv.findContours(thrash, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    
    for contour in contours:
        shape = cv.approxPolyDP(contour, 0.01*cv.arcLength(contour, True), True)
        x_cor = shape.ravel()[0]
        y_cor = shape.ravel()[1]
    
        #For triangle
        if len(shape) ==3:
            cv.drawContours(image, [shape], 0, (0,255,0), 4)
            cv.putText(image, "Triangle", (x_cor, y_cor), cv.FONT_HERSHEY_COMPLEX, 0.5, (0,0,0))
    
        #for polygon
        if len(shape) ==5:
            cv.drawContours(image, [shape], 0, (0,255,0), 4)
            cv.putText(image, "Polygon", (x_cor, y_cor), cv.FONT_HERSHEY_COMPLEX, 0.5, (0,0,0))
    
            
    cv.imshow("Shape", image)
    cv.waitKey(0)
    cv.destroyAllWindows()

    Output

    Conclusion

    In this Python OpenCV tutorial, we used the approxPolyDP() function to find out the closed shape in an image. This method will work fine if the image, as well as all the shapes present in the image, are clear. There is another popular shape detection method called the Hough Transform technique present in OpenCV, but it is limited to detecting a circle. The approxPolyDP() technique is emerging as a better alternative when we want to detect different shapes in an image.

    People are also reading:

    Leave a Comment on this Post

    0 Comments