凸包跟多边形逼近很像,只不过它是物体最外层的"凸"多边形:集合A内连接任意两个点的直线都在A的内部,则称集合A是凸形的。如下图,红色的部分为手掌的凸包,双箭头部分表示凸缺陷(Convexity Defects),凸缺陷常用来进行手势识别等;
#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_8UC3); 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() { srcImage = imread("E:\VS2015Opencv\vs2015\project\picture\01.jpg"); if (!srcImage.data) return -1; cvtColor(srcImage, srcGray, CV_BGR2GRAY); blur(srcGray, srcGray, Size(3, 3)); char* sour_window = "Sourse"; namedWindow(sour_window, CV_WINDOW_AUTOSIZE); imshow(sour_window, srcImage); createTrackbar("Thewshold:", sour_window, &thresh, max_thresh, thresh_callback); thresh_callback(0, 0); waitKey(0); return 0; }