当看到轮廓的时候,发现没有办法具体到什么, 因为关系轮廓的东西似乎有很多,例如检测轮廓,提取轮廓,轮廓跟踪,轮廓面积,周长,标记,匹配,还有一系列的外接最小矩形,圆形,椭圆,图像矩,填充孔洞等,不得不说东西真的很好。
轮廓其实最容易和边缘检测联系到一起,有很多的相同,但是我理解的是边缘是检测,是预处理,而轮廓就可能是你要用的特征。
一、函数:一个是找,一个是画
<span style="font-size:18px;">void findContours//提取轮廓,用于提取图像的轮廓
(
InputOutputArray image,//输入图像,必须是8位单通道图像,并且应该转化成二值的
OutputArrayOfArrays contours,//检测到的轮廓,每个轮廓被表示成一个point向量
OutputArray hierarchy,//可选的输出向量,包含图像的拓扑信息。其中元素的个数和检测到的轮廓的数量相等
int mode,//说明需要的轮廓类型和希望的返回值方式
int method,//轮廓近似方法
Point offset = Point()
)</span>
注意:mode轮廓检索模式
CV_RETR_EXTERNAL 只检测出最外轮廓即c0。图2中第一个轮廓指向最外的序列,除此之外没有别的连接。
CV_RETR_LIST 检测出所有的轮廓并将他们保存到表(list)中,图2中描绘了这个表,被找到的9条轮廓相互之间由h_prev和h_next连接。这里并没有表达出纵向的连接关系,没有使用v_prev和v_next.
CV_RETR_COMP 检测出所有的轮廓并将他们组织成双层的结构,第一层是外部轮廓边界,第二层边界是孔的边界。从图2可以看到5个轮廓的边界,其中3个包含孔。最外层边界c0有两个孔,c0之间的所有孔相互间由h_prev和h_next指针连接。
CV_RETR_TREE 检测出所有轮廓并且重新建立网状的轮廓结构。图2中,根节点是最外层的边界c0,c0之下是孔h00,在同一层中与另一个孔h01相连接。同理,每个孔都有子节点(相对于c000和c010),这些子节点和父节点被垂直连接起来。这个步骤一直持续到图像最内层的轮廓,这些轮廓会成为树叶节点。
注意,method 也就是轮廓的近似方法
CV_CHAIN_CODE 用freeman链码输出轮廓,其他方法输出多边形(顶点的序列)。
CV_CHAIN_APPROX_NONE将链码编码中的所有点转换为点。
CV_CHAIN_APPROX_SIMPLE压缩水平,垂直或斜的部分,只保存最后一个点。
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_QPPROX_TC89_KCOS使用Teh-Chin链逼近算法中的一个。
CV_LINK_RUNS与上述的算法完全不同,连接所有的水平层次的轮廓。
<span style="font-size:18px;">void drawContours//绘制轮廓,用于绘制找到的图像轮廓
(
InputOutputArray image,//要绘制轮廓的图像
InputArrayOfArrays contours,//所有输入的轮廓,每个轮廓被保存成一个point向量
int contourIdx,//指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓
const Scalar& color,//绘制轮廓所用的颜色
int thickness = 1, //绘制轮廓的线的粗细,如果是负数,则轮廓内部被填充
int lineType = 8, /绘制轮廓的线的连通性
InputArray hierarchy = noArray(),//关于层级的可选参数,只有绘制部分轮廓时才会用到
int maxLevel = INT_MAX,//绘制轮廓的最高级别,这个参数只有hierarchy有效的时候才有效
//maxLevel=0,绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓
//maxLevel=1, 绘制与输入轮廓同一等级的所有轮廓与其子节点。
//maxLevel=2,绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点
Point offset = Point()
)</span>
具体的用法
<span style="font-size:18px;">
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】"
#define WINDOW_NAME2 "【轮廓图】"
Mat g_srcImage;
Mat g_grayImage;
int g_nThresh = 80;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;
void on_ThreshChange(int, void* );
int main( int argc, char** argv )
{
g_srcImage = imread( "lena.jpg", 1 );
if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
cvtColor( g_srcImage, g_grayImage, COLOR_BGR2GRAY );
blur( g_grayImage, g_grayImage, Size(3,3) );
namedWindow( WINDOW_NAME1, WINDOW_AUTOSIZE );
imshow( WINDOW_NAME1, g_srcImage );
//创建滚动条并初始化
createTrackbar( "canny阈值", WINDOW_NAME1, &g_nThresh, g_nThresh_max, on_ThreshChange );
on_ThreshChange( 0, 0 );
waitKey(0);
return(0);
}
void on_ThreshChange(int, void* )
{
Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );
imshow("1",g_cannyMat_output);
// 寻找轮廓
findContours( g_cannyMat_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
// 绘出轮廓
Mat drawing = Mat::zeros( g_cannyMat_output.size(), CV_8UC3 );
for( int i =0; i< g_vContours.size(); i++ )
{
Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//任意值
drawContours( drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point() );
}
// 显示效果图
imshow( WINDOW_NAME2, drawing );
}
</span>
二、其他的函数
- 返回外部矩形边界 boundingRect()
- 寻找最小包围矩形minA热aRect()
- 寻找最小包围圆形minEnclosingCircle()
- 椭圆拟合二维点集 fitEllipse()
- 逼近多边形曲线approxPolyDP()
- 寻找凸包 convexHull()
- 图像的矩 moments
- 轮廓面积 contourArea
- 轮廓曲线长度 arcLength
regionprops统计被标记的区域的面积分布,显示区域总数。这个里面有多的不能再多的好用
函数regionprops语法规则为:STATS = regionprops(L,properties)
该函数用来测量标注矩阵L中每一个标注区域的一系列属性。
- 'Area' 图像各个区域中像素总个数
- 'BoundingBox' 包含相应区域的最小矩形
- 'Centroid' 每个区域的质心(重心)
- 'MajorAxisLength' 与区域具有相同标准二阶中心矩的椭圆的长轴长度(像素意义下)
- 'MinorAxisLength' 与区域具有相同标准二阶中心矩的椭圆的短轴长度(像素意义下)
- 'Eccentricity' 与区域具有相同标准二阶中心矩的椭圆的离心率(可作为特征)
- 'Orientation' 与区域具有相同标准二阶中心矩的椭圆的长轴与x轴的交角(度)
- 'Image' 与某区域具有相同大小的逻辑矩阵
- 'FilledImage' 与某区域具有相同大小的填充逻辑矩阵
- 'FilledArea' 填充区域图像中的on像素个数
- 'ConvexHull' 包含某区域的最小凸多边形
- 'ConvexImage' 画出上述区域最小凸多边形
- 'ConvexArea' 填充区域凸多边形图像中的on像素个数
- 'EulerNumber' 几何拓扑中的一个拓扑不变量——欧拉数
- 'Extrema' 八方向区域极值点
- 'EquivDiameter' 与区域具有相同面积的圆的直径
- 'Solidity' 同时在区域和其最小凸多边形中的像素比例
- 'Extent' 同时在区域和其最小边界矩形中的像素比例
- 'PixelIdxList' 存储区域像素的索引下标
- 'PixelList' 存储上述索引对应的像素坐标
<span style="font-size:18px;">im=imread('d:\lena.jpg'); %读取原图
figure,imshow(im,[]);title('Raw'); %显示原图
im=im2bw(im); %转二值图像
figure,imshow(im,[]),title('BW'); %显示二值图像
im2=imfill(im,'holes'); %填充
im3=bwperim(im2); %轮廓提取
figure,imshow(im2,[]); title('') %显示
figure,imshow(im3,[]);</span>