Python cv2包如何测量圆心角

How to measure the central angle with Python cv2 package

我们的团队设置了一个带有相机、显微镜和可调透镜的视觉系统来观察锥体的内表面。

从视觉上讲,相机会为一个锥体拍摄 12 张图像,每张图像覆盖 30 度。

现在我们收集了很多样图,想确保每个"fan"(如下图)至少是30度。

Python中有没有什么方法可以用cv2或其他包来测量这个圆心角。谢谢

听起来有可能。您需要进行一些预处理和过滤以确定有效的方法,并且可能涉及一些调整。

可以使用三种方法。

1.)

基本思路是以某种方式得到两条线并测量它们之间的角度。

  • 定义一个阈值来定义外部黑色区域(圆心角外),并将其下方的所有值设置为零。

  • 这也会将中心角内的一些模糊条纹设置为零,因此我们必须尝试 "heal" 将它们移除。这是通过使用 形态转换 完成的。您可以阅读它们 here and here.

  • 你可以尝试关闭操作,但我不知道它是否修复了条纹。通常它会修复斑点或划痕。 似乎表明它应该在线工作。

  • 也许在那个时候再次应用一些高斯模糊和阈值。然后尝试使用一些边缘或线检测。

这基本上是试错法,您必须看看有什么用。

2.)

  • 另一个可行的方法是尝试使用圆弧-enter code here样的划痕,甚至可以加强它们并使用Hough Circle Transform。我认为它也能检测到弧线。

  • 试试吧,看看有什么功能returns。在最好的情况下,有几个圆/弧可以用来估计圆心角。

  • several approaches on arc detection here on Whosebug or here.

  • 我不确定你的所有图像是否都一样,但上面的图像看起来有一些细的、绿色和粉红色的弧线似乎一直沿着中心角延伸。您可以使用它来过滤该颜色,然后将其设为灰度。

  • This question 可能会有帮助。

3.)

  • 应用边缘过滤器,例如 Canny skimage.feature.canny

  • 尝试几个西格玛和post您问题中的图像,然后我们可以尝试思考如何继续。

  • 可行的方法是计算属于边的所有点周围的凸包。然后从凸包得到构成圆心角的两条直线

这是 Python/OpenCV 中的一种方法。

  • 阅读图片
  • 转换为灰色
  • 阈值
  • 使用形态学打开和关闭来平滑和填充边界
  • 应用 Canny 边缘提取
  • 通过将每个边缘的相对侧涂黑,将图像分为顶部边缘和底部边缘
  • 将线条拟合到顶部和底部边缘
  • 计算每条边的角度
  • 计算两个角度的差值
  • 在输入上画线
  • 保存结果

输入:

import cv2
import numpy as np
import math

# read image
img = cv2.imread('cone_shape.jpg')

# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# threshold
thresh = cv2.threshold(gray,11,255,cv2.THRESH_BINARY)[1]

# apply open then close to smooth boundary
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13,13))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = np.ones((33,33), np.uint8)
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)

# apply canny edge detection
edges = cv2.Canny(morph, 150, 200)
hh, ww = edges.shape
hh2 = hh // 2

# split edge image in half vertically and blacken opposite half
top_edge = edges.copy()
top_edge[hh2:hh, 0:ww] = 0
bottom_edge = edges.copy()
bottom_edge[0:hh2, 0:ww] = 0

# get coordinates of white pixels in top and bottom
# note: need to transpose y,x in numpy to x,y for opencv
top_white_pts = np.argwhere(top_edge.transpose()==255)
bottom_white_pts = np.argwhere(bottom_edge.transpose()==255)

# fit lines to white pixels
# (x,y) is point on line, (vx,vy) is unit vector along line
(vx1,vy1,x1,y1) = cv2.fitLine(top_white_pts, cv2.DIST_L2, 0, 0.01, 0.01)
(vx2,vy2,x2,y2) = cv2.fitLine(bottom_white_pts, cv2.DIST_L2, 0, 0.01, 0.01)

# compute angle for vectors vx,vy
top_angle = (180/math.pi)*math.atan(vy1/vx1)
bottom_angle = (180/math.pi)*math.atan(vy2/vx2)
print(top_angle, bottom_angle)

# cone angle is the difference
cone_angle = math.fabs(top_angle - bottom_angle)
print(cone_angle)

# draw lines on input
lines = img.copy()
p1x1 = int(x1-1000*vx1)
p1y1 = int(y1-1000*vy1)
p1x2 = int(x1+1000*vx1)
p1y2 = int(y1+1000*vy1)
cv2.line(lines, (p1x1,p1y1), (p1x2,p1y2), (0, 0, 255), 1)
p2x1 = int(x2-1000*vx2)
p2y1 = int(y2-1000*vy2)
p2x2 = int(x2+1000*vx2)
p2y2 = int(y2+1000*vy2)
cv2.line(lines, (p2x1,p2y1), (p2x2,p2y2), (0, 0, 255), 1)

# save resulting images
cv2.imwrite('cone_shape_thresh.jpg',thresh)
cv2.imwrite('cone_shape_morph.jpg',morph)
cv2.imwrite('cone_shape_edges.jpg',edges)
cv2.imwrite('cone_shape_lines.jpg',lines)

# show thresh and result    
cv2.imshow("thresh", thresh)
cv2.imshow("morph", morph)
cv2.imshow("edges", edges)
cv2.imshow("top edge", top_edge)
cv2.imshow("bottom edge", bottom_edge)
cv2.imshow("lines", lines)
cv2.waitKey(0)
cv2.destroyAllWindows()


阈值图像:

形态学处理图像:

边缘图像:

输入行数:

锥角(以度为单位):

42.03975696357633