求助,opencv识别圆问题

a401183680 2018-08-01 12:37:02
要求:采用opencv编程,设计一个统一的方案,从imgs目录中的二值细化图中提取刻度线(使用HoughLinesP函数检测直线),利用刻度线向心性及长短均匀特性计算圆心及半径,使用不同颜色显示在原图上(如下图所示)。
刚刚接触opencv,好多地方都不懂,自己折腾了一个星期,还是达不到要求,不明白如何利用刻度线向心性及长短均匀特性计算圆心及半径。自己摸索着用HoughCirceles函数一步步调参数慢慢得到下图还算良好的结果,但是不知道怎么可以得到图中绿色的刻度线,题目要求应该是可以利用刻度线方便快捷的画出圆,我这种只会慢慢调参数,完全是瞎蒙,完全不一样。网上也搜不到相关的,只能求大神指点迷津,再次感谢
原图:

应该得到的结果:

自己调试结果:

程序如下:
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
//【1】载入原始图和Mat变量定义
Mat srcImage = imread("1.png"); //工程目录下应该有一张名为1.jpg的素材图
Mat midImage, dstImage;//临时变量和目标图的定义

//【2】进行边缘检测和转化为灰度图
Canny(srcImage, midImage, 50, 200, 3);//进行一此canny边缘检测
cvtColor(midImage, dstImage, COLOR_GRAY2BGR);//转化边缘检测后的图为灰度图

//【3】进行霍夫线变换
vector<Vec4i> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
HoughLinesP(midImage, lines, 1, CV_PI / 180, 40, 10, 10);

//【4】依次在图中绘制出每条线段
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA);
}

//【5】转为灰度图并进行图像平滑
cvtColor(srcImage, midImage, COLOR_BGR2GRAY);//转化边缘检测后的图为灰度图
GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);
//【6】进行霍夫圆变换
vector<Vec3f> circles;
HoughCircles(midImage, circles, HOUGH_GRADIENT, 1.5, 300, 130, 50, 138, 220);

//【7】依次在图中绘制出圆
for (size_t i = 0; i < circles.size(); i++)
{
//参数定义
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
//绘制圆心
circle(dstImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
//绘制圆轮廓
circle(dstImage, center, radius, Scalar(75, 170, 75), 3, 8, 0);
}



imshow("【原图】", srcImage);
//【8】显示效果图
imshow("【效果图】", dstImage);

waitKey(0);

return 0;
}
...全文
400 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_39389146 2019-07-24
  • 打赏
  • 举报
回复
请问 为什么我运行该程序 不出现结果,按了键盘也没出现圆圈 求助 谢谢
赵4老师 2018-08-02
  • 打赏
  • 举报
回复
知其然,还要知其所以然。
赵4老师 2018-08-02
  • 打赏
  • 举报
回复
引用 7 楼 a401183680 的回复:
[quote=引用 2 楼 zhao4zhong1 的回复:]

赵老师,一样的程序,为啥我这个歪掉了?

另外,能麻烦您说说如何找出刻度线并利用刻度线吗?[/quote]
修改46行: Mat Structure0=getStructuringElement(MORPH_ELLIPSE,Size(16,16));
试试看能不能不歪掉。

整体思路和步骤是:
1.用足够大的StructuringElement Structure1膨胀
2.用足够大的StructuringElement Structure0腐蚀
得到刻度线组成的近似圆弧构成整个图中包围矩形最大的白色连通区域
3.提取所有轮廓,求其中包围矩形最大的白色连通区域对应轮廓的包围矩形maxrect
4.circle(smallImg,Point(maxrect.x+maxrect.width/2,maxrect.y+int(maxrect.height/2*1.17)),int(maxrect.height/2*1.1),CV_RGB(255,255,0),8);
其中1.17是圆心座标往下偏移的因子,1.1是圆半径扩大的因子。
tiger波波 2018-08-02
  • 打赏
  • 举报
回复
引用 6 楼 a401183680 的回复:
[quote=引用 4 楼 youyingbo 的回复:]
[quote=引用 3 楼 a401183680 的回复:]
首先感谢赵4老师的指导,但是不知道是哪部分出了毛病,运行程序,没有报错,但也没显示结果。

另外,请问老师,利用刻度线向心性及长短均匀特性计算圆心及半径的函数在哪,我还是不知道该如何利用刻度线,而且并没有图中绿色的刻度线那样,也没有用到HoughLinesP函数,是采用了其他的办法实现的吗?


没有这么具体的函数吧,你得自己根据长短均匀特性找出刻度线
而向心性就是所有刻度线的延长线交与圆心区域,从而得出圆心。
圆心加任意一个刻度线可得到半径
圆心加半径得到圆

所以首要的一点就是找到长短一样的一系列刻度线[/quote]
感谢您回复和帮助,的确是需要按一下才能出下一张,另外能稍微讲一下怎么根据长短均匀特性找出刻度线吗,或者给个类似的例子链接也好。道理您说的很清楚,我也很明白,但是正是不知道如何实现这个识别刻度线,所以我才来请教的。
[/quote]

