我有一个名为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
找到该线与轮廓的交点,但我无法弄清楚画一条线的方法。
如何绘制这些线条的任何帮助将非常感激。
答案 0 :(得分:1)
我得到了一些工作。它有点特别,但这基本上就是我写的算法。我不得不重建你的图像的轮廓,所以我做的是我手动读取图像,提取对象的最外轮廓,然后从那里开始。 cv2.line
方法的优点在于,如果绘制一条超出界限的线条,则线条将被图像边界剪切。这在我写的算法中很有用。
不用多说,这些是以下步骤:
out
。N
。对于我们拥有的每个角度,i = 0, 1
最多N - 1
:
一个。创建临时空白图像
湾计算适当的角度:i*(360 / N)
并转换为弧度
℃。在临时图像上,从轮廓的质心到图像外部的坐标绘制一条线,以确保我们沿着我们想要的角度绘制一条朝向图像边界的线。此行的水平分量为cos(360/N)
(参数以度为单位),而垂直分量为-sin(360/N)
(参数也以度为单位)。负面原因是y
轴在我们的图像坐标空间中向下是正向的,所以负面是为了使正向相对于笛卡尔坐标向上反转。这样做的原因是,当我们计算每条线与中心形成的角度时,角度将是正确的,因为正角度逆时针扫过。从质心开始,我们将移动图像的宽度,水平和图像的高度垂直保持先前找到的水平和垂直分量。这将使我们画出超出界限的线条,但线条将被图像边界剪切。
另一个复杂的问题是在这张足够厚的临时图像中画一条线。如果我们绘制一条只有1像素厚的线,则可能会出现这样一种情况:由于像素的采样和绘制线的方式,线与轮廓不相交。我在这里选择了5像素的厚度。
d。使用此临时图像,查看哪些位置等于参考图像。对于任何相同的位置,我们已经找到该线与原始图像的轮廓相交的位置。因此,选择任何相交的位置,因为粗线最有可能与最外面的轮廓产生多个交叉点。
即使用步骤(d),从out
的质心到我们在步骤(d)中找到的位置画一条线。
对所有角度重复步骤#6。 {#1}}将在步骤#6完成后包含我们的结果。
不用多说,这里是我写的代码:
out
这是我得到的结果。我选择了20个角度:
答案 1 :(得分:1)
我会以一种老式的方式投入,我怀疑这可能是STL加速或对编译器的普遍信任;)。顺便说一下,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 );