目标分割和检测笔记(OpenCV实例精解)
2017-10-04 20:03
645 查看
版本说明:Opencv 3.2.0版本
1)差分
2)除法
图像差分是最简单的方法。如果有光纹矩阵L和图像矩阵I,去除R的结果是他们之间的差值:
R=L-I
除法去除R的结果是
R=255×(1-I/L)
下面给出差分代码 img为需要删除光的图像,pattern位光纹遮挡
下面是除法
注意 :除法需要用32位浮点型才能分离图像。
可以用blur原图来估计背景。估计背景的方法如下:
在输入图像上使用大尺寸核矩阵模糊化,这是一种在OCR中常用的技术。虽然与上述方法存在差异,但足以消除背景类。函数如下:
下面给出自己根据上述函数做的效果图。这是用差分法后的去光效果:
下面是用除法的
可以发现两种方式都能有效的把背景光去掉。注意,我可是开的手电筒哦。。
threshold 全局二值化
一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,最常用的方法就是设定一个全局的阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。将大于T的像素群的像素值设定为白色(或者黑色),小于T的像素群的像素值设定为黑色(或者白色)。
这里可以使用两个不同阀值的threshold函数:从图片中可以看出非兴趣区域是黑色或者很低值,删除光/背景时,可以使用一个低值.
下面是阀值化后的效果
可以看出大部分感兴趣区域已经亮起来啦,这里的阀值需要自己根据实际慢慢调整。。当然我这个兴趣区域太大啦而且是在晚上室内灯下做的,可能效果不好。
double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type )
参数说明:
src:输入图像。
dst:输出图像。
thresh:阀值T。
maxval:向上最大值
type:类型
详细解释大家可以看看这位大佬总结的http://blog.csdn.net/guduruyu/article/details/68059450
1)连通区域
2)findContours函数
连通域是使用8或者4链接像素标记图像的迭代算法。
4连通:只有横向和竖向连通。
8连通:在4连通的基础上加上了对角连通。
OpenCV3中提供有下面两个不同功能的连通区域算法:
1)connectedComponents(image,labels,connectivity=8,type=CV_32S)
2)connectedComponentsWithStats(image,labels,stats,centroids,connectivity=8,ltype=CV_32S)
这两个函数返回一个表示检测到几个标签的整数,标签0表示背景,1表示第一个对象,然后依次类推。
connectedComponents的参数说明:
Image :待标记的输入图像
Label :这是一个Mat,是输出,其输出一个与输入大小相同的图像,每个像素都有各自标签值,0代表背景,1代表连通区域的第一个对象,2代表第二个对象,以此类推。
Connectivity:有两个可能值,4或者8。分别表示4连通方式还是8连通方式。
Type:这是想要使用的标签图像类型:只允许两种类型,CV_32S或CV_16U.
connectedComponentsWithStats的参数说明:
Image :待标记的输入图像
Label :这是一个Mat,是输出,其输出一个与输入大小相同的图像,每个像素都有各自标签值,0代表背景,1代表连通区域的第一个对象,2代表第二个对象,以此类推。
Connectivity:有两个可能值,4或者8。分别表示4连通方式还是8连通方式。
Type:这是想要使用的标签图像类型:只允许两种类型,CV_32S或CV_16U.
Stats :包括背景标签在内的所有标签的输出参数。以下统计值可以通过统计数据(标签。列)访问,列也同样定义,具体如下:
××××××CC_STAT_LEFT:这是连通区域对象的左边x坐标
××××××CC_STAT_TOP:这是连通区域对象的顶层y坐标
××××××CC_STAT_WIDTH:这定义连通区域对象边框的宽度
××××××CC_STAT_HEIGHT:这定义连通区域对象边框的高度
××××××CC_STAT_AREA:这是连通区域对象的像素(区)数量
Centroids:每个标签(包含背景)的浮点型质心点。
下面给出函数,就不给图了(总不能把我自己分割类吧),书上是针对一些零件分割的,自行想象上面已出的图,效果应该不错。
A:此处括号是我自己加的 便于理解,个人认为labels是mat类,里面存以不同标签号的图
B:randomColor其实就是将随机数/255的作用。 setTo(x,mask)自己理解为只处理mask,即矩阵不为0的地方,并将x得到的三通到颜色给予mask
下面用connectedComponentsWithStats()来显示更多信息的输出结果图像。
下面是其函数:
A: centroids.at < Point2d > (i)表示第i个连通域的质心 stats.at < int>(i,CC_STAT_AREA)为连通域像素的数量。
void findContours(InputOutputArray image, OutputArrayofArrays contours, OutputArray hierarchy, int mode,int method,Point offset=Point())
每个参数的含义如下:
image:二进制输入图像。
contours:输出轮廓,每个检测出来的输出轮廓是点向量,通常用vector < vector< Point> >类型来保存。
hierarchy:储存轮廓层次结构的可选输出向量,可以得到每个轮廓之间的关系的图像拓扑。具体可以在learning Opencv 里面看。
mode:检测轮廓的方法:
××××××RETR_EXTERNAL:检测外部轮廓
××××××RETR_LIST:检索没有建立层次结构的轮廓
××××××RETR_CCOMP:检索有两个级别的层次结构的所有轮廓:外部和孔,如果另一个对象在一个洞里,那么将其放在层次结构的顶层。
method:检测轮廓形状的近似方法:
××××××CV_CHAIN_APPROX_NONE:这并不适用于近似任何轮廓和存储所有的轮廓点。
××××××CV_CHAIN_APPROX_SIMPLE:这压缩存储水平,垂直和对角线段的起始点和结束点。例如,矩形就只会有4个角点。
××××××CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:这适用于Teh-Chin chain近似算法。
offset:用于转移所有轮廓的可选点。当ROI工作中,这是非常有用的,而且需要检索全局位置。
这里再给出与之成对使用的函数DrawContours:
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
image:用来绘制轮廓的输出图像
contours:轮廓向量一般与findContours里面一致
contourIdx:指示轮廓绘制的数字。即绘制contours里面的第几个轮廓,若为负数,则全部绘出
Scalar& color:绘制轮廓的颜色
thickness:轮廓线的粗细。若为负数则填充整个轮廓内部。
lineType:线型
hierarchy:绘制轮廓层次结构的可选输出向量,可以得到每个轮廓之间的关系的图像拓扑。具体可以在learning Opencv 里面看。
maxLevel:可选参数,当层次结构参数可用时,可对他进行设置。若设置为0,只绘制指定轮廓;若设置为1,这个函数绘制当前轮廓及嵌套;若为2,算法绘制所有指定轮廓层次。
offset:可选参数,改变轮廓。
下面给出代码及个人理解:
一.预处理
1.去噪声
根据噪声的种类选择合适的滤波器进行去除。2.去除光亮
需从场景中的其他图像提取位于完全相同位置,没有任何对象,并且具有相同光照条件的图像。然后用一种简单的数学运算,删除光这个模式:1)差分
2)除法
图像差分是最简单的方法。如果有光纹矩阵L和图像矩阵I,去除R的结果是他们之间的差值:
R=L-I
除法去除R的结果是
R=255×(1-I/L)
下面给出差分代码 img为需要删除光的图像,pattern位光纹遮挡
Mat removeLight(Mat img,Mat pattern) { Mat result; result=pattern-img;//R=L-I return result; }
下面是除法
Mat removeLight(Mat img,Mat pattern) { Mat result,img32,pattern32; img.covertTo(img32,CV_32F); pattern.convertTo(pattern32,CV_32F); //图像除以模式 result=1-(img32/pattern32); result=result*255;//缩放以转换为8位模式 result.convertTo(result,CV_8U);//转换为8位模式 return result; }
注意 :除法需要用32位浮点型才能分离图像。
可以用blur原图来估计背景。估计背景的方法如下:
在输入图像上使用大尺寸核矩阵模糊化,这是一种在OCR中常用的技术。虽然与上述方法存在差异,但足以消除背景类。函数如下:
Mat calculateLightPattern(Mat img) { Mat pattern; blur(img,pattern,Size(img.cols/3,img.rows/3)); return pattern; }
下面给出自己根据上述函数做的效果图。这是用差分法后的去光效果:
下面是用除法的
可以发现两种方式都能有效的把背景光去掉。注意,我可是开的手电筒哦。。
3. 阀值操作
删除背景后,还需要能在为来进行图像分割的二值图像。threshold 全局二值化
一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,最常用的方法就是设定一个全局的阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。将大于T的像素群的像素值设定为白色(或者黑色),小于T的像素群的像素值设定为黑色(或者白色)。
这里可以使用两个不同阀值的threshold函数:从图片中可以看出非兴趣区域是黑色或者很低值,删除光/背景时,可以使用一个低值.
下面是阀值化后的效果
可以看出大部分感兴趣区域已经亮起来啦,这里的阀值需要自己根据实际慢慢调整。。当然我这个兴趣区域太大啦而且是在晚上室内灯下做的,可能效果不好。
double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type )
参数说明:
src:输入图像。
dst:输出图像。
thresh:阀值T。
maxval:向上最大值
type:类型
详细解释大家可以看看这位大佬总结的http://blog.csdn.net/guduruyu/article/details/68059450
二.分割
这里介绍了用于分割阀值图像的两种技术:1)连通区域
2)findContours函数
1.连通区域算法
连通区域是分割和识别二进制图像部分的常用算法。连通域是使用8或者4链接像素标记图像的迭代算法。
4连通:只有横向和竖向连通。
8连通:在4连通的基础上加上了对角连通。
OpenCV3中提供有下面两个不同功能的连通区域算法:
1)connectedComponents(image,labels,connectivity=8,type=CV_32S)
2)connectedComponentsWithStats(image,labels,stats,centroids,connectivity=8,ltype=CV_32S)
这两个函数返回一个表示检测到几个标签的整数,标签0表示背景,1表示第一个对象,然后依次类推。
connectedComponents的参数说明:
Image :待标记的输入图像
Label :这是一个Mat,是输出,其输出一个与输入大小相同的图像,每个像素都有各自标签值,0代表背景,1代表连通区域的第一个对象,2代表第二个对象,以此类推。
Connectivity:有两个可能值,4或者8。分别表示4连通方式还是8连通方式。
Type:这是想要使用的标签图像类型:只允许两种类型,CV_32S或CV_16U.
connectedComponentsWithStats的参数说明:
Image :待标记的输入图像
Label :这是一个Mat,是输出,其输出一个与输入大小相同的图像,每个像素都有各自标签值,0代表背景,1代表连通区域的第一个对象,2代表第二个对象,以此类推。
Connectivity:有两个可能值,4或者8。分别表示4连通方式还是8连通方式。
Type:这是想要使用的标签图像类型:只允许两种类型,CV_32S或CV_16U.
Stats :包括背景标签在内的所有标签的输出参数。以下统计值可以通过统计数据(标签。列)访问,列也同样定义,具体如下:
××××××CC_STAT_LEFT:这是连通区域对象的左边x坐标
××××××CC_STAT_TOP:这是连通区域对象的顶层y坐标
××××××CC_STAT_WIDTH:这定义连通区域对象边框的宽度
××××××CC_STAT_HEIGHT:这定义连通区域对象边框的高度
××××××CC_STAT_AREA:这是连通区域对象的像素(区)数量
Centroids:每个标签(包含背景)的浮点型质心点。
下面给出函数,就不给图了(总不能把我自己分割类吧),书上是针对一些零件分割的,自行想象上面已出的图,效果应该不错。
void ConnectedComponents(Mat img) { Mat lebels; //检测到连通区域的数目给lebels int num_ob 4000 jects=connectedComponents(img,labels); if(num_objects<2)//1的时候应该是只有背景(个人理解) { cout<<"No object detected"<<endl; return; } else { cout<<"Number of objects detected:"<<num_objects-1<<endl; } //创建彩色目标输出图像 Mat output=Mat::zeros(img.rows,img.cols,CV_8UC3);//3通道8位uchar 0矩阵 RNG rng(0xFFFFFFFF);//RNG为随机数生成器类 for(int i=1;i<num_objects;i++) { Mat mask=(labels==i);//A output.setTo(randomColor(rng),mask);//B } imshow("result",output); }
A:此处括号是我自己加的 便于理解,个人认为labels是mat类,里面存以不同标签号的图
B:randomColor其实就是将随机数/255的作用。 setTo(x,mask)自己理解为只处理mask,即矩阵不为0的地方,并将x得到的三通到颜色给予mask
下面用connectedComponentsWithStats()来显示更多信息的输出结果图像。
下面是其函数:
void ConnectedComponentsStats(Mat img) { //连通区域统计信息的三个量 Mat labels,stats,centroids; int num_objects=connectedComponentsWithStats(img,labels,stats,centroids); //检查检测到连通域的数目 if(num_objects<2)//1的时候应该是只有背景(个人理解) { cout<<"No object detected"<<endl; return; } else { cout<<"Number of objects detected:"<<num_objects-1<<endl; } Mat output=Mat::zeros(img.rows,img.cols,CV_8UC3); RNG rng(0xFFFFFFFF);//RNG为随机数生成器类 for(int i=1;i<num_objects;i++) { cout<<"Object"<<i<<"with pos:"<<centroids.at<Point2d>(i)<<"with area"<<stats.at<int>(i,CC_STAT_AREA)<<endl;//A Mat mask=(labels==i); output.setTo(randomColor(rng),mask); //使用区域绘制文本 stringstream ss;//添加统计区域信息 ss<<"area:"<<stats.at<int>(i,CC_STAT_AREA); putText(output,ss.str(),centroids.at<Point2d>(i),FONT_HERSHEY_SIMPLEX,0.4,Scalar(255,255,255)); //在output上描述信息(这里利用了putText函数) } imshow("result",output); }
A: centroids.at < Point2d > (i)表示第i个连通域的质心 stats.at < int>(i,CC_STAT_AREA)为连通域像素的数量。
2.查找轮廓(findContours算法)
其函数声明如下:void findContours(InputOutputArray image, OutputArrayofArrays contours, OutputArray hierarchy, int mode,int method,Point offset=Point())
每个参数的含义如下:
image:二进制输入图像。
contours:输出轮廓,每个检测出来的输出轮廓是点向量,通常用vector < vector< Point> >类型来保存。
hierarchy:储存轮廓层次结构的可选输出向量,可以得到每个轮廓之间的关系的图像拓扑。具体可以在learning Opencv 里面看。
mode:检测轮廓的方法:
××××××RETR_EXTERNAL:检测外部轮廓
××××××RETR_LIST:检索没有建立层次结构的轮廓
××××××RETR_CCOMP:检索有两个级别的层次结构的所有轮廓:外部和孔,如果另一个对象在一个洞里,那么将其放在层次结构的顶层。
method:检测轮廓形状的近似方法:
××××××CV_CHAIN_APPROX_NONE:这并不适用于近似任何轮廓和存储所有的轮廓点。
××××××CV_CHAIN_APPROX_SIMPLE:这压缩存储水平,垂直和对角线段的起始点和结束点。例如,矩形就只会有4个角点。
××××××CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:这适用于Teh-Chin chain近似算法。
offset:用于转移所有轮廓的可选点。当ROI工作中,这是非常有用的,而且需要检索全局位置。
这里再给出与之成对使用的函数DrawContours:
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
image:用来绘制轮廓的输出图像
contours:轮廓向量一般与findContours里面一致
contourIdx:指示轮廓绘制的数字。即绘制contours里面的第几个轮廓,若为负数,则全部绘出
Scalar& color:绘制轮廓的颜色
thickness:轮廓线的粗细。若为负数则填充整个轮廓内部。
lineType:线型
hierarchy:绘制轮廓层次结构的可选输出向量,可以得到每个轮廓之间的关系的图像拓扑。具体可以在learning Opencv 里面看。
maxLevel:可选参数,当层次结构参数可用时,可对他进行设置。若设置为0,只绘制指定轮廓;若设置为1,这个函数绘制当前轮廓及嵌套;若为2,算法绘制所有指定轮廓层次。
offset:可选参数,改变轮廓。
下面给出代码及个人理解:
void FindContoursBasic(Mat img) { vector<vector<Point> > contours;//点集数组.那个空格必须有,不然会被读成>>。 findContours(img,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat output=Mat::zeros(img.rows,img.cols,CV_8UC3);//定义绘制板 if(contours.size()==0) { cout<<"No objects founded"<<endl; return -1; } else { cout<<"objects number:"<<contours.size()<<endl; } RNG rng(0xFFFFFFFF);//随机数 for(int i=0;i<contours.size(),i++) { drawContours(output,contours,i,randomColor(rng));//依次将轮廓绘制到output上 } imshow("Output",output); }
相关文章推荐
- 直接可以用的Python和OpenCV检测及分割图像的目标区域例子
- 《OpenCV 3计算机视觉:Python语言实现》学习笔记——目标跟踪中基本运动检测的思考
- 我的OpenCV学习笔记(3):基于混合高斯模型GMM的运动目标检测
- python+opencv+caffe+摄像头做目标检测的实例代码
- python opencv检测目标颜色的实例讲解
- 【OpenCV学习笔记】【编程实例】六 (霍夫圆检测续)
- OpenCV学习笔记(二十六)——小试SVM算法ml OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect OpenCV学习笔记(二十八)——光流法对运动目标跟踪Video Ope
- opencv自动光学检测、目标分割和检测(连通区域和findContours)
- openCV目标检测学习笔记(一)
- 图像分割、目标检测 MASK R-CNN 论文阅读笔记
- OpenCV自学笔记14:Harris角点检测实例
- 【OpenCV学习笔记】【教程翻译】三( 车牌检测之区域分割)
- OpenCV自学笔记14:Harris角点检测实例
- 【OpenCV学习笔记】【编程实例】五 (霍夫圆检测)
- OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect
- 【OpenCV学习笔记 019】SIFT和SURF算法实现目标检测
- opencv学习系列:目标检测相关
- OpenCV笔记:图像边缘检测Sobel,Laplace,Canny
- Python语言opencv使用笔记(十一)(详解hough变换检测直线与圆)
- OpenCV2学习笔记(四):两种图像分割方法比较