那这个问题就是数据统计问题了。反正你所有线的两个端点都知道了,那么利用三角函数可以算出每条线的长度,形成一个长度数组
然后统计数组中出现次数最多的那个数,在这里就是约等于次数最多的数

https://blog.csdn.net/haojknm/article/details/7048664
a401183680 2018-08-02
  • 打赏
  • 举报
回复
引用 10 楼 zhao4zhong1 的回复:
知其然,还要知其所以然。

是的,还得多研究啊。
a401183680 2018-08-02
  • 打赏
  • 举报
回复
引用 8 楼 youyingbo 的回复:
[quote=引用 6 楼 a401183680 的回复:]
[quote=引用 4 楼 youyingbo 的回复:]
[quote=引用 3 楼 a401183680 的回复:]
首先感谢赵4老师的指导,但是不知道是哪部分出了毛病,运行程序,没有报错,但也没显示结果。

另外,请问老师,利用刻度线向心性及长短均匀特性计算圆心及半径的函数在哪,我还是不知道该如何利用刻度线,而且并没有图中绿色的刻度线那样,也没有用到HoughLinesP函数,是采用了其他的办法实现的吗?


没有这么具体的函数吧,你得自己根据长短均匀特性找出刻度线
而向心性就是所有刻度线的延长线交与圆心区域,从而得出圆心。
圆心加任意一个刻度线可得到半径
圆心加半径得到圆

所以首要的一点就是找到长短一样的一系列刻度线[/quote]
感谢您回复和帮助,的确是需要按一下才能出下一张,另外能稍微讲一下怎么根据长短均匀特性找出刻度线吗,或者给个类似的例子链接也好。道理您说的很清楚,我也很明白,但是正是不知道如何实现这个识别刻度线,所以我才来请教的。
[/quote]

那这个问题就是数据统计问题了。反正你所有线的两个端点都知道了,那么利用三角函数可以算出每条线的长度,形成一个长度数组
然后统计数组中出现次数最多的那个数,在这里就是约等于次数最多的数

https://blog.csdn.net/haojknm/article/details/7048664[/quote]
感谢指导,我去试试看。
a401183680 2018-08-01
  • 打赏
  • 举报
回复
引用 2 楼 zhao4zhong1 的回复:

赵老师,一样的程序,为啥我这个歪掉了?

另外,能麻烦您说说如何找出刻度线并利用刻度线吗?
a401183680 2018-08-01
  • 打赏
  • 举报
回复
引用 4 楼 youyingbo 的回复:
[quote=引用 3 楼 a401183680 的回复:]
首先感谢赵4老师的指导,但是不知道是哪部分出了毛病,运行程序,没有报错,但也没显示结果。

另外,请问老师,利用刻度线向心性及长短均匀特性计算圆心及半径的函数在哪,我还是不知道该如何利用刻度线,而且并没有图中绿色的刻度线那样,也没有用到HoughLinesP函数,是采用了其他的办法实现的吗?


没有这么具体的函数吧,你得自己根据长短均匀特性找出刻度线
而向心性就是所有刻度线的延长线交与圆心区域,从而得出圆心。
圆心加任意一个刻度线可得到半径
圆心加半径得到圆

所以首要的一点就是找到长短一样的一系列刻度线[/quote]
感谢您回复和帮助,的确是需要按一下才能出下一张,另外能稍微讲一下怎么根据长短均匀特性找出刻度线吗,或者给个类似的例子链接也好。道理您说的很清楚,我也很明白,但是正是不知道如何实现这个识别刻度线,所以我才来请教的。
tiger波波 2018-08-01
  • 打赏
  • 举报
回复
引用 3 楼 a401183680 的回复:
首先感谢赵4老师的指导,但是不知道是哪部分出了毛病,运行程序,没有报错,但也没显示结果。

另外,请问老师,利用刻度线向心性及长短均匀特性计算圆心及半径的函数在哪,我还是不知道该如何利用刻度线,而且并没有图中绿色的刻度线那样,也没有用到HoughLinesP函数,是采用了其他的办法实现的吗?


赵老师用了waitkey函数,你需要一下按键盘才能显示下一张
tiger波波 2018-08-01
  • 打赏
  • 举报
回复
引用 3 楼 a401183680 的回复:
首先感谢赵4老师的指导,但是不知道是哪部分出了毛病,运行程序,没有报错,但也没显示结果。

另外,请问老师,利用刻度线向心性及长短均匀特性计算圆心及半径的函数在哪,我还是不知道该如何利用刻度线,而且并没有图中绿色的刻度线那样,也没有用到HoughLinesP函数,是采用了其他的办法实现的吗?


没有这么具体的函数吧,你得自己根据长短均匀特性找出刻度线
而向心性就是所有刻度线的延长线交与圆心区域,从而得出圆心。
圆心加任意一个刻度线可得到半径
圆心加半径得到圆

所以首要的一点就是找到长短一样的一系列刻度线
a401183680 2018-08-01
  • 打赏
  • 举报
