物体的轮廓勾勒出了物体的整体形状,物体形状的边界像素一起组合成了轮廓。
灰度图像边界的明显特征是边界两侧灰度级的突变,根据这个特征,使用Sobel、拉普拉斯或Canny之类的边缘检测算子可以有效的检测到物体的边界,所有连续的边界像素组合在一起成为一个整体,就构成了物体的轮廓。
轮廓检测可以使用findContours函数,检测步骤是:
1. 使用拉普拉斯或Canny等边缘检测算子处理图像,获得仅包含边界的二值图像
2. 使用findContorus方法,获取图像所有的边界连续像素序列,并保存在contours向量中
3. 标示出contours向量中所有的轮廓序列
以下Opencv实现:
#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
#include "iostream"
using namespace std;
using namespace cv;
int main(int argc,char *argv[])
{
Mat imageSource=imread(argv[1],0);
imshow("Source Image",imageSource);
Mat image;
GaussianBlur(imageSource,image,Size(3,3),0);
Canny(image,image,100,250);
imshow("Canny Image",image);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
Mat imageContours=Mat::zeros(image.size(),CV_8UC1);
for(int i=0;i<contours.size();i++)
{
drawContours(imageContours,contours,i,Scalar(255),1,8,hierarchy);
}
imshow("Contours Image",imageContours);
waitKey(0);
return 0;
}
原图:
Canny边缘:
轮廓:
轮廓图像和Canny图像乍看起来表现几乎是一致的,但其实组成两者的数据结构差别很大:
Canny边缘图像只是一些相互独立的散点勾勒出了一个边界,点与点之间没有联系,是没有“思想”的;
轮廓图像是一系列的点组成的,相邻的点与点同属于一个轮廓“集合”,连续的点构成了一个整体,甚至我们可以通过编号对每个轮廓定位,定义其前后轮廓线段,内外轮廓包含、隶属等树形关系,是有“思想”,可进一步处理的。