一 概念:
Convexity hull, Convexity defects
如上图所示,黑色的轮廓线为convexity hull, 而convexity hull与手掌之间的部分为convexity defects. 每个convexity defect区域有四个特征量:起始点(startPoint),结束点(endPoint),距离convexity hull最远点(farPoint),最远点到convexity hull的距离(depth)。
二.OpenCV中的相关函数
void convexityDefects(InputArray contour, InputArray convexhull, OutputArrayconvexityDefects)
参数:
coutour: 输入参数,检测到的轮廓,可以调用findContours函数得到;
convexhull: 输入参数,检测到的凸包,可以调用convexHull函数得到。注意,convexHull函数可以得到vector<vector<Point>>和vector<vector<int>>两种类型结果,这里的convexhull应该为vector<vector<int>>类型,否则通不过ASSERT检查;
convexityDefects:输出参数,检测到的最终结果,应为vector<vector<Vec4i>>类型,Vec4i存储了起始点(startPoint),结束点(endPoint),距离convexity hull最远点(farPoint)以及最远点到convexity hull的距离(depth)
三.代码
-
//http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/hull/hull.html
-
//http://www.codeproject.com/Articles/782602/Beginners-guide-to-understand-Fingertips-counting
-
-
#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 src; Mat src_gray;
-
int thresh =
100;
-
int max_thresh =
255;
-
RNG rng(12345);
-
-
/// Function header
-
void thresh_callback(int, void* );
-
-
/** @function main */
-
int main( int argc, char** argv )
-
{
-
/// Load source image and convert it to gray
-
src = imread( argv[
1],
1 );
-
-
/// Convert image to gray and blur it
-
cvtColor( src, src_gray, CV_BGR2GRAY );
-
blur( src_gray, src_gray, Size(
3,
3) );
-
-
/// Create Window
-
char* source_window =
"Source";
-
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
-
imshow( source_window, src );
-
-
createTrackbar(
" Threshold:",
"Source", &thresh, max_thresh, thresh_callback );
-
thresh_callback(
0,
0 );
-
-
waitKey(
0);
-
return(
0);
-
}
-
-
/** @function thresh_callback */
-
void thresh_callback(int, void* )
-
{
-
Mat src_copy = src.clone();
-
Mat threshold_output;
-
vector<
vector<Point> > contours;
-
vector<Vec4i> hierarchy;
-
-
/// Detect edges using Threshold
-
threshold( src_gray, threshold_output, thresh,
255, THRESH_BINARY );
-
-
/// Find contours
-
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(
0,
0) );
-
-
/// Find the convex hull object for each contour
-
vector<
vector<Point> >hull( contours.size() );
-
// Int type hull
-
vector<
vector<
int>> hullsI( contours.size() );
-
// Convexity defects
-
vector<
vector<Vec4i>> defects( contours.size() );
-
-
for(
size_t i =
0; i < contours.size(); i++ )
-
{
-
convexHull( Mat(contours[i]), hull[i],
false );
-
// find int type hull
-
convexHull( Mat(contours[i]), hullsI[i],
false );
-
// get convexity defects
-
convexityDefects(Mat(contours[i]),hullsI[i], defects[i]);
-
-
}
-
-
/// Draw contours + hull results
-
Mat drawing = Mat::zeros( threshold_output.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, hull, i, color,
1,
8,
vector<Vec4i>(),
0, Point() );
-
-
// draw defects
-
size_t count = contours[i].size();
-
std::
cout<<
"Count : "<<count<<
std::
endl;
-
if( count <
300 )
-
continue;
-
-
vector<Vec4i>::iterator d =defects[i].begin();
-
-
while( d!=defects[i].end() ) {
-
Vec4i& v=(*d);
-
//if(IndexOfBiggestContour == i)
-
{
-
-
int startidx=v[
0];
-
Point ptStart( contours[i][startidx] );
// point of the contour where the defect begins
-
int endidx=v[
1];
-
Point ptEnd( contours[i][endidx] );
// point of the contour where the defect ends
-
int faridx=v[
2];
-
Point ptFar( contours[i][faridx] );
// the farthest from the convex hull point within the defect
-
int depth = v[
3] /
256;
// distance between the farthest point and the convex hull
-
-
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 );
-
}
-
-
/*printf("start(%d,%d) end(%d,%d), far(%d,%d)\n",
-
ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, ptFar.x, ptFar.y);*/
-
}
-
d++;
-
}
-
-
-
}
-
-
/// Show in a window
-
namedWindow(
"Hull demo", CV_WINDOW_AUTOSIZE );
-
imshow(
"Hull demo", drawing );
-
//imwrite("convexity_defects.jpg", drawing);
-
}
四.结果
原图
Convexity defects图,蓝色点是convexity defects的起始点和结束点,红色点是最远点。(为什么有的起始点和结束点中间没有最远点呢?因为只画出了depth范围在20到80之间的convexity defects的起始点、结束点和最远点)
五.参考
[1] Gary Bradski, Adrian Kaehler. Learning OpenCV: Computer Vision with the OpenCV Library. Page258~259.
[2] http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/hull/hull.html
[3] http://www.codeproject.com/Articles/782602/Beginners-guide-to-understand-Fingertips-counting