回复
首先感谢赵4老师的指导,但是不知道是哪部分出了毛病,运行程序,没有报错,但也没显示结果。

另外,请问老师,利用刻度线向心性及长短均匀特性计算圆心及半径的函数在哪,我还是不知道该如何利用刻度线,而且并没有图中绿色的刻度线那样,也没有用到HoughLinesP函数,是采用了其他的办法实现的吗?
赵4老师 2018-08-01
  • 打赏
  • 举报
回复
赵4老师 2018-08-01
  • 打赏
  • 举报
回复
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
using namespace std;
using namespace cv;
Mat img,smallImg,gray,bw;
vector<Vec4i> hierarchy;
vector<vector<Point> > contours;
int threshval=64;
Rect r;
Rect maxrect,brect;
int idx,n;
const static Scalar colors[15]={
CV_RGB( 0, 0,128),
CV_RGB( 0,128, 0),
CV_RGB( 0,128,128),
CV_RGB(128, 0, 0),
CV_RGB(128, 0,128),
CV_RGB(128,128, 0),
CV_RGB(128,128,128),
CV_RGB(160,160,160),
CV_RGB( 0, 0,255),
CV_RGB( 0,255, 0),
CV_RGB( 0,255,255),
CV_RGB(255, 0, 0),
CV_RGB(255, 0,255),
CV_RGB(255,255, 0),
CV_RGB(255,255,255),
};
Scalar color;
int main() {
cvNamedWindow("display",1);
smallImg=imread("test.png",1);
cvtColor(smallImg,gray,CV_BGR2GRAY);
imshow("display",gray);
waitKey(0);

bw=(gray>threshval);
imshow("display",bw);
waitKey(0);

Mat Structure1=getStructuringElement(MORPH_ELLIPSE,Size(16,16));
dilate(bw,bw,Structure1, Point(-1,-1));
imshow("display",bw);
waitKey(0);
Mat Structure0=getStructuringElement(MORPH_ELLIPSE,Size(20,20));
erode(bw,bw,Structure0,Point(-1,-1));
imshow("display",bw);
waitKey(0);

findContours(bw,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
if (!contours.empty()&&!hierarchy.empty()) {
idx=0;
n=0;
vector<Point> approx;
for (;idx>=0;idx=hierarchy[idx][0]) {
color=colors[idx%15];
// drawContours(smallImg,contours,idx,color,1,8,hierarchy);
approxPolyDP(Mat(contours[idx]), approx, arcLength(Mat(contours[idx]), true)*0.005, true);//0.005为将毛边拉直的系数
const Point* p = &approx[0];
int m=(int)approx.size();
polylines(smallImg, &p, &m, 1, true, color);
circle(smallImg,Point(p[0].x,p[0].y),3,color);
circle(smallImg,Point(p[1].x,p[1].y),2,color);
for (int i=2;i<m;i++) circle(smallImg,Point(p[i].x,p[i].y),1,color);
n++;
if (1==n) {
maxrect=boundingRect(Mat(contours[idx]));
} else {
brect=boundingRect(Mat(contours[idx]));
if (brect.width*brect.height>maxrect.width*maxrect.height) maxrect=brect;
}
}
circle(smallImg,Point(maxrect.x+maxrect.width/2,maxrect.y+int(maxrect.height/2*1.17)),int(maxrect.height/2*1.1),CV_RGB(255,255,0),8);
}
imshow("display",smallImg);
waitKey(0);
cvDestroyWindow("display");
return 0;
}

    本课程分享对由中国开发者提供的OpenCV条形码识别模块的原理和代码精讲。该模块借鉴“目标识别”领域先进理念,采用“定位-识别”二段模式,有效提高了自然环境下条码识别的准确率并保持了C++代码的高速度,相比较常用的zxing和zbar在准确率和识别速度上均有较大优势。更难得可贵的是在代码的实现过程中能够注意细节,在诸如“循环测试确定参数数值”“积分图的使用”“倾斜矩形纠偏”等处,均提供了思路清晰、弹性高的优质代码。作为一套通过了OpenCV官方的代码检验、解决一个常用领域内具体问题的模块,对于图像处理学习来说是难得可贵的。    逐条进行代码解读繁琐且低效,个人认为,在图像处理领域,能够运行和修改观察的代码对于学习研究至关重要。在理论剖析部分,也是由应用引导原理。同时做好知识的迁移和代码的复用工作。在这个过程中,创建针对性的实验非常重要。 课程内容分为4个部分:一是基本配置,包括· 条形码识别模块的安装使用 (cmake配置和OpenCV编译);· 构建用于测试和代码阅读的环境;· 模块对官方数据集的测试;二是条码定位,将详细讲解思路、原理和实现知识迁移部分将简单说一下在毛发识别上的迁移:三是条码识别,该部分内容会首先梳理框架,而后具体进行分析讲解    此外,我们将结合例子,将OpenCV的基础功能,包括积分图像、形态学变化、联通区域、透视变化等进行复习,加深理解。 

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