Python OpenCV:以给定角度通过轮廓形心的线
我从下面的图像中获得了一个名为Python OpenCV:以给定角度通过轮廓形心的线,python,opencv,image-processing,line,contour,Python,Opencv,Image Processing,Line,Contour,我从下面的图像中获得了一个名为cnt的轮廓: 我可以找到像这样的质心: M = cv2.moments(cnt) centroid_x = int(M['m10']/M['m00']) centroid_y = int(M['m01']/M['m00']) 现在我想画N条线,每一条线之间360/N度,从质心开始,在所有可能的交点处切割轮廓。函数需要起点和终点,但我没有终点 如果我画了一条穿过质心的直线,斜率为Tan(360/N),我会使用按位_和找到该直线与轮廓的交点,但我无法找到绘制该直线
cnt
的轮廓:
我可以找到像这样的质心:
M = cv2.moments(cnt)
centroid_x = int(M['m10']/M['m00'])
centroid_y = int(M['m01']/M['m00'])
现在我想画N条线,每一条线之间360/N度,从质心开始,在所有可能的交点处切割轮廓。函数需要起点和终点,但我没有终点
如果我画了一条穿过质心的直线,斜率为Tan(360/N),我会使用按位_和找到该直线与轮廓的交点,但我无法找到绘制该直线的方法
任何关于如何划定这些界限的帮助都将不胜感激 我有些东西在工作。这有点特别,但这基本上是我写的算法。我必须重建你图像的轮廓,所以我所做的是手动读取图像,提取物体最外层的轮廓,然后从那里开始。cv2.line
方法的优点在于,如果您画了一条超出边界的线,该线将被图像边界剪裁。这将在我编写的算法中很有用
不用多说,以下是步骤:
读取图像,然后反转图像,使黑色轮廓线变为白色点
检测最外面的轮廓
创建原始输入图像的副本,以便我们可以绘制线条。将此调出
创建一个“参考”图像,存储步骤2中找到的最外层轮廓
检测轮廓点的质心。还可以访问图像的宽度和高度。如果没有任何宽度或高度值,请选择一个非常大的值。。。大概1000左右吧。您需要确保该值超出轮廓上任何点的最大值。另外,设置所需的角度总数,N
对于每个角度,对于i=0,1
到N-1
:
a。创建一个临时空白图像
b。计算适当的角度:i*(360/N)
并转换为弧度
c。在临时图像上,从轮廓的质心到图像外部的坐标绘制一条线,以确保我们沿所需角度向图像边界绘制一条线。此行的水平分量是cos(360/N)
(此处参数以度为单位),而垂直分量是-sin(360/N)
(参数也以度为单位)。负数是因为在图像坐标空间中,y
轴向下是正的,所以负数是要将其还原,这样正数相对于笛卡尔坐标向上。这样做的原因是,当我们计算每条线与中心的夹角时,这些夹角将是正确的,因为正角度逆时针扫掠。从质心开始,我们将移动水平方向的图像宽度和垂直方向的图像高度,以保持先前发现的水平和垂直分量。这将使我们画出边界外的线,但该线将被图像边界剪裁
另一个复杂之处是在这个临时图像中画一条足够厚的线。如果我们画了一条只有1像素厚的线,你可能会遇到这样的情况:由于像素的采样和线的绘制方式,线与轮廓不相交。我在这里选择了5像素的厚度来确定
d。使用此临时图像,查看哪些位置等于参考图像。对于任何相等的位置,我们已经找到了这条线与原始图像轮廓相交的位置。因此,请选择任何相交的位置,因为粗线很可能会与最外层轮廓产生多个交点
e。使用步骤(d),从out
的质心到我们在步骤(d)中找到的位置画一条线
对所有角度重复步骤6<代码>输出
将包含步骤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()
#步骤#1
img=cv2.imread('contour.png',0)
img_bw=img我有些东西在工作。这有点特别,但这基本上是我写的算法。我必须重建你图像的轮廓,所以我所做的是手动读取图像,提取物体最外层的轮廓,然后从那里开始。cv2.line
方法的优点在于,如果您画了一条超出边界的线,该线将被图像边界剪裁。这将在我编写的算法中很有用
不用多说,以下是步骤:
读取图像,然后反转图像,使黑色轮廓线变为白色点
检测最外面的轮廓
创建原始输入图像的副本,以便我们可以绘制线条。将此调出
创建一个“参考”图像,存储步骤2中找到的最外层轮廓
检测轮廓点的质心。还可以访问图像的宽度和高度。如果没有任何宽度或高度值,请选择一个非常大的值。。。大概1000左右吧。您需要确保该值超出轮廓上任何点的最大值。另外,设置所需的角度总数,N
对于每个角度,对于i=0,1
到N-1
:
a。创建一个临时空白图像
b。计算适当的角度:i*(360/N)
并转换为弧度
c。在临时图像上,从轮廓的质心到图像外部的坐标绘制一条线,以确保
findContours( f, contours, heirarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
Moments M = moments( contours[0], true );
Point2f cntr = Point2f( (int)M.m10/M.m00, (int)M.m01/M.m00 );
circle( frame, cntr, 5, Scalar(0,0,0) );
int N = 20;
vector<float> slopes;
for( int i=0; i<N; i++ )
slopes.push_back( i*360.0/N );
for( auto s : slopes )
for( auto p : contours[0] )
if( std::abs( cv::fastAtan2( p.y-cntr.y, p.x-cntr.x ) - s ) <= 0.5 ) //error margin, of sorts..
{ finalpoints.push_back( p ); break; }
cout<<"\nfound points: "<<finalpoints.size()<<endl;
for( auto p : finalpoints )
line( frame, cntr, p, Scalar(0,0,0), 1 );