/*
*凸包
凸包是在轮廓提取的基础上再走一步,轮廓就是那些点,要把这些轮廓全部包含在一个里面就需要一个凸包把它包含在里面
* 概念介绍
什么是凸包(Convex Hull),在一个多变形边缘或者内部任意两个点的连线都包含在多边形边界或者内部。
正式定义
包含点集合S中所有点的最小凸多边形称为凸包。
*检测算法
- Graham扫描法
*Graham扫描算法
首先选择Y方向最低的点作为起始点p0,从p0开始极坐标扫描,依次添加p1….pn(排序顺序是根据极坐标的角度大小,逆时针方向),对每个点pi来说,如果添加pi点到凸包中导致一个左转向(逆时针方法)则添加该点到凸包,
反之如果导致一个右转向(顺时针方向)删除该点从凸包中。
*步骤
1:首先把图像从RGB转为灰度
2:然后再转为二值图像 这里二值化使用阈值化的方法,没有用Canny,多熟悉熟悉其他的API,免得忘记
3:在通过发现轮廓得到候选点
4:凸包API调用
5:绘制显示
*API说明cv::convexHull
convexHull(
InputArray points,// 输入候选点,来自findContours 第一步首先要寻找到轮廓
OutputArray hull,// 凸包 凸包也有多少个点嘛,那几个点把它弄出来
bool clockwise,// default true, 顺时针方向
bool returnPoints // true 表示返回点个数,如果第二个参数是vector<Point>(即数组)则自动忽略,凸包有多少个点给返回出来
)
*/
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat src, src_gray, dst;
int threshold_value = 80;
int threshold_max = 255;
RNG rng(12345);
void Threshold_Callback(int, void*);
int main()
{
src = imread("D:/A_Graduation/Learning/opencv/learningOpencv/hand.png");
cvtColor(src, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3), Point(-1, -1), BORDER_DEFAULT); //适当降低图像噪声,二值化可以取得更好的效果
//小小的blur一下,千万不要给它来个太猛的,来个太猛的就怕把那些信息都覆盖掉了,边缘都没有了,你还怎么去发现轮廓
imshow("input", src_gray);
createTrackbar("Threshold : ", "output", &threshold_value, threshold_max, Threshold_Callback);
Threshold_Callback(0, 0);
waitKey(0);
return 0;
}
void Threshold_Callback(int, void*)
{
//把它变成一张二值图像
Mat bin_output;
threshold(src_gray, bin_output, threshold_value, threshold_max, THRESH_BINARY); //THRESH_BINARY二值化
//发现轮廓,就知道有多少个轮廓了
vector<vector<Point>> contours; //把轮廓放到这个容器当中
vector<Vec4i> hierachy;
findContours(bin_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//做凸包
vector<vector<Point>> convexs(contours.size()); //每个凸包也是一系列的点组成的,初始化和contours一样多
for (size_t i = 0; i < contours.size(); i++)
{
convexHull(contours[i], convexs[i], false, true);
}
//绘制,把凸包显示出来
dst = Mat::zeros(src.size(), CV_8UC3); //绘制到一张RGB的图像上去
vector<Vec4i> empty(0);
for (size_t k = 0; k < contours.size(); k++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(dst, contours, k, color, 2, LINE_8, hierachy, 0, Point(0, 0));
drawContours(dst, convexs, k, color, 2, LINE_8, empty, 0, Point(0, 0));
}
imshow("output", dst);
return;
}
/*
* 对图像多做几个预处理出来的结果就比较好,如果直接用算法效果可能不好,二值化,模糊,多做几步初始化处理,开操作,闭操作,
把一些噪声都去掉,最后再去做这个凸包可能效果就不一样了,去了干扰后就不一样了,有很多前缀的步骤一定不要忘记,做图像处理
最忌讳的一点就是拿着个算法,说这个算法是人脸识别的,拿着它就对人一照,什么结果都没有,说识别出来你这个算法错了,其实不是,
它前面还有n步,你要排除各种干扰,其中隐含着很多种步骤的,而不是有一个API就万事大吉了
*/