pythonopencvimage-processingcomputer-visionobject-detection

Image detection with rotation (2D)


I try to find the best way to detect images with the rotation. Without rotation cv2.matchTemplate works pretty fine, but I found no function for rotated images. I need the position and angle of the template images in the big picture. Any idea is welcome, I hope the example makes it clear.
thanks for help and support.

template image:

template image

big picture:

big picture


Solution

  • Here is a simplistic approach in Python/OpenCV to get the rotation angle, centroid and width and height of the rotated bounding box of the image.

    The approach is to get (and filter contours on area), then draw them white filled on a black background to merge the contours. Then get the convex hull of the merged contour and compute the rotated rectangle from the contour of the convex hull. That returns the rotation angle, centroid and rotated bounding box dimensions.

    #!/bin/python3.12
    
    import cv2
    import numpy as np
    
    # read the input image as grayscale
    img = cv2.imread('ace_image.png')
    
    # convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # threshold image and invert
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]
    
    # Find external contours
    contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if len(contours) == 2 else contours[1]
    minArea=100
    mask = np.zeros_like(thresh)
    for c in contours: 
        area=cv2.contourArea(c) 
        if area > minArea:
            cv2.drawContours(mask,[c],0,(255),-1)
    
                        
    # draw white filled contour on black background for combined bounding box
    points = np.column_stack(np.where(mask.transpose() > 0))
    hull = cv2.convexHull(points)
    
    # draw convex hull in white filled on black 
    hull_img = np.zeros_like(thresh)
    cv2.fillPoly(hull_img, [hull], 255)
    
    # get rotated rectangle for combined bounding box
    contours = cv2.findContours(hull_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if len(contours) == 2 else contours[1]
    c = max(contours, key=cv2.contourArea)
    rotrect = cv2.minAreaRect(c)
    (center), (width,height), angle = rotrect
    print('width x height:', width, "x", height)
    print('center', center)
    print('angle', angle)
    box = cv2.boxPoints(rotrect)
    boxpts = np.int32(box)
    
    # draw rotated rectangle on copy of image
    rotrect_img = img.copy()
    cv2.drawContours(rotrect_img,[boxpts],0,(0,255,0),2)
    
    # write results images
    cv2.imwrite('ace_image_combined_contour.jpg', mask)
    cv2.imwrite('ace_image_convexhull.jpg', hull_img)
    cv2.imwrite('ace_image_rotated_rectangle.jpg', rotrect_img)
    
    # show results
    cv2.imshow('combined contours',  mask)
    cv2.imshow('convex hull',  hull_img)
    cv2.imshow('rotated rectangle', rotrect_img)
    cv2.waitKey(0)
    

    Combined Contour Image:

    enter image description here

    ConvexHull Image:

    enter image description here

    Rotated Rectangle On Copy Of Image:

    enter image description here

    Text Output:

    width x height: 23.33452033996582 x 45.96194076538086
    center (129.5, 95.0)
    angle 45.0