转载请注明出处:http://blog.csdn.net/wangyaninglm/article/details/44151213

来自:shiter编写程序的艺术

基础介绍

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.
  • 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.
  • 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.

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

来自:shiter编写程序的艺术

OpenCV 矩形轮廓检测的更多相关文章

  1. OpenCV—Python 轮廓检测 绘出矩形框(findContours\ boundingRect\rectangle

    千万注意opencv的轮廓检测和边缘检测是两码事 本文链接:https://blog.csdn.net/wsp_1138886114/article/details/82945328 1 获取轮廓 O ...

  2. OpenCV图像轮廓检测

    轮廓检测: 轮廓检测的原理通俗的说就是掏空内部点,比如原图中有3*3的矩形点.那么就可以将中间的那一点去掉. 一.关键函数1.1  cvFindContours函数功能:对图像进行轮廓检测,这个函数将 ...

  3. OpenCV 闭合轮廓检测

    这个好像是骨头什么的,但是要求轮廓闭合,于是对图片进行一下膨胀操作,再次检测轮廓就好了. // A closed contour.cpp : 定义控制台应用程序的入口点. // #include &q ...

  4. OpenCV矩形检测

    OpenCV矩形检测 需求:提取图像中的矩形,图像存在污染现象,即矩形区域不是完全规则的矩形. 思路一:轮廓法 OpenCV里提取目标轮廓的函数是findContours,它的输入图像是一幅二值图像, ...

  5. 第十七节,OpenCV(学习六)图像轮廓检测

    1.检测轮廓 轮廓检测是图像处理中经常用到的,OpenCV-Python接口中使用cv2.findContours()函数查找检测物体的轮廓. cv2.findContours(image, mode ...

  6. 学习opencv跟轮廓相关的

    查找轮廓 轮廓到底是什么?一个轮廓一般对应一系列的点,也就是图像中的一条曲线.表示的方法可能根据不同情况而有所不同.有多重方法可以表示曲线.在openCV中一般用序列来存储轮廓信息.序列中的每一个元素 ...

  7. 机器学习进阶-图像金字塔与轮廓检测-轮廓检测 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表示颜色的变换形式 ...

  8. 【python+opencv】轮廓发现

    python+opencv---轮廓发现 轮廓发现---是基于图像边缘提取的基础寻找对象轮廓的方法, 所有边缘提取的阈值选定会影响最终轮廓发现的结果. 介绍两种API使用: -cv.findConto ...

  9. opencv--图像轮廓检测

    //图像的轮廓检测上 //By MoreWindows (http://blog.csdn.net/MoreWindows) #include <opencv2/opencv.hpp> u ...

随机推荐

  1. 23 服务音乐的启动Demo4

    注意如果音乐服务和Activity在一个应用中那么将不会因为绑定的Activity销毁而关闭音乐 MainActivity.java package com.qf.day23_service_demo ...

  2. JAVA面向对象-----成员内部类的访问方式

    成员内部类的访问方式 1.内部类可以直接访问外部类的成员属性.(孙悟空相当于内部类飞到牛魔王的肚子里面去). 2.外部类需要访问内部类的成员属性时需要创建内部类的对象. 1.在外部类的成员函数中创建内 ...

  3. Java进阶(四十三)线程与进程的区别

    Java进阶(四十三)线程与进程的区别 1.线程的基本概念   概念:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必 ...

  4. MPI二维笛卡尔坐标划分【1】

    本文简单演示,如何对现有进程进行二维划分,如何获得进程的X和Y坐标. 只有一段程序: #include <mpi.h> #include <stdio.h> #include ...

  5. UE4联机多人游戏基本设置

    UE4自带网络联机功能,但是似乎只有蓝图接口,而真正写功能的时候不能用C++,让人感觉相当诡异 还是作一个简单记录 1.建一个第三人称模板,为什么会用他呢,因为它自带模板的很多组件,直接支持联机功能, ...

  6. Ubuntu 16.04 安装和使用QQ最简洁的方式

    推荐参考网址: 1  http://www.ubuntukylin.com/ 2  http://www.ubuntukylin.com/application/ Wine QQ 1  http:// ...

  7. SYBASE bcp用法及例子

    BCP是SYBASE公司提供专门用于数据库表一级数据备份的工具. 语法: 语法如下:(可用 bcp – 得到) 常用参数说明: -b batch_size 指定所复制的每批数据中的行数.每个批处理作为 ...

  8. ceil和floor函数的编程实践

    ceil()向上取整 floor向下取整 题目 在最近几场魔兽争霸赛中,赫柏对自己的表现都不满意. 为了尽快提升战力,赫柏来到了雷鸣交易行并找到了幻兽师格丽,打算让格丽为自己的七阶幻兽升星. 经过漫长 ...

  9. Sharepoint Solution Gallery Active Solution时激活按钮灰色不可用的解决方法

    在做CRM与sharepoint集成的时候,需要在sharepoint中上传crmlistcomponent组件,上传后需要激活,但会碰到激活按钮是灰色的无法点击的问题,如下图中这样,包括点击组件后面 ...

  10. iOS中 static变量与全局、局部变量的区别 !

    static变量与全局.局部变量的区别 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量.全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式. 这两者在存储方式上并 ...