OpenCV学习笔记(十五)形状检测

来源:互联网 发布:外贸域名网址 编辑:程序博客网 时间:2024/05/17 07:35

1 轮廓检测

图像目标中的形状检测是图像识别的重要的技术之一,对物体进行检测并提取,首先要做的就是提取物体的轮廓信息,然后在通过点集特征选择相应的算法进行处理,最后得到物体的形状信息。轮廓形状是我们看到物体最开始的印象,轮廓提取的原理是通过对图像进行二值化,利用边缘点连接的层次差别,提取位于数结构特征高的区域点集构成的集合,这部分最可能是物体的轮廓。

主要用到的函数findContours()对物体轮廓进行检测。

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

  • image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() ,Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the imagewhile extracting the contours.
  • contours – Detected contours. Each contour is stored as a vector of points.
  • hiararchy – Optional output vector containing information about the image topology. It has as many elements as the number of contours. For each contour contours[i] , the elements hierarchy[i][0] , hiearchy[i][1] ,hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level: the first child contourand the parent contour, respectively. If for a contour ithere are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.
  • mode –

    Contour retrieval mode.

    • CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets hierarchy[i][2]=hierarchy[i][3]=-1 for all the contours.
    • CV_RETR_LIST retrieves all of the contours without establishing any hierarchical relationships.
    • 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 retrieves all of the contours and reconstructs a full hierarchy of nested contours. This full hierarchy is built and shown in the OpenCV contours.c demo.
  • method –

    Contour approximation method.

    • CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and(x2,y2) of the contour will be either horizontal, vertical or diagonal neighbors, that is, max(abs(x1-x2),abs(y2-y1))==1.
    • CV_CHAIN_APPROX_SIMPLE compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points.
    • CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS applies one of the flavors of the Teh-Chin chain approximation algorithm. See [TehChin89] for details.
  • offset – Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.

然后根据寻找出来的轮廓contours,绘制轮廓。使用函数drawContours()。

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() )
  • image – Destination image.
  • contours – All the input contours. Each contour is stored as a point vector.
  • contourIdx – Parameter indicating a contour to draw. If it is negative, all the contours are drawn.
  • color – Color of the contours.
  • thickness – Thickness of lines the contours are drawn with. If it is negative (for example, thickness=CV_FILLED), the contour interiors are drawn.
  • lineType – Line connectivity. See line() for details. Type=8/4/CV_AA
  • hierarchy – Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see maxLevel ).
  • maxLevel – Maximal level for drawn contours. If it is 0, only the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is hierarchy available.
  • offset – Optional contour shift parameter. Shift all the drawn contours by the specified \texttt{offset}=(dx,dy) Point();

使用这两个函数就可以完成我们的形状检测与绘画。
完整程序轮廓检测:
#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>#include <stdio.h>#include <stdlib.h>using namespace cv;using namespace std;Mat srcImagel;Mat srcGray;int max_thresh = 255;int thresh = 100;RNG rng(12345);//鼠标回调事件void thresh_callback(int, void*){Mat canny_output;vector<vector<Point>> contours;vector<Vec4i> hierarchy;//用canny算子检测边缘Canny(srcGray, 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());}//显示轮廓结果namedWindow("Contours", CV_WINDOW_AUTOSIZE);imshow("Contours", drawing);}int main(){Mat srcImage = imread("D:\\6.jpg");if (!srcImage.data)return -1;cvtColor(srcImage, srcGray, COLOR_BGR2GRAY);blur(srcGray, srcGray, Size(3, 3));//创建窗体char* source_window = "srcImage";namedWindow(source_window, CV_WINDOW_AUTOSIZE);imshow(source_window, srcImage);//滑动条控制Canny阈值createTrackbar(" thresh:", "srcImage", &thresh, max_thresh, thresh_callback);thresh_callback(0, 0);waitKey(0);return 0;}

原图:


效果图:



2 凸包检测

