“This is the 26th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Hu invariant moments

Hu invariant moments hold translation, scaling, and rotation invariant, while all moments (except the seventh moment) are invariant for reflection. The seventh moment is altered by reflection, allowing it to distinguish between mirrored images. OpenCV provides cv2.humoments () to calculate the seven Hu invariant moments, using the following method:

Cv2. HuMoments (m, hu []) - huCopy the code

Here, M corresponds to moments calculated with cv2.moments() and the output HU corresponds to seven HU invariant moments. The seven Hu invariant moments are defined as follows:


h u [ 0 ] = n u 20 + n u 02 h u [ 1 ] = ( n u 20 n u 02 ) 2 + 4 n u 11 2 h u [ 2 ] = ( n u 30 3 n u 12 ) 2 + ( 3 n u 21 n u 03 ) 2 h u [ 3 ] = ( n u 30 + n u 12 ) 2 + ( n u 21 + n u 03 ) 2 h u [ 4 ] = ( n u 30 3 n u 12 ) ( n u 30 + n u 12 ) [ ( n u 30 + n u 12 ) 2 3 ( n u 21 + n u 03 ) 2 ] + ( 3 n u 21 n u 03 ) ( n u 21 + n u 03 ) [ 3 ( n u 30 + n u 12 ) 2 ( n u 21 + n u 03 ) 2 ] h u [ 5 ] = ( n u 20 n u 02 ) [ ( n u 30 + n u 12 ) 2 ( n u 21 + n u 03 ) 2 ] + 4 ( n u 30 + n u 12 ) ( n u 21 + n u 03 ) h u [ 6 ] = ( 3 n u 21 n u 03 ) ( n u 21 + n u 03 ) [ 3 ( n u 30 + n u 12 ) 2 ( n u 21 + n u 03 ) 2 ] ( n u 30 3 n u 12 ) ( n u 21 + n u 03 ) [ 3 ( n u 30 + n u 12 ) 2 ( n u 21 + n u 03 ) 2 ] \begin{aligned} hu[0]&=nu_{20}+nu_{02} \\ hu[1]&=(nu_{20}-nu_{02})^2+4\cdot nu_{11}^2 \\ hu[2]&=(nu_{30}-3\cdot nu_{12})^2+(3\cdot nu_{21}- nu_{03})^2 \\ hu[3]&=(nu_{30}+nu_{12})^2+(nu_{21}+ nu_{03})^2 \\ hu[4]&=(nu_{30}-3\cdot nu_{12})(nu_{30}+nu_{12})[(nu_{30}+nu_{12})^2-3\cdot(nu_{21}+nu_{03})^2]+(3\cdot nu_{21}- nu_{03})(nu_{21}+ nu_{03})[3\cdot (nu_{30}+nu_{12})^2-(nu_{21}+ nu_{03})^2]\\ hu[5]&=(nu_{20}-nu_{02})[(nu_{30}+nu_{12})^2-(nu_{21}+nu_{03})^2]+4\cdot(nu_{30}+nu_{12})(nu_{21}+ nu_{03})\\ hu[6]&=(3\cdot nu_{21}- nu_{03})(nu_{21}+ nu_{03})[3\cdot (nu_{30}+nu_{12})^2-(nu_{21}+nu_{03})^2]-(nu_{30}-3\cdot nu_{12})(nu_{21}+ nu_{03})[3\cdot (nu_{30}+nu_{12})^2-(nu_{21}+ nu_{03})^2] \end{aligned}

Next, a program is written to calculate 7 Hu invariant moments. In order to calculate invariant moments, cv2.moments() must be used first to calculate moments. When calculating image moments, you can use vector shapes or images, and if the binaryImage parameter is true (for images only), all non-zero pixels in the input image will be treated as 1. After calculating the image moments using vector shapes and images, Hu invariant moments are calculated according to the calculated moments.

