OpenCV 矩形轮廓检测
转载请注明出处:http://blog.csdn.net/wangyaninglm/article/details/44151213,
基础介绍
OpenCV里提取目标轮廓的函数是findContours,它的输入图像是一幅二值图像,输出的是每一个连通区域的轮廓点的集合:vector<vector<Point>>。外层vector的size代表了图像中轮廓的个数,里面vector的size代表了轮廓上点的个数。
轮廓进行填充的时候我会有下面2步骤:
a)依次遍历轮廓点,将点绘制到img上

void drawMaxAreaLine(cv::Mat &dst, const std::vector<cv::Point> maxAreaPoints)
{
int step = dst.step;
auto data = dst.data;
for (int i = 0; i < maxAreaPoints.size(); ++i)
{
*(data + maxAreaPoints[i].x + maxAreaPoints[i].y * step) = 255;
}
}

b)使用floodFill以及一个种子点进行填充
floodFill(savedGrayMat, Point(currentFrameEdge[0].x + 2, currentFrameEdge[0].y + 2), 255);
主要函数用法
-
C++: void findContours(InputOutputArray image,
OutputArrayOfArrays contours, int mode, int method, Point offset=Point())
- Python: cv2.findContours(image,
mode, method[, contours[, hierarchy[, offset]]]) →
contours, hierarchy
-
C: int cvFindContours(CvArr* image,
CvMemStorage* storage, CvSeq** first_contour, int header_size=sizeof(CvContour), int mode=CV_RETR_LIST, intmethod=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) )
- Python: cv.FindContours(image,
storage, mode=CV_RETR_LIST, method=CV_CHAIN_APPROX_SIMPLE, offset=(0, 0)) → contours -
Parameters: - image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated asbinary .
You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() ,
and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. If mode
equals to CV_RETR_CCOMP orCV_RETR_FLOODFILL,
the input can also be a 32-bit integer image of labels (CV_32SC1). - contours – Detected contours. Each contour is stored as a vector of points.
- hierarchy – Optional output vector, containing information about the image topology. It has as many elements as the number of contours. For each i-th contour contours[i] ,
the elements hierarchy[i][0] , hiearchy[i][1] , hiearchy[i][2] ,
and hiearchy[i][3] are set to 0-based indices in contours of
the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour i there
are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i]will be negative. - mode –
Contour retrieval mode (if you use Python see also a note below).
- CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets hierarchy[i][2]=hierarchy[i][3]=-1 for
all the contours. - CV_RETR_LIST retrieves all of the contours without establishing any hierarchical relationships.
- CV_RETR_CCOMP retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level,
there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level. - CV_RETR_TREE retrieves all of the contours and reconstructs a full hierarchy of nested contours. This full hierarchy is built and shown in the OpenCV contours.c demo.
- CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets hierarchy[i][2]=hierarchy[i][3]=-1 for
- method –
Contour approximation method (if you use Python see also a note below).
- CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and (x2,y2) of
the contour will be either horizontal, vertical or diagonal neighbors, that is, max(abs(x1-x2),abs(y2-y1))==1. - CV_CHAIN_APPROX_SIMPLE compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points.
- CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS applies one of the flavors of the Teh-Chin chain approximation algorithm. See[TehChin89] for
details.
- CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and (x2,y2) of
- offset – Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image
context.
- image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated asbinary .
cvFindContours(tour_buf,storage, &contour,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
- tour_buf 是需要查找轮廓的单通道灰度图像 ,
- storage 是临时存储区 ,
- contour是存储轮廓点的CvSeq实例,
- CV_RECT_EXTERNAL 只查找外围轮廓,还有CV_RECT_TREE
输入图像image必须为一个2值单通道图像
contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
mode表示轮廓的检索模式
CV_RETR_EXTERNAL表示只检测外轮廓
CV_RETR_LIST检测的轮廓不建立等级关系
CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demo
method为轮廓的近似办法
CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
正确调用查找函数后,接下来就是从轮廓序列contour(这里的contour不单单只有一个轮廓序列) 提取轮廓点了. contour可能是空指针,提取前最好判断一下 在提取之前还可以调用一个函数:
contour = cvApproxPoly( contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1 );
可能是拟合,有这一句找出的轮廓线更直。 contour里面包含了很多个轮廓,每个轮廓是单独存放的.
#include "cv.h"
#include <iostream>
#include <cxcore.h>
#include <highgui.h>
#include <math.h>
#include <vector>
#include <algorithm> #pragma comment(lib,"opencv_core2410d.lib")
#pragma comment(lib,"opencv_highgui2410d.lib")
#pragma comment(lib,"opencv_imgproc2410d.lib") using namespace std; typedef struct
{
CvPoint cP;
int height;
int width; } RecP;
//自定义排序函数
namespace my
{
bool less(const RecP& s1, const RecP& s2)
{
//if(s1.cP.x < s2.cP.x && s1.cP.y < s2.cP.y)
return s1.cP.x < s2.cP.x; //依次增大 }
} void PrintVector( vector<RecP> & vec)
{
for(vector<RecP>::iterator n = vec.begin() ; n != vec.end() ; n++ )
{
cout<< n->cP.x <<'\t'<< n->cP.y <<'\t'<< n->height<<'\t'<< n->width <<endl;
}
} IplImage* src;
IplImage* img;
IplImage* dst;
IplImage* bianyuan;
CvMemStorage* storage=NULL; int thresh=50; void on_trackbar(int pos)
{
CvSeq* contour=0;
if(storage==NULL)
{
dst=cvCreateImage(cvGetSize(bianyuan), 8, 3);
storage=cvCreateMemStorage(0);
}
else
{
cvClearMemStorage(storage);
}
cvSmooth(bianyuan, bianyuan, CV_GAUSSIAN, 3, 3, 0, 0);
cvThreshold( bianyuan, img, thresh, 200, CV_THRESH_BINARY); cvNamedWindow( "threshold", 1);
cvShowImage( "threshold", img ); cvFindContours(img, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0)); //查找轮廓
cvZero( dst ); //将数组中所有通道的所有元素的值都设置为0 vector<RecP> vecP; int n=0;
for( ; contour; contour = contour->h_next )
{
CvRect rect=cvBoundingRect(contour,1); // 获取矩形边界框 if(abs(rect.width-rect.height)>3)
{
rect.width=0;
rect.height=0;
rect.x = rect.x + 640;
rect.y = rect.y + 480;
} CvPoint pt1=cvPoint(rect.x, rect.y), pt2=cvPoint(rect.x+rect.width, rect.y+rect.height); //定义矩形对顶点 cvRectangle(dst, pt1, pt2, CV_RGB(255,0,0), 1, CV_AA, 0); //绘制矩形边框
cvLine(dst, pt1, pt2, CV_RGB(0,255,0), 1, CV_AA, 0); //矩形对角线相连 pt1=cvPoint(rect.x, rect.y+rect.height),
pt2=cvPoint(rect.x+rect.width, rect.y); cvLine(dst, pt1, pt2, CV_RGB(0,255,0), 1, CV_AA,0); //矩形对角线相连 RecP tmp;
CvPoint p1;
p1 = cvPoint(rect.x + rect.width/2, rect.y + rect.height/2); //矩形中心坐标 tmp.cP = p1;
tmp.height = rect.height;
tmp.width = rect.width;
vecP.push_back(tmp);
//printf("(%d,%d)\n", p1);
sort(vecP.begin(), vecP.end(),my::less); //依次增大
//printf("(%d,%d):(%d,%d)\n", vecP[n].cP, vecP[n].height, vecP[n].width);
n++;
}
PrintVector(vecP); cvShowImage( "Components", dst );
}
int main()
{ const char* a = "Chess.jpg";
src = cvLoadImage(a, 0);
cvSmooth(src,src,CV_GAUSSIAN,5,5,0,0);
cvNamedWindow( "Source0000",1);
cvShowImage( "Source0000", src); IplImage* bw =NULL;
IplImage* color=NULL;
IplImage* jh=NULL;
IplImage* sm=NULL;
if( !src )
return -1;
jh = cvCreateImage( cvGetSize(src), 8, 1 );
sm = cvCreateImage( cvGetSize(src), 8, 1 );
bw = cvCreateImage( cvGetSize(src), 8, 1 );
color = cvCreateImage( cvGetSize(src), 8, 3 );
cvEqualizeHist( src, jh);
cvSmooth(jh, sm, CV_MEDIAN, 3, 3, 0, 0); cvCanny(sm,bw,200,600,3);
cvCvtColor( bw, color, CV_GRAY2BGR );
cvSaveImage("color.bmp",color); const char* b = "color.bmp";
bianyuan = cvLoadImage(b, 0);
img=cvCreateImage(cvGetSize(bianyuan),8,1); cvNamedWindow( "Source",1);
cvShowImage( "Source", bianyuan); cvNamedWindow( "Components",1); on_trackbar(0); cvWaitKey(0);
cvDestroyWindow( "sorce" );
cvDestroyWindow( "threshold" );
cvDestroyWindow( "Components" );
cvReleaseImage( &src);
cvReleaseImage( &img );
cvReleaseImage(&dst);
cvReleaseMemStorage(&storage);
return 0;
}
实现效果
参考文献
http://blog.csdn.net/zcube/article/details/7357602# 轮廓分析
转载请注明出处:http://blog.csdn.net/wangyaninglm/article/details/44151213,
OpenCV 矩形轮廓检测的更多相关文章
- OpenCV—Python 轮廓检测 绘出矩形框(findContours\ boundingRect\rectangle
千万注意opencv的轮廓检测和边缘检测是两码事 本文链接:https://blog.csdn.net/wsp_1138886114/article/details/82945328 1 获取轮廓 O ...
- OpenCV图像轮廓检测
轮廓检测: 轮廓检测的原理通俗的说就是掏空内部点,比如原图中有3*3的矩形点.那么就可以将中间的那一点去掉. 一.关键函数1.1 cvFindContours函数功能:对图像进行轮廓检测,这个函数将 ...
- OpenCV 闭合轮廓检测
这个好像是骨头什么的,但是要求轮廓闭合,于是对图片进行一下膨胀操作,再次检测轮廓就好了. // A closed contour.cpp : 定义控制台应用程序的入口点. // #include &q ...
- OpenCV矩形检测
OpenCV矩形检测 需求:提取图像中的矩形,图像存在污染现象,即矩形区域不是完全规则的矩形. 思路一:轮廓法 OpenCV里提取目标轮廓的函数是findContours,它的输入图像是一幅二值图像, ...
- 第十七节,OpenCV(学习六)图像轮廓检测
1.检测轮廓 轮廓检测是图像处理中经常用到的,OpenCV-Python接口中使用cv2.findContours()函数查找检测物体的轮廓. cv2.findContours(image, mode ...
- 学习opencv跟轮廓相关的
查找轮廓 轮廓到底是什么?一个轮廓一般对应一系列的点,也就是图像中的一条曲线.表示的方法可能根据不同情况而有所不同.有多重方法可以表示曲线.在openCV中一般用序列来存储轮廓信息.序列中的每一个元素 ...
- 机器学习进阶-图像金字塔与轮廓检测-轮廓检测 1.cv2.cvtColor(图像颜色转换) 2.cv2.findContours(找出图像的轮廓) 3.cv2.drawContours(画出图像轮廓) 4.cv2.contourArea(轮廓面积) 5.cv2.arcLength(轮廓周长) 6.cv2.aprroxPloyDP(获得轮廓近似) 7.cv2.boudingrect(外接圆)..
1. cv2.cvtcolor(img, cv2.COLOR_BGR2GRAY) # 将彩色图转换为灰度图 参数说明: img表示输入的图片, cv2.COLOR_BGR2GRAY表示颜色的变换形式 ...
- 【python+opencv】轮廓发现
python+opencv---轮廓发现 轮廓发现---是基于图像边缘提取的基础寻找对象轮廓的方法, 所有边缘提取的阈值选定会影响最终轮廓发现的结果. 介绍两种API使用: -cv.findConto ...
- opencv--图像轮廓检测
//图像的轮廓检测上 //By MoreWindows (http://blog.csdn.net/MoreWindows) #include <opencv2/opencv.hpp> u ...
随机推荐
- Windows 8 Cython 的配置(解决Unable to find vcvarsall.bat问题)
关键是安装之前配置编译器. 1.下载MinGW 编译器 http://www.mingw.org/download.shtml 2.把编译器路径(例如C:\Program Files (x86)\Co ...
- Nagle算法
简介 Nagle算法是以他的发明人John Nagle的名字命名的,它用于自动连接许多的小缓冲器消息:这一过程(称为nagling)通过减少必须发送包的个数来增加网络软件系统的效率.Nagle算法于1 ...
- Linux下C/C++程序调试基础(GCC,G++,GDB,CGDB,DDD)
在写程序的时候,经常会遇到一些问题,比如某些变量计算结果不是我们预期的那样,这时我们需要对程序进行调试.本文主要介绍调试C/C++在Linux操作系统下主要的调试工具. 在Linux下写程序,C/C+ ...
- Makefile自动生成:cmake
http://blog.csdn.net/pipisorry/article/details/51647073 编辑makefile文件CMakeLists.txt,使用cmake命令自动生成make ...
- SpringMVC,MyBatis项目中兼容Oracle和MySql的解决方案及其项目环境搭建配置、web项目中的单元测试写法、HttpClient调用post请求等案例
要搭建的项目的项目结构如下(使用的框架为:Spring.SpingMVC.MyBatis): 2.pom.xml中的配置如下(注意,本工程分为几个小的子工程,另外两个工程最终是jar包): 其中 ...
- DBoW2算法原理介绍
本篇介绍DBoW2算法原理介绍,下篇介绍DBoW2的应用. DBow2算法 DBow2是一种高效的回环检测算法,DBOW2算法的全称为Bags of binary words for fast pla ...
- (NO.00004)iOS实现打砖块游戏(十):砖块!更多的砖块!
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 到目前为止游戏基本可玩,但是砖块数量是不变的,等玩家打光所有的砖 ...
- Simple tutorial for using TensorFlow to compute polynomial regression
"""Simple tutorial for using TensorFlow to compute polynomial regression. Parag K. Mi ...
- ProgressBar的indeterminateDrawable属性在安卓6.0上的问题
通过indeterminateDrawable属性去自定义ProgressBar方法: <ProgressBar android:id="@+id/pb" android:l ...
- 【一天一道LeetCode】#107. Binary Tree Level Order Traversal II
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 来源: htt ...