我有一个名为 cnt
的轮廓从下图得到:
我能够找到这样的质心:
M = cv2.moments(cnt)
centroid_x = int(M['m10']/M['m00'])
centroid_y = int(M['m01']/M['m00'])
我现在想画 N 条线,每条线相隔 360/N 度,从质心开始,在所有可能的交点处穿过轮廓。 cv2.line() 函数需要起点和终点,但我没有终点。
如果我画了一条通过质心的线,斜率为 Tan(360/N),我会使用
bitwise_and
找到线与轮廓的交点。但我无法想出画出那条线的方法。任何有关如何绘制此类线条的帮助将不胜感激。
最佳答案
我得到了一些工作。这有点特别,但这基本上是我写的算法。我必须重建图像的轮廓,所以我手动读取图像,提取对象的最外层轮廓,然后从那里开始。 cv2.line
有什么好处?方法是,如果您绘制的线超出范围,则该线将被图像边界剪切。这在我写的算法中很有用。
事不宜迟,以下是步骤:
out
. N
. i = 0, 1
高达 N - 1
:一种。创建临时空白图像
湾。计算合适的角度:
i*(360 / N)
并转换为弧度C。在临时图像上,从轮廓的质心到图像外部的坐标画一条线,以确保我们沿着我们想要的角度向图像边界画一条线。这条线的水平分量是
cos(360/N)
(这里的参数是度数)而垂直分量是 -sin(360/N)
(参数也以度为单位)。负面的原因是 y
轴在我们的图像坐标空间中是向下的正数,所以负数是反转它,以便正数相对于笛卡尔坐标向上。这样做的原因是,当我们计算每条线与中心所成的角度时,角度将是正确的,因为正角度逆时针扫过。从质心开始,我们将移动水平图像的宽度和垂直图像的高度,保持之前找到的水平和垂直分量。这将使我们画出边界线,但线会被图像边界剪裁。另一个复杂之处是在这个临时图像中画一条线,即 。足够厚的。如果我们画了一条只有 1 个像素粗的线,由于像素的采样和线的绘制方式,您可能会遇到线不与轮廓相交的情况。为了确定,我在这里选择了 5 个像素的厚度。
d。使用这个临时图像,查看哪些位置是 等于 引用图像。对于任何相等的位置,我们已经找到了这条线与原始图像的轮廓相交的位置。因此,选择任何相交的位置,因为粗线很可能会与最外层轮廓产生多个相交点。
e.使用步骤 (d),从
out
的质心画一条线到我们在步骤 (d) 中找到的位置。 out
将包含我们在第 6 步完成后的结果。 废话不多说,下面是我写的代码:
# Step #1
img = cv2.imread('contour.png', 0)
img_bw = img <= 128
img_bw = 255*img_bw.astype('uint8')
# Step #2
contours, _ = cv2.findContours(img_bw,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
# Step #3
out = img.copy()
# Step #4
ref = np.zeros_like(img_bw)
cv2.drawContours(ref, contours, 0, 255, 1)
# Step #5
M = cv2.moments(contours[0])
centroid_x = int(M['m10']/M['m00'])
centroid_y = int(M['m01']/M['m00'])
# Get dimensions of the image
width = img.shape[1]
height = img.shape[0]
# Define total number of angles we want
N = 20
# Step #6
for i in range(N):
# Step #6a
tmp = np.zeros_like(img_bw)
# Step #6b
theta = i*(360/N)
theta *= np.pi/180.0
# Step #6c
cv2.line(tmp, (centroid_x, centroid_y),
(int(centroid_x+np.cos(theta)*width),
int(centroid_y-np.sin(theta)*height)), 255, 5)
# Step #6d
(row,col) = np.nonzero(np.logical_and(tmp, ref))
# Step #6e
cv2.line(out, (centroid_x, centroid_y), (col[0],row[0]), 0, 1)
# Show the image
# Step #7
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
这是我得到的结果。我选择了20个角度:
关于python - OpenCV:以给定角度穿过轮廓质心的线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28710337/