opencv学习系列:连通域参考处理
OpenCV里提取目标轮廓的函数是findContours,它的输入图像是一幅二值图像,输出的是每一个连通区域的轮廓点的集合:vector<vector<Point>>。
外层vector的size代表了图像中轮廓的个数,里面vector的size代表了轮廓上点的个数。 hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
第六个参数传入CV_CHAIN_CODE时,要设置成sizeof(CvChain),其它情况统一设置成sizeof(CvContour)
CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。例如一个矩形轮廓只需4个点来保存轮廓信息
CV_RETR_EXTERNAL:只检索最外面的轮廓;
CV_RETR_LIST:检测的轮廓不建立等级关系,检索所有的轮廓,并将其保存到一条链表当中;
CV_RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次,可以参见下图。
加滚动条确定阈值化的合适阈值!:http://blog.csdn.net/augusdi/article/details/9021467
****************************************************************************************
//做一下膨胀,x与y方向都做,但系数不同
var kernal = Cv.CreateStructuringElementEx(5, 2, 1, 1, ElementShape.Rect);
Cv.Erode(gray, gray, kernal, 2); //二值化
Cv.Threshold(gray, gray, 0, 255, ThresholdType.BinaryInv | ThresholdType.Otsu); //检测连通域,每一个连通域以一系列的点表示,FindContours方法只能得到第一个域
var storage = Cv.CreateMemStorage();
CvSeq<CvPoint> contour = null;
Cv.FindContours(gray, storage, out contour, CvContour.SizeOf, ContourRetrieval.CComp, ContourChain.ApproxSimple);
var color = new CvScalar(0, 0, 255); //开始遍历
while (contour != null)
{
//得到这个连通区域的外接矩形
var rect = Cv.BoundingRect(contour); //如果高度不足,或者长宽比太小,认为是无效数据,否则把矩形画到原图上
if(rect.Height > 10 && (rect.Width * 1.0 / rect.Height) > 0.2)
Cv.DrawRect(src, rect, color); //取下一个连通域
contour = contour.HNext;
} *************************************************************** ***********************************************************************************************************
// 移除过小或过大的轮廓
void getSizeContours(vector<vector<Point>> &contours)
{
int cmin = 100; // 最小轮廓长度
int cmax = 1000; // 最大轮廓长度
vector<vector<Point>>::const_iterator itc = contours.begin();
while(itc != contours.end())
{
if((itc->size()) < cmin || (itc->size()) > cmax)
{
itc = contours.erase(itc);
}
else ++ itc;
}
}
****************************************************************************
while(contour) {
/*area = cvContourArea(contour, CV_WHOLE_SEQ);*/
area = fabs(cvContourArea( contour, CV_WHOLE_SEQ )); //获取当前轮廓面积
printf("area == %lf\n", area);
//画轮廓
//画外接矩形
CvRect r = ((CvContour*)contour)->rect;
if (r.height * r.width > size)
{
cvRectangle(pimg, cvPoint(r.x, r.y), cvPoint(r.x + r.width, r.y + r.height),CV_RGB(255, 0, 0), 1, CV_AA, 0); }
contour = contour->h_next; } *********************************************************************************************************
// Get the contours of the connected components
std::vector<std::vector<cv::Point>> contours; cv::findContours(gray,
contours, // a vector of contours
CV_RETR_EXTERNAL , // retrieve the external contours
CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours // Print contours' length
std::cout << "Contours: " << contours.size() << std::endl;
std::vector<std::vector<cv::Point>>::const_iterator itContours= contours.begin();
for ( ; itContours!=contours.end(); ++itContours)
{ std::cout << "Size: " << itContours->size() << std::endl;
} // draw black contours on white image
cv::Mat result(image.size(),CV_8U,cv::Scalar(255));
cv::drawContours(result,contours,
-1, // draw all contours
cv::Scalar(0), // in black
2); // with a thickness of 2 ************************************************************************
double maxarea = 0;
double minarea = 100;
int m = 0;
for( ; contour != 0; contour = contour->h_next )
{ double tmparea = fabs(cvContourArea(contour));
if(tmparea < minarea)
{
cvSeqRemove(contour, 0); // 删除面积小于设定值的轮廓
continue;
}
CvRect aRect = cvBoundingRect( contour, 0 );
if ((aRect.width/aRect.height)<1)
{
cvSeqRemove(contour, 0); //删除宽高比例小于设定值的轮廓
continue;
}
if(tmparea > maxarea)
{
maxarea = tmparea;
}
m++;
// 创建一个色彩值
CvScalar color = CV_RGB( 0, 255, 255 ); //max_level 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓
//如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种
//如果值为负数,函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓
cvDrawContours(dst, contour, color, color, -1, 1, 8); //绘制外部和内部的轮廓
}
contour = _contour;
int count = 0;
for(; contour != 0; contour = contour->h_next)
{
count++;
double tmparea = fabs(cvContourArea(contour));
if (tmparea == maxarea)
{
CvScalar color = CV_RGB( 255, 0, 0);
cvDrawContours(dst, contour, color, color, -1, 1, 8);
}
}
*************************************************************************************
在提取之前还可以调用一个函数:
contour = cvApproxPoly( contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1 );
可能是拟合,有这一句找出的轮廓线更直。 contour里面包含了很多个轮廓,每个轮廓是单独存放的. 输出轮廓位置!
printf(" %d elements:\n", c->total );
for( int i=0; i<c->total; ++i ) {
CvPoint* p = CV_GET_SEQ_ELEM( CvPoint, c, i );
printf(" (%d,%d)\n", p->x, p->y );
}
输出轮廓面积!
for( ; contour; contour = contour->h_next)
{
area = fabs(cvContourArea(contour, CV_WHOLE_SEQ)); //获取当前轮廓面积
printf("area == %lf\n", area);
if(area > maxArea)
{
contmax = contour;
maxArea = area;
}
}
***********************************************************************************************
内轮廓填充
// 参数:
// 1. pBinary: 输入二值图像,单通道,位深IPL_DEPTH_8U。
// 2. dAreaThre: 面积阈值,当内轮廓面积小于等于dAreaThre时,进行填充。
void FillInternalContours(IplImage *pBinary, double dAreaThre)
{
double dConArea;
CvSeq *pContour = NULL;
CvSeq *pConInner = NULL;
CvMemStorage *pStorage = NULL;
// 执行条件
if (pBinary)
{
// 查找所有轮廓
pStorage = cvCreateMemStorage(0);
cvFindContours(pBinary, pStorage, &pContour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
// 填充所有轮廓
cvDrawContours(pBinary, pContour, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 2, CV_FILLED, 8, cvPoint(0, 0));
// 外轮廓循环
for (; pContour != NULL; pContour = pContour->h_next)
{
// 内轮廓循环
for (pConInner = pContour->v_next; pConInner != NULL; pConInner = pConInner->h_next)
{
// 内轮廓面积
dConArea = fabs(cvContourArea(pConInner, CV_WHOLE_SEQ));
if (dConArea <= dAreaThre)
{
cvDrawContours(pBinary, pConInner, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 0, CV_FILLED, 8, cvPoint(0, 0));
}
}
}
cvReleaseMemStorage(&pStorage);
pStorage = NULL;
}
} ******************************************************************* *********************
// Get the contours of the connected components
std::vector<std::vector<cv::Point>> contours;
cv::findContours(image,
contours, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours // Print contours' length
std::cout << "Contours: " << contours.size() << std::endl;
std::vector<std::vector<cv::Point>>::const_iterator itContours= contours.begin();
for ( ; itContours!=contours.end(); ++itContours)
{ std::cout << "Size: " << itContours->size() << std::endl;
} ***************************************************************************************
// Eliminate too short or too long contours
int cmin= 100; // minimum contour length
int cmax= 1000; // maximum contour length
std::vector<std::vector<cv::Point>>::const_iterator itc= contours.begin();
while (itc!=contours.end()) { if (itc->size() < cmin || itc->size() > cmax)
itc= contours.erase(itc);
else
++itc;
} 输出所有轮廓的旋转角度
CvBox2D End_Rage2D; CvMemStorage *storage = cvCreateMemStorage(0); //开辟内存空间 CvSeq* contour = NULL; //CvSeq类型 存放检测到的图像轮廓边缘所有的像素值,坐标值特征的结构体以链表形式 cvFindContours( pSrcImage, storage, &contour, sizeof(CvContour),CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);//这函数可选参数还有不少
for(; contour; contour = contour->h_next) //如果contour不为空,表示找到一个以上轮廓,这样写法只显示一个轮廓
//如改为for(; contour; contour = contour->h_next) 就可以同时显示多个轮廓
{ End_Rage2D = cvMinAreaRect2(contour);
//代入cvMinAreaRect2这个函数得到最小包围矩形 这里已得出被测物体的角度,宽度,高度,和中点坐标点存放在CvBox2D类型的结构体中,
//主要工作基本结束。 std::cout <<" angle:\n"<<(float)End_Rage2D.angle << std::endl; //被测物体旋转角度 }
//函数形式画轮廓
void DrawRec(IplImage* pImgFrame,IplImage* pImgProcessed,int MaxArea)
{
//pImgFrame:初始未处理的帧,用于最后标出检测结果的输出;
//pImgProcessed:处理完的帧,用于找运动物体的轮廓 stor = cvCreateMemStorage(0); //创建动态结构和序列
cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor); // 找到所有轮廓
cvFindContours( pImgProcessed, stor, &cont, sizeof(CvContour),
CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); // 直接使用CONTOUR中的矩形来画轮廓
for(;cont;cont = cont->h_next)
{
CvRect r = ((CvContour*)cont)->rect;
if(r.height * r.width > MaxArea) // 面积小的方形抛弃掉
{
cvRectangle( pImgFrame, cvPoint(r.x,r.y),
cvPoint(r.x + r.width, r.y + r.height),
CV_RGB(255,0,0), 1, CV_AA,0);
}
}
cvShowImage("video", pImgFrame);
} *********************************************************************************************** 绍opencv 的基于面积区域过滤方法,这个对图像处理时去除小区域杂点是很有帮助的。基于区域宽度,高度等其他方式的过滤也可以根据这个方法类推。 # 图片中找到我们需要的目标 一般是最大连通区域
#获取当前轮廓面积
area = abs(cv.cvContourArea( contour ))
# 获取最大区域矩形块
aRect = cv.cvBoundingRect( contmax, 0 )
#原始区域的不加边框
#rcenter = cv.cvPoint2D32f(aRect.x + aRect.width/2.0, aRect.y + aRect.height/2.0) *****************************************************************************************
//移除过长或过短的轮廓
int cmin = 100; //最小轮廓长度
int cmax = 1000; //最大轮廓
vector<vector<Point>>::const_iterator itc = contours.begin();
while (itc!=contours.end())
{
if (itc->size() < cmin || itc->size() > cmax)
itc = contours.erase(itc);
else
++itc;
} //在白色图像上绘制黑色轮廓
Mat result_erase(binaryImage.size(), CV_8U, Scalar(255));
drawContours(result_erase, contours,
-1, //绘制所有轮廓
Scalar(0), //颜色为黑色
2); //轮廓线的绘制宽度为2 Rect r0 = boundingRect(Mat(contours[0]));
rectangle(result_erase, r0, Scalar(128), 2);
Rect r1 = boundingRect(Mat(contours[1]));
rectangle(result_erase, r1, Scalar(128), 2); *****************************************************************************************************************
//对前景先进行中值滤波,再进行形态学膨胀操作,以去除伪目标和连接断开的小目标
69 medianBlur(mask, mask, 5);
70 //morphologyEx(mask, mask, MORPH_DILATE, getStructuringElement(MORPH_RECT, Size(5, 5)));
71
72 //测试:先开运算再闭运算
73 morphologyEx(mask, mask, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(5, 5)));
74 morphologyEx(mask, mask, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(5, 5))); //外接矩阵
93 Rect rct;
94
95 //对轮廓进行外接矩阵之前先对轮廓按面积降序排序,目的为了去除小目标(伪目标)
96 sort(contours.begin(), contours.end(), descSort);
97
98 for (int i = 0; i < contours.size(); i++)
99 {
100 //当第i个连通分量的外接矩阵面积小于最大面积的1/6,则认为是伪目标
101 if (contourArea(contours[i]) < contourArea(contours[0]) / 5)
102 break;
103 //包含轮廓的最小矩阵
104 rct = boundingRect(contours[i]);
105 rectangle(result, rct, Scalar(0, 255, 0), 2);
106
107 } **************************************************************************************************************
Mat element(5,5,CV_8U,Scalar(1));
cvMorphologyEx(green, green, NULL, element, CV_MOP_OPEN); // 开运算,去除比结构元素小的亮点 cvThreshold(green, green, 0.0, 255.0, CV_THRESH_BINARY | CV_THRESH_OTSU); // OTSU法二值化 一般用:findContours(image,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
int cmin=100; int cmax=1000; vector<std::vector<cv::Point> >::iterator itc = contours.begin(); while(itc!=contours.end()) { if(itc->size()<cmin||itc->size()>cmax) itc =contours.erase(itc); else itc++; }
Mat image2=imread("E:\\group.jpg");
drawContours(image2,contours,-1,Scalar(255,255,255),2);
imshow("image",image2);
opencv学习系列:连通域参考处理的更多相关文章
- OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现
# OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现 [-= 博客目录 =-] 1-学习目标 1.1-本章介绍 1.2-实践内容 1.3-相关说明 2-学习过程 2.1-环 ...
- OpenCV学习系列(零) Mac下OpenCV + xcode环境搭建
# OpenCV学习系列(零) Mac下OpenCV + xcode环境搭建 [-= 博客目录 =-] 1-学习目标 1.1-本章介绍 1.2-实践内容 1.3-相关说明 2-学习过程 2.1-hom ...
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- opencv-python教程学习系列13-图像平滑
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍图像平滑,坚持学习,共同进步. 系列教程参照OpenCV-Python中文教程: 系统环境 系统: ...
- opencv-python教程学习系列12-图像阈值
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍图像阈值/二值化,坚持学习,共同进步. 系列教程参照OpenCV-Python中文教程: 系统环境 ...
- opencv-python教程学习系列11-几何变换
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍几何变换,坚持学习,共同进步. 系列教程参照OpenCV-Python中文教程: 系统环境 系统: ...
- opencv-python教程学习系列10-颜色空间转换
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍颜色空间转换,坚持学习,共同进步. 系列教程参照OpenCV-Python中文教程: 系统环境 系 ...
- opencv-python教程学习系列9-程序性能检测及优化
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍程序性能检测及优化,坚持学习,共同进步. 系列教程参照OpenCV-Python中文教程: 系统环 ...
- opencv-python教程学习系列8-opencv图像算术运算
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍图像的算术运算,坚持学习,共同进步. 系列教程参照OpenCV-Python中文教程: 系统环境 ...
随机推荐
- Python-字典(dict)
字典是一种key-value的数据类型,字典里必须写Key和value: 字典的优点是取数方便和速度快. 字典的定义使用大括号{ },每个值用“,”隔开,key和value使用“:”分隔. value ...
- spring boot开发笔记——mybatis
概述 mybatis框架的优点,就不用多说了,今天这边干货主要讲mybatis的逆向工程,以及springboot的集成技巧,和分页的使用 因为在日常的开发中,当碰到特殊需求之类会手动写一下s ...
- Flask实例化的参数 及 对app的配置
首先展示一下: from flask import Flask app = Flask(__name__) # type:Flask app.config["DEBUG"] = T ...
- Redis 学习笔记(十二)Redis 复制功能详解 ----- (error) READONLY You can't write against a read only slave
Redis 复制(Replication)1. 复制介绍分布式数据库为了获取更大的存储容量和更高的并发访问量,会将原来集中式数据库中的数据分散存储到多个通过网络连接的数据存储节点上.Redis为了解决 ...
- 第九节:详细讲解Java中的泛型,多线程,网络编程
前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...
- pdf.js显示合同签名问题
需求 pdf页面显示在ios11以下的环境,合同的签名印章或签字会显示不出 解决方案(初步处理参考下文引用,这里是后续具体做法) 现在通过使用pdf.js插件,参考下文,引入自己的代码 我把gener ...
- vue 自学笔记(6) axios的使用
前情提要:axios 的使用 axios是一个ajax 的包,主要在node.js 使用 axios 的官网 https://www.kancloud.cn/yunye/axios/234845 一: ...
- Python——pytessercat识别简单的验证码
什么是验证码 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computersand Humans Apart” (全自动 ...
- Python函数学习——作用域与嵌套函数
全局与局部变量 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量. 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数. 当全局变量与局部变量同名时,在定义局部变量的函数内 ...
- 采用太平洋AI的DINK框架一键运行3D点云识别,一键训练深度学习模型
DINK安装视频教程: http://fp-ai.com/video_details.html?id=072b030ba126b2f4b2374f342be9ed44 DINK一键启动视频教程: ...