OpenCV学习笔记15 OpenCV图像处理模块ImgProc Module. Image Processing(八)

3.20 在图像中寻找轮廓 


使用 findContours 函数寻找轮廓。
使用 drawContours 函数绘出轮廓。

  Mat canny_output;
  vector > contours;
  vector hierarchy;

  /// 用Canny算子检测边缘
  Canny( src_gray, canny_output, thresh, thresh*2, 3 );
  /// 寻找轮廓
  findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 绘出轮廓
  Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
     }
findContours 函数参数说明:
canny_output:输入,源图像,8位单通道图像,非零像素看作1,零值像素仍为0(其实就是二值图像)。
contours:输出,检测到的轮廓,每一个轮廓都存储在一个 vector 中.
hierarchy:可选的输出数组,包含了图像的拓扑信息。它有尽可能多的轮廓数目的元素。记录了轮廓的层次信息。
mode:轮廓的检测模式。 
CV_RETR_EXTERNAL:仅检测外轮廓。
CV_RETR_LIST:检测所有轮廓,但不建立任何层次关系。
CV_RETR_CCOMP:检测所有轮廓并把它们组织成两级层次。顶层是外轮廓,第二层是内孔的边界。如果在孔内还有轮廓,则放置在顶层。
CV_RETR_TREE:检测所有轮廓并重构一个完整的嵌套式层次结构轮廓。
method:轮廓逼近方法。
CV_CHAIN_APPROX_NONE:存储所有的轮廓点,任意两个连续的轮廓点之间的关系是垂直、水平或对角线相邻。
CV_CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角线段,只留下它们的端点。
CV_CHAIN_APPROX_TC89_L1和CV_CHAIN_APPROX_TC89_KCOS:适用于 Tech-Chin 链逼近算法的一种。
offset:可选偏移量。如果轮廓从图像的ROI中提取,轮廓坐标是ROI中的位置,而分析应针对整幅图像,则得到的轮廓坐标应该进行一定的偏移,移回原图像的坐标位置。

drawContours 函数参数说明:
drawing:输出目标图像。
contours:输入的所有轮廓,每个轮廓存储为vector
i:要画的轮廓线的索引。如果为负数,则绘制所有轮廓。
color:轮廓线的颜色。
2:轮廓线的粗细。
8:连接线的类型。
hierarchy:关于层次的可选信息。
0:绘制轮廓的最大水平。如果是0,只绘制指定的轮廓。如果是1,绘制指定轮廓和被嵌套的轮廓。如果是2,绘制指定轮廓,被嵌套轮廓和迭代嵌套的轮廓。只有上一个参数hierarchy有用时才考虑使用该参数。
Point():可选偏移量。解释同上一个函数的offset。


3.21 计算凸包 - Convex Hull


凸包(Convex Hull)是一个计算几何(图形学)中的概念。用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有点的。严谨的定义和相关概念参见维基百科:凸包。
使用 convexHull 函数计算凸包。
在进行凸包计算之前,先要将图像转换到灰度图并进行滤波处理。

   Mat src_copy = src.clone();
   Mat threshold_output;
   vector > contours;
   vector hierarchy;

   /// 对图像进行二值化
   threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );

   /// 寻找轮廓
   findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

   /// 对每个轮廓计算其凸包
   vector >hull( contours.size() );
   for( int i = 0; i < contours.size(); i++ )
      {  convexHull( Mat(contours[i]), hull[i], false ); }

   /// 绘出轮廓及其凸包
   Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
   for( int i = 0; i< contours.size(); i++ )
      {
        Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
        drawContours( drawing, contours, i, color, 1, 8, vector(), 0, Point() );
        drawContours( drawing, hull, i, color, 1, 8, vector(), 0, Point() );
      }
convexHull 函数参数说明:
Mat(contours[i]):输入的2维点集,存储在 vector 或 Mat 中。
hull[i]:输出的凸包。同轮廓的存储方式类似,存储构成凸包的点集。它也可以存储输入的原始点集数组的索引。
false:标志位。为true时返回构成凸包的点。为false时返回凸包点的索引。当hull是vector时,该标志位被忽略,输出取决于vector的具体类型:vector则返回点集,vector则返回索引(reference_manual上这样说的,感觉说反了,存疑)。


3.22 创建包围轮廓的矩形和圆形边界框


使用 boundingRect 函数计算包围轮廓的矩形框。
使用 minEnclosingCircle 函数计算完全包围已有轮廓的最小圆。

/** @thresh_callback 函数 */
void thresh_callback(int, void* )
{
  Mat threshold_output;
  vector > contours;
  vector hierarchy;

  /// 使用Threshold检测边缘
  threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
  /// 找到轮廓
  findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 多边形逼近轮廓 + 获取矩形和圆形边界框
  vector > contours_poly( contours.size() );
  vector boundRect( contours.size() );
  vectorcenter( contours.size() );
  vectorradius( contours.size() );

  for( int i = 0; i < contours.size(); i++ )
     { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
       boundRect[i] = boundingRect( Mat(contours_poly[i]) );
       minEnclosingCircle( contours_poly[i], center[i], radius[i] );
     }


  /// 画多边形轮廓 + 包围的矩形框 + 圆形框
  Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( drawing, contours_poly, i, color, 1, 8, vector(), 0, Point() );
       rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
       circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );
     }
boundingRect 函数参数说明:
Mat(contours_poly[i]):输入的点集数组,计算出恰好完全包围该点集的矩形。返回描述矩形的Rect类型。

minEnclosingCircle 函数参数说明:
contours_poly[i]:输入一组2维点集,存储在 vector 或 Mat 中。
center[i]:输出圆心。
radius[i]:输出圆的半径。


3.23 为轮廓创建可倾斜的边界框和椭圆


使用 minAreaRect 函数计算包围轮廓的最小矩形框(可能是倾斜的)。
使用 fitEllipse 函数计算包围轮廓的最小椭圆形。

  Mat threshold_output;
  vector > contours;
  vector hierarchy;

  /// 阈值化检测边界
  threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
  /// 寻找轮廓
  findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 对每个找到的轮廓创建可倾斜的边界框和椭圆
  vector minRect( contours.size() );
  vector minEllipse( contours.size() );

  for( int i = 0; i < contours.size(); i++ )
     { minRect[i] = minAreaRect( Mat(contours[i]) );
       if( contours[i].size() > 5 )
         { minEllipse[i] = fitEllipse( Mat(contours[i]) ); }
     }

  /// 绘出轮廓及其可倾斜的边界框和边界椭圆
  Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       // contour
       drawContours( drawing, contours, i, color, 1, 8, vector(), 0, Point() );
       // ellipse
       ellipse( drawing, minEllipse[i], color, 2, 8 );
       // rotated rectangle
       Point2f rect_points[4]; minRect[i].points( rect_points );
       for( int j = 0; j < 4; j++ )
          line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
     }
minAreaRect 函数参数说明:
Mat(contours[i]):输入的一组点集。返回包围该点集的最小矩形,矩形可能是旋转倾斜的情况。

fitEllipse 函数参数说明:
Mat(contours[i]):输入的一组点集。计算包围该点集的最小平方意义上的椭圆,返回的是 该椭圆的外接矩形


你可能感兴趣的:(opencv)