凸包检测是给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它是能包含点集中的所有点的。理解物体形状或轮廓的一种比较有用的方法便是计算一个物体的凸包,然后计算其凸缺陷。
OpenCV中提供了函数convesHull()用于对物体轮廓凸包进行检测,对形状凸包缺陷分析时使用convexityDefects()函数,每个缺陷区包含四个特征量:起始点、结束点、距离和最远点。
下面介绍这两个函数:
void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true )
  • points – Input 2D point set, stored in std::vector or Mat.
  • hull – Output convex hull. It is either an integer vector of indices or vector of points. In the first case, the hull elements are 0-based indices of the convex hull points in the original array (since the set of convex hull points is a subset of the original point set). In the second case, hull elements aree the convex hull points themselves.
  • clockwise – Orientation flag. If it is true, the output convex hull is oriented clockwise. Otherwise, it is oriented counter-clockwise. The usual screen coordinate system is assumed so that the origin is at the top-left corner, x axis is oriented to the right, and y axis is oriented downwards.
  • returnPoints – Operation flag. In case of a matrix, when the flag is true, the function returns convex hull points. Otherwise, it returns indices of the convex hull points. When the output array is std::vector, the flag is ignored, and the output depends on the type of the vector: std::vector<int> implies returnPoints=truestd::vector<Point> implies returnPoints=false.

ConvexityDefects(const CvArr* contour, const CvArr* convexhull, CvMemStorage* storage=NULL )
  • contour – Input contour.
  • convexhull – Convex hull obtained using ConvexHull2() that should contain pointers or indices to the contour points, not the hull points themselves (the returnPoints parameter in ConvexHull2() should be zero).
  • storage – Container for the output sequence of convexity defects. If it is NULL, the contour or hull (in that order) storage is used.

convexhull可以得到vector<vector<Point> >和vector<vector<int>>两种类型结果,ConvexityDefects中的convechull凸包检测函数convexhull应该为vector<vector<int> >类型,否则不能通过ASSERT检查;参数convexityDefects为输出参数,检测到的结果为vector<vector<Vec4i> >类型,Vec4i中存储了起始点、结束点、距离及最远点到凸包的距离。

直接通过程序来说明:
#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>#include <stdio.h>#include <stdlib.h>using namespace cv;using namespace std;//设置全局参数Mat srcImage, srcGray;int thresh = 100;int max_thresh = 255;RNG rng(12345);void thresh_callback(int, void*){Mat srcTemp = srcImage.clone();Mat threMat;//轮廓检测参数vector<vector<Point> > contours;vector<Vec4i> hierarchy;//阈值化操作threshold(srcGray, threMat, thresh, 255, THRESH_BINARY);//轮廓检测findContours(threMat, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));//凸包及缺陷检测参数vector<vector<Point> > pointHull(contours.size());vector<vector<int> > intHull(contours.size());vector<vector<Vec4i> > hullDefect(contours.size());for (size_t i = 0; i < contours.size(); i++){//Point类型凸包检测convexHull(Mat(contours[i]), pointHull[i], false);//int 类型凸包检测convexHull(Mat(contours[i]), intHull[i], false);//凸包缺陷检测convexityDefects(Mat(contours[i]), intHull[i], hullDefect[i]);}//绘制凸包及缺陷检测Mat drawing = Mat::zeros(threMat.size(), CV_8UC1);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(drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point());drawContours(drawing, pointHull, i, color, 1, 8, vector<Vec4i>(), 0, Point());//绘制缺陷size_t count = contours[i].size();if (count < 300)continue;//设置凸包缺陷迭代器vector<Vec4i>::iterator iterDefects = hullDefect[i].begin();//遍历得到4个特征量while (iterDefects != hullDefect[i].end()){Vec4i& v = (*iterDefects);//起始位置int startidx = v[0];Point ptStart(contours[i][startidx]);//终止位置int endidx = v[1];Point ptEnd(contours[i][endidx]);//内凸壳最远的点缺陷int faridx = v[2];Point ptFar(contours[i][faridx]);//凸点之间的最远点int depth = v[3] / 256;//绘制相应的线与圆检测结果if (depth > 20 && depth < 80){line(drawing, ptStart, ptFar, CV_RGB(0, 255, 0), 2);line(drawing, ptEnd, ptFar, CV_RGB(0, 255, 0), 2);circle(drawing, ptStart, 4, Scalar(255, 0, 100), 2);circle(drawing, ptEnd, 4, Scalar(255, 0, 100), 2);circle(drawing, ptFar, 4, Scalar(100, 0, 255), 2);}iterDefects++;}}imshow("result", drawing);}int main(){Mat srcImage = imread("D:\\3.jpg");if (!srcImage.data)return -1;cvtColor(srcImage, srcGray, CV_BGR2GRAY);blur(srcGray, srcGray, Size(3, 3));char* source_window = "Source";namedWindow(source_window, CV_WINDOW_AUTOSIZE);imshow(source_window, srcImage);createTrackbar("Thewshold:", "Source", &thresh, max_thresh, thresh_callback);thresh_callback(0, 0);waitKey(0);return 0;}





















0 0