I want to find the principal axis of a blob which goes through the centroid of the blob. I was able to find the centroid of the blob, but how can I find the principal axis?
Here’s what I have tried:
JavaScript
x
25
25
1
import cv2
2
import numpy as np
3
4
img = cv2.imread('skin6.jpg')
5
6
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
7
ret, thresh2 = cv2.threshold(imgray, 155, 255, cv2.THRESH_BINARY_INV)
8
9
#find the maximum contour
10
contours, heir = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
11
c = max(contours, key = cv2.contourArea)
12
13
tmpArea = np.zeros(img.shape)
14
cv2.drawContours(tmpArea,[c],0,(255, 255, 255),cv2.FILLED)
15
16
#centroid
17
M = cv2.moments(c)
18
cx = int(M['m10']/M['m00'])
19
cy = int(M['m01']/M['m00'])
20
21
cv2.circle(tmpArea, (cx, cy), 5, (0, 0, 255), -1)
22
23
cv2.imshow("tmpArea", tmpArea)
24
cv2.waitKey(0)
25
These are the images that I used:
I’m expecting something like this. It should connect with the contour properly: Expected
Advertisement
Answer
You can use cv2.fitEllipse
on your detected contour. There’s an OpenCV tutorial on that topic. You get the center of the fitted ellipse, the length of both axes (please have a detailed look at cv2.ellipse
), and the rotation angle. From that information, it’s just some math to get the principal axis through the center.
Here’s your code with some modifications and additions:
JavaScript
1
35
35
1
import cv2
2
import numpy as np
3
4
# Images
5
img = cv2.imread('images/1KXQA.jpg')
6
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
7
thresh2 = cv2.threshold(img_gray, 155, 255, cv2.THRESH_BINARY_INV)[1]
8
tmpArea = np.zeros(img.shape)
9
10
# Contours
11
contours = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
12
c = max(contours, key=cv2.contourArea)
13
cv2.drawContours(tmpArea,[c],0,(255, 255, 255),cv2.FILLED)
14
15
# Centroid
16
M = cv2.moments(c)
17
cx = int(M['m10']/M['m00'])
18
cy = int(M['m01']/M['m00'])
19
cv2.circle(tmpArea, (cx, cy), 5, (0, 0, 255), -1)
20
21
# Ellipse
22
e = cv2.fitEllipse(c)
23
cv2.ellipse(tmpArea, e, (0, 255, 0), 2)
24
25
# Principal axis
26
x1 = int(np.round(cx + e[1][1] / 2 * np.cos((e[2] + 90) * np.pi / 180.0)))
27
y1 = int(np.round(cy + e[1][1] / 2 * np.sin((e[2] + 90) * np.pi / 180.0)))
28
x2 = int(np.round(cx + e[1][1] / 2 * np.cos((e[2] - 90) * np.pi / 180.0)))
29
y2 = int(np.round(cy + e[1][1] / 2 * np.sin((e[2] - 90) * np.pi / 180.0)))
30
cv2.line(tmpArea, (x1, y1), (x2, y2), (255, 255, 0), 2)
31
32
# Output
33
cv2.imshow('tmpArea', tmpArea)
34
cv2.waitKey(0)
35
The output looks like this:
JavaScript
1
9
1
----------------------------------------
2
System information
3
----------------------------------------
4
Platform: Windows-10-10.0.16299-SP0
5
Python: 3.8.5
6
NumPy: 1.19.5
7
OpenCV: 4.5.1
8
----------------------------------------
9