钢管识别项目2
零、相关说明:
首先进行一下相关说明。在“jsxyhelu.cnblogs.com/项目实战派”栏目里面出现的需求、图片和其他资源,都是我在浏览威客网站、论坛等网站的时候通过正规渠道获得的真实需求。个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目。但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块。希望能够给浏览者一些启发。如果你认为这些图片和资源放在这里不合适,请及时联系我(1755311380@qq.com),我会及时处理的。此外,我会将核心代码和技术细节尽可能将清楚,我认为这样才是最有价值的方式。如果需要原始代码,也可以和我联系。
一、需求
将“钢管识别项目1”中识别出来的结果导入Csharp的GUI中,通过手工辅助操作,对识别的结果进行修正。
二、初步分析
现在已经实现了图像处理的相关算法,能够自动处理图像得到上图的结果,那么下面需要做的就是
2.1)传递结果到Csharp中去;
采用的方法是比较熟悉的"csharp调用dll文件"方法。麻烦之处在于这里的结果数量比较大,而且其大小不固定。所以我尝试采用了“外文件参数”的方法。
修改相关的代码,使得能够将所有圆的坐标打印出来
//寻找被填充的部分
threshold(gray,thresh,240,250,THRESH_OTSU);
erode(thresh,thresh,Mat());
erode(thresh,thresh,Mat());
contours.clear();
selectContours.clear();
findContours(thresh.clone(),contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
for (int i=0;i<contours.size();i++)
{
if ( contourArea(contours[i])>188 && contourArea(contours[i])<388 )
{
//drawContours(srcClone,contours,i,Scalar(0,0,255));
selectContours.push_back(contours[i]);//将经过筛选的轮廓保存起来
}
}
for (int i=0;i<selectContours.size();i++)
{
Point2f center;
float radius;
minEnclosingCircle(selectContours[i],center,radius);
if (radius > 10*0.8 && radius < 10*1.4)
{
if (ellipseLikeCircle(minEllipse[i]))
{
circle(src,center,radius,Scalar(0,0,255));
//ellipse( src,minEllipse[i],Scalar(255,0,0));
pair<Point2f,float> tmp;
tmp.first = center;
tmp.second = radius;
resultPair.push_back(tmp);
}
}
}
//打印结果
fstream ftxt;
ftxt.open("c:/GO_FindTube_Param.ini",ios::out); //写入的方式,覆盖写入
if(ftxt.fail())
{
cout<<"can not open it"<<endl;
getchar();
return 0;
}
for (int i=0;i<resultPair.size();i++)
{
pair<Point2f,float> tmp = resultPair[i];
ftxt<<tmp.first.x<<" "<<tmp.first.y<<" "<<tmp.second<<endl;
}
ftxt.close();
erode(thresh,thresh,Mat());
erode(thresh,thresh,Mat());
contours.clear();
selectContours.clear();
findContours(thresh.clone(),contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
for (int i=0;i<contours.size();i++)
{
if ( contourArea(contours[i])>188 && contourArea(contours[i])<388 )
{
//drawContours(srcClone,contours,i,Scalar(0,0,255));
selectContours.push_back(contours[i]);//将经过筛选的轮廓保存起来
}
}
for (int i=0;i<selectContours.size();i++)
{
Point2f center;
float radius;
minEnclosingCircle(selectContours[i],center,radius);
if (radius > 10*0.8 && radius < 10*1.4)
{
if (ellipseLikeCircle(minEllipse[i]))
{
circle(src,center,radius,Scalar(0,0,255));
//ellipse( src,minEllipse[i],Scalar(255,0,0));
pair<Point2f,float> tmp;
tmp.first = center;
tmp.second = radius;
resultPair.push_back(tmp);
}
}
}
//打印结果
fstream ftxt;
ftxt.open("c:/GO_FindTube_Param.ini",ios::out); //写入的方式,覆盖写入
if(ftxt.fail())
{
cout<<"can not open it"<<endl;
getchar();
return 0;
}
for (int i=0;i<resultPair.size();i++)
{
pair<Point2f,float> tmp = resultPair[i];
ftxt<<tmp.first.x<<" "<<tmp.first.y<<" "<<tmp.second<<endl;
}
ftxt.close();
432.967 294.45 11.3052
461 290 10.949
571 288.5 11.3417
517.214 286.643 9.90404
88.7667 286.767 11.4066
627 287 11.5157
599.571 287.714 11.1538
537.269 284.86 12.7203
487.5 287 11.3417
395 285.5 10.617
257.093 288.093 11.6269
145.085 286.573 10.5136
311 286 11.7438
……
导入并且画圆,结果看起来还不错。里面的误差来自于数值转化的时候的误差,在本例中不是大问题。
2.2)坐标统一化操作
本例的图片显示和上面的圆的计算,都是和实际图片相一致的。实际运用中可能会出现在显示的时候需要进行图片缩放的情况,这个时候,需要计算出缩放的比率,并且在最后画圆的时候有所考虑。
2.3)编写合适的界面处理代码,使得交互工作能够运行和达到效果。
能够选中某一个圆,并且删除一个圆
能够创建一个圆
三、结果(看视频)
小结:目前这种方法应该说是能够解决一定问题的。而且由于目前使用winform通过dll调用opencv的方法也比较熟悉了,使用起来比较顺手。
解决目前这个需求应该是问题不大了,更多的问题可能需要晕倒真实项目的时候来解决吧。