OpenCV实现轮廓的发现

前言:

当我们通过阈值分割提取到图像中的目标物体后,我们就需要通过边缘检测来提取目标物体的轮廓,使用这两种方法基本能够确定物体的边缘或者前景。接下来,我们通常需要做的是拟合这些边缘的前景,如拟合出包含前景或者边缘像素点的最小外包矩形、圆、凸包等几何形状,为计算它们的面积或者模板匹配等操作打下坚实的基础。

一、查找、绘制轮廓

首先了解一下轮廓的定义。一个轮廓代表一系列的点(像素),这一系列的点构成一个有序的点集,所以可以把一个轮廓理解为一个有序的点集。

1.1 findContour()函数

在OpenCV中,提供了一个函数返回或者输出一个有序的点集或者有序的点集的集合(指多个有序的点集),函数findContour是从二值图像中来计算轮廓的,它可以使用Canny()函数处理的图像,因为这样的图像含有边缘像素;也可以使用threshold()或者adaptiveThreshold()处理后的图像,其边缘隐含在正负区域的交界处。这个函数的声明如下:

void findContours(InputOutputArray image,OutputArrayOfArrays contours,OutputArray hierarchy,int mode,int method,Point offset = Point());

其参数解释如下:

(1)image:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;

(2)contours:vector<vector<Point>>类型,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。

(3)hierarchy:vector<Vec4i> 类型, Vec4i是Vec<int,4>的别名,即容器内每一个元素都是一个包含了4个int型变量的向量,所以从定义上看,hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1。

(4)mode:int类型的,定义轮廓的检索模式:

取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略;

取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到;

取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层;

取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。

(5) method:int类型,定义轮廓的近似方法:

取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内;

取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留;

取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法;

(6) Point:偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值。

注意事项:

显然,从函数名可以看出“寻找轮廓”的意思。我们可以通过边缘检测算法得到边缘二值图或者前景二值图,二值图的边缘像素或者前景像素就可以被看出是由多个轮廓(点集)组成的。函数findContours的作用就是将二值图的边缘像素或者前景像素拆分成多个轮廓,便于分开讨论每一个轮廓,其中参数image代表一张二值图,contours代表输出的多个轮廓。对于该函数的C++API,对一个轮廓的描述用vector<Point>,那么多个轮廓(多个点集)如何表示呢?即参数contours是什么数据结构呢?在C++API中,用vector<vector<Point>>描述多个轮廓,即将多个轮廓存在一个vector中。

1.2 drawContours()函数

OpenCV中也提供了一个函数来绘制findContours所找到的多个轮廓,其函数声明如下:

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())

其参数解释如下:

(1)image: 代表输入的图像矩阵,将轮廓画在该图上;
    (2)contours:是得到的一系列点的集合,代表多个轮廓;
    (3)contourIdx:是一个索引,代表绘制contours中的第几个轮廓;
    (4) color:被填充的颜色,单色可以设置为Scalar(255)等;
    (5)thickness: 所画Contour的线条粗细,如果该参数值小于0,则表示填充整个轮廓内的区域;
    (6)lineType: 线的连通性;
    (7)hierarchy:可选层次信息结构,这里面是findContours所的到的基于Contours的层级信息;
    (8)maxLevel: 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓。如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种。如果值为负数,函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓

(9)offset:照给出的偏移量移动每一个轮廓点坐标.当轮廓是从某些感兴趣区域(ROI)中提取的然后需要在运算中考虑ROI偏移量时,将会用到这个参数。

二、 演示代码

实例步骤

  • 转灰度
  • canny得到二值图像
  • findcontours寻找轮廓
  • drawcontours画轮廓

我们编写演示代码如下:

#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src1, src2,gray_img, dst;
int value = 100;
int max_value = 255;
void demo(int, void*);
int main()
{
 //发现轮廓--> cvtcolor-->canny得到二值图像-->findcontours(寻找轮廓)-->drawcontous()
 src1 = imread("C:\\Users\\马迎伟\\Desktop\\yuan1.jpg");
 //src2 = imread("C:\\Users\\马迎伟\\Desktop\\heibao1.png");
 if (src1.empty())
 {
 printf("cannot load!!\n");
 system("pause");
 return -1;
 }
 namedWindow("input", CV_WINDOW_AUTOSIZE);
 imshow("input",src1);
 namedWindow("output", CV_WINDOW_AUTOSIZE);
 cvtColor(src1,gray_img,CV_BGR2GRAY);
 createTrackbar("creattrackbar","output",&value,max_value,demo);
 demo(0, 0);
 waitKey(0);
 return 0;
}
void demo(int, void*)
{
 //将图像表现在src3上
 Mat src3 = Mat::zeros(src1.size(),CV_8UC3);
 vector<vector<Point>>contours;
 vector<Vec4i>hierarchy;
 Canny(gray_img,src2,value,value*2,3,false );
 findContours(src2,contours,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));
 RNG rng(12345);
 for (size_t i = 0; i < contours.size(); i++)
 {
 Scalar color = Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
 drawContours(src3, contours, i,color,1,LINE_AA,hierarchy,0,Point(0,0));
 }
 imshow("output",src3);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Python Opencv实现图像轮廓识别功能

    本文实例为大家分享了python opencv识别图像轮廓的具体代码,供大家参考,具体内容如下 要求:用矩形或者圆形框住图片中的云朵(不要求全部框出) 轮廓检测 Opencv-Python接口中使用cv2.findContours()函数来查找检测物体的轮廓. import cv2 img = cv2.imread('cloud.jpg') # 灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.th

  • OpenCV实现图像轮廓检测以及外接矩形

    前两篇博文分别介绍了图像的边缘检测和轮廓检测,本文接着介绍图像的轮廓检测和轮廓外接矩形: 一.代码部分: // extract_contours.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<cv.h> #include<highgui.h> using namespace cv; using namespace std; int _tmain(int argc, _TCHAR* argv[]) { /

  • opencv提取外部轮廓并在外部加矩形框

    这段时间一直在用opencv搞图像处理的问题,发现虽然可调用的函数多,但是直接找相应代码还是很困难,就行寻找连通域,并在连通域外侧加框,对于习惯使用Mat矩形操作的我,真心感觉代码少之又少,为防止以后自己还会用到,特在此记录一下. 要对下面的图像进行字符的边缘检测. 程序中具体的步骤为: (1)灰度化.二值化 (2)图像膨胀 (3)检测膨胀图像的边缘并叫外矩形框 实现代码如下: #include "stdafx.h" #include "stdio.h" #incl

  • OpenCV-Python实现轮廓检测实例分析

    相比C++而言,Python适合做原型.本系列的文章介绍如何在Python中用OpenCV图形库,以及与C++调用相应OpenCV函数的不同之处.这篇文章介绍在Python中使用OpenCV检测并绘制轮廓. 提示: 转载请详细注明原作者及出处,谢谢! 本文介绍在OpenCV-Python中检测并绘制轮廓的方法. 本文不介详细的理论知识,读者可从其他资料中获取相应的背景知识.笔者推荐清华大学出版社的<图像处理与计算机视觉算法及应用(第2版)>. 轮廓检测 轮廓检测也是图像处理中经常用到的.Ope

  • python+opencv轮廓检测代码解析

    首先大家可以对OpenCV有个初步的了解,可以参考:简单了解OpenCV 轮廓(Contours),指的是有相同颜色或者密度,连接所有连续点的一条曲线.检测轮廓的工作对形状分析和物体检测与识别都非常有用. 在轮廓检测之前,首先要对图片进行二值化或者Canny边缘检测.在OpenCV中,寻找的物体是白色的,而背景必须是黑色的,因此图片预处理时必须保证这一点. import cv2 #读入图片 img = cv2.imread("1.png") # 必须先转化成灰度图 gray = cv2

  • Python通过OpenCV的findContours获取轮廓并切割实例

    1 获取轮廓 OpenCV2获取轮廓主要是用cv2.findContours import numpy as np import cv2 im = cv2.imread('test.jpg') imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(imgray,127,255,0) image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_T

  • c语言通过opencv实现轮廓处理与切割

    注意在寻找轮廓时要选择中寻找外层轮廓 RETR_EXTERNAL #include "opencv/cv.h" #include "opencv/highgui.h" using namespace std; using namespace cv; int main() { Mat srcimg=imread("./22.jpg"); Mat dst; cvtColor(srcimg,dst,CV_BGR2GRAY); threshold(dst

  • Opencv提取连通区域轮廓的方法

    本文实例为大家分享了Opencv提取连通区域轮廓的具体代码,供大家参考,具体内容如下 在进行图像分割后,可能需要对感兴趣的目标区域进行提取,比较常用的方法是计算轮廓. 通过轮廓可以获得目标的一些信息: (1)目标位置 (2)目标大小(即面积) (3)目标形状(轮廓矩) 当然,轮廓不一定代表希望目标区域,阈值分割时可能造成一部分信息丢失,因此可以计算轮廓的质心坐标,再进行漫水填充. 程序中有寻找质心+填充,但效果不好,因此就不放填充后的图了. 实验结果: #include "opencv2/img

  • Opencv处理图像之轮廓提取

    本文实例为大家分享了Opencv处理图像之轮廓提取,使用cvfindContours对图像进行轮廓检测,供大家参考,具体内容如下 #include<iostream> #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> int main() { IplImage* img = cvLoadImage("E:\\test.bmp",0); IplImage* img

  • C语言实现opencv提取直线、轮廓及ROI实例详解

    一.Canny检测轮廓 在上一篇文章中有提到sobel边缘检测,并重写了soble的C++代码让其与matlab中算法效果一致,而soble边缘检测是基于单一阈值的,我们不能兼顾到低阈值的丰富边缘和高阈值时的边缘缺失这两个问题.而canny算子则很好的弥补了这一不足,从目前看来,canny边缘检测在做图像轮廓提取方面是最优秀的边缘检测算法. canny边缘检测采用双阈值值法,高阈值用来检测图像中重要的.显著的线条.轮廓等,而低阈值用来保证不丢失细节部分,低阈值检测出来的边缘更丰富,但是很多边缘并

随机推荐