- 在图片中找到轮廓并且描绘轮廓
- 使用多边形,圆,椭圆来逼近我们的轮廓
葵花宝典
关于轮廓提取,差不多是一个连通域的判断。原理还是比较简单的。
初识API
-
C++: void findContours(InputOutputArray image,
OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
-
-
C++: void findContours(InputOutputArray image,
OutputArrayOfArrays contours, int mode, int method, Point offset=Point())
-
|
- image – 灰度图片.非0像素都被认为是1.会被修改.
- contours – 每一个被检测到的轮廓都是points的集合
- hierarchy – 可选输出, 跟轮廓数量大小一样.对每一个contours[i]来说 ,hierarchy[i][0] , hiearchy[i][1] 分别表示与contours[i]同level的下一个,前一个轮廓索引hiearchy[i][2] ,
andhiearchy[i][3]分别表示contours[i]的子轮廓和父轮廓索引。如果不存在hierarchy[i] will
be negative.
- mode –
- CV_RETR_EXTERNAL 只获得最外面的轮廓,也就是说所有轮廓的hierarchy[i][2]=hierarchy[i][3]=-1 .
- CV_RETR_LIST 获得所有的轮廓,无hierarchy
- 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 获得所有的轮廓,并输出hierarchy组织
- method –
- CV_CHAIN_APPROX_NONE 保存所有的点,max(abs(x1-x2),abs(y2-y1))==1.也就是说,任何轮廓上的两个点都处在一个九宫格内.
- CV_CHAIN_APPROX_SIMPLE 进行了简单的水平竖直对角线压缩.对于一个矩形,只保留了4个顶点.
- CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS [TehChin89]
- offset – 可选的轮廓位移.当分析图片ROI比较有用.
|
找到轮廓后,就可以用drawContours画出来
#include "cv.h"
#include "highgui.h"
using namespace cv;
int main( int argc, char** argv )
{
Mat src;
// the first command-line parameter must be a filename of the binary
// (black-n-white) image
if( argc != 2 || !(src=imread(argv[1], 0)).data)
return -1;
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
src = src > 1;
namedWindow( "Source", 1 );
imshow( "Source", src );
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( src, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// iterate through all the top-level contours,
// draw each connected component with its own random color
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( rand()&255, rand()&255, rand()&255 );
drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
}
namedWindow( "Components", 1 );
imshow( "Components", dst );
waitKey(0);
}
我们可以用矩形包围轮廓
cv::Rect r0= cv::boundingRect(cv::Mat(contours[0]));
cv::rectangle(result,r0,cv::Scalar(0),2);</span>
也可以用圆
float radius;
cv::Point2f center;
cv::minEnclosingCircle(cv::Mat(contours[1]),center,radius);
cv::circle(result,cv::Point(center),static_cast<int>(radius),cv::Scalar(0),2);
也可以用多边形
std::vector<cv::Point> poly;
cv::approxPolyDP(cv::Mat(contours[2]), poly, 5, true);
最左边那个
也可以用另一种多边形模拟convex hull
std::vector<cv::Point> hull;
cv::convexHull(cv::Mat(contours[3]),hull);
也可以用最小外接矩形
vector<RotatedRect> minRect( contours.size() );
for( int i = 0; i < contours.size(); i++ ) {
minRect[i] = minAreaRect( Mat(contours[i]) );
}
也可以用椭圆vector<RotatedRect> minEllipse( contours.size() );
for( int i = 0; i < contours.size(); i++ )
if( contours[i].size() > 5 )
minEllipse[i] = fitEllipse( Mat(contours[i]) );
还有很多好用的函数