Load the image and convert it to a grayscale image
image = cv2.imread("example.png")
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Get binary image
ret, thresh = cv2.threshold(gray_image, 70.255, cv2.THRESH_BINARY)
# Calculate the image moment, and the transfer parameter is the image
M = cv2.moments(thresh, True)
print("moments: '{}'".format(M))
def centroid(moments) :
    Calculation of centroid from image moment
    x_centroid = round(moments['m10'] / moments['m00'])
    y_centroid = round(moments['m01'] / moments['m00'])
    return x_centroid, y_centroid
# Calculate the center of mass
x, y = centroid(M)
# Calculate Hu moment and print
HuM = cv2.HuMoments(M)
print("Hu moments: '{}'".format(HuM))

# Transfer contour when calculating image moment, repeat the above calculation process
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
M2 = cv2.moments(contours[0])
print("moments: '{}'".format(M2))
x2, y2 = centroid(M2)
# Draw outline
draw_contour_outline(image, contours, (255.0.0), 10)
Draw the center of mass
cv2.circle(image, (x, y), 25, (255.255.0), -1)
cv2.circle(image, (x2, y2), 25, (0.0.255), -1)
# Print center of mass
print("('x','y'): ('{}','{}')".format(x, y))
print("('x2','y2'): ('{}','{}')".format(x2, y2))
The show_img_with_matplotlib() function is similar to the previous example and will not be described again
def show_thresh_with_matplotlib(thresh, title, pos) :
    ax = plt.subplot(1.2, pos)
    plt.imshow(thresh, cmap='gray')
    plt.title(title, fontsize=8)
    plt.axis('off')
show_img_with_matplotlib(image, "detected contour and centroid".1)
show_thresh_with_matplotlib(thresh, 'thresh'.2)
plt.show()
Copy the code

Observing the calculated moments, Hu invariant moments, and the center of mass, it can be seen that the results obtained using vector shapes and images are similar, but slightly different, for example, the center of mass obtained:

('x','y'): ('1124','1713')
('x2','y2'): ('1157','1636')
Copy the code

The coordinates differ by a few pixels due to the limited resolution of the rasterized image. The moments estimated for the contour are slightly different from those calculated for the rasterized contour. You can see the output of the program in the figure above, where the two centroids are shown in different colors to see how different they are before.

Next, to compare Hu invariants, we use three images. The first one is the original image, the second one rotates the original image 180 degrees, and the third one flips the original image horizontally to calculate the Hu invariant moment of the above image.

The first step of the program is to load images using cv2.imread() and convert them to grayscale images by using cv2.cvtColor(). The second step is to apply cv2.threshold() to get the binary image. Finally, Hu invariant moment is calculated using Cv2.humoments () :

Load the image and convert it
images = [image_1, image_2, image_3]
des = ['original'.'rotation'.'reflection']
for i in range(len(images)):
    image = images[i]
    # Convert to grayscale image
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # Image binarization
    ret, thresh = cv2.threshold(gray_image, 100.255, cv2.THRESH_BINARY)
    # Calculate Hu invariant moment
    HuM_1 = cv2.HuMoments(cv2.moments(thresh, True)).flatten()
    Print Hu invariants
    print("Hu moments ({}): '{}'".format(des[i], HuM_1))
    # visualization
    show_img_with_matplotlib(image, "original".1+i )

plt.show()
Copy the code

View the calculated Hu moment invariant results:

Hu moments (original): '[3.01270761E-01 2.85277848E-02 6.91011783E-03 3.83970453E-04-3.46840290E-07-3.85059443E-05 5.20465006E-07]' Hu moments (rotation): '[3.01270761E-01 2.85277848E-02 6.91011783E-03 3.83970453E-04-3.46840290E-07-3.85059443E-05 5.20465006E-07]' Hu moments (reflection): '[3.01270761E-01 2.85277848E-02 6.91011783E-03 3.83970453E-04-3.46840290E-07-3.85059443E-05-5.20465006E-07]'Copy the code

It can be seen that the calculated Hu invariant moment is the same in all three cases except for the seventh moment.

A link to the

OpenCV contour detection in detail

OpenCV image moments in detail