图像轮廓
图像轮廓是一系列相连的点组成的曲线,代表了物体的基本外形,相对于边缘,轮廓是连续的,边缘并不全部连续。一般地,获取图像轮廓要经过下面几个步骤:
查找轮廓
void findContours( InputArray image, OutputArrayOfArrays contours,int mode, int method, Point offset = Point()); /******************************************************************* * image: 单通道灰度图 * contours: 检测到的轮廓,存储的是点坐标 * mode: 轮廓检索模式 * method: 轮廓逼近方法 * offset: 按照偏移量移动所有的轮廓 一般不使用 *********************************************************************/
void findContours( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode,int method, Point offset = Point()); /******************************************************************* * image: 输入单通道灰度图 * contours: 检测到的轮廓,存储的是点坐标 * hierarchy: 轮廓的拓扑信息 * contours[i]包含4个hierarchy[i]元素, * hierarchy[i][0]:后一个轮廓 * hierarchy[i][1]:前一个轮廓 * hierarchy[i][2]:父轮廓 * hierarchy[i][3]:内嵌轮廓 * mode: 轮廓检索模式 * method: 轮廓逼近方法 * offset: 按照偏移量移动所有的轮廓 一般不使用 *********************************************************************/
//mode取值: enum RetrievalModes { RETR_EXTERNAL = 0,//只检索最外面的轮廓 RETR_LIST = 1,//检索所有轮廓,并保存到一条链表中 RETR_CCOMP = 2,//检索所有轮廓,组织为顶层(外部边界)和次层(内部边界) RETR_TREE = 3,//检索所有的轮廓,并重构嵌套轮廓的整个层次 RETR_FLOODFILL = 4 //支持CV_32SC1图像,不等于仅支持CV_8UC1图像 }; //method取值: enum ContourApproximationModes { CHAIN_APPROX_NONE = 1, //保存所有轮廓点 CHAIN_APPROX_SIMPLE = 2, //压缩水垂直对角线,只保留线的两端点 CHAIN_APPROX_TC89_L1 = 3, //使用teh-Chinl chain 近似算法 CHAIN_APPROX_TC89_KCOS = 4 //使用teh-Chinl chain 近似算法 };
- void drawContours( InputOutputArray image, InputArrayOfArrays contours,int contourIdx, const Scalar& color,
- int thickness = 1, int lineType = LINE_8,InputArray hierarchy = noArray(),int maxLevel = INT_MAX, Point offset = Point());
- /*******************************************************************
- * image: 输出单通道灰度图
- * contours: 所有的输入轮廓
- * contourIdx: 指定轮廓列表的索引 ID(将被绘制)
- * 若为负数,则所有的轮廓将会被绘制
- * color: 绘制轮廓的颜色
- * thickness: 绘制轮廓线条的宽度
- * lineType: 线条的类型,8连通型或4连通型
- * hierarchy: 层次结构信息
- * maxLevel: 绘制轮廓的最高级别
- * 0:绘制指定轮廓
- * 1:绘制该轮廓和所有嵌套轮廓
- * 2:绘制该轮廓、嵌套轮廓子轮廓等
- * offset: 按照偏移量移动所有的轮廓
- *********************************************************************/
- #include
- #include
- #include
- #include
- #include
- using namespace cv;
- using namespace std;
- class OutLine
- {
- public:
- OutLine() :img(imread("testMin.jpg", IMREAD_GRAYSCALE))
- {
- result["Gray"] = img;
- }
- void Show()
- {
- for (auto& v : result)
- {
- imshow(v.first, v.second);
- }
- waitKey(0);
- }
-
- //查找轮廓
- void FindOutLine()
- {
- threshold(result["Gray"], result["Binary"], 125, 255, THRESH_BINARY);
- findContours(result["Binary"], contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
- }
- //着色
- void DrawOutLine()
- {
- result["OutLine"] = Mat::zeros(result["Binary"].size(), CV_8UC3);
- for (int i = 0; i < contours.size(); i++)
- {
- Scalar color = Scalar(0, 255, 0);
- //drawContours(result["OutLine"], contours, i, color, 1, 8, hierarchy);
- drawContours(result["OutLine"], contours, i, color);
- }
- }
- private:
- Mat img;
- map
result; - vector
> contours; - vector
hierarchy; - };
-
- int main()
- {
- OutLine* p = new OutLine;
- p->FindOutLine();
- p->DrawOutLine();
- p->Show();
- return 0;
- }
凸包
凸包指如果在集合A内连接任意两个点的直线段都在A的内部,则称集合A是凸形的。
简单点理解,就是一个多边型,没有凹的地方。凸包(凸壳)能包含点集中所有的点,凸包检测常应用在物体识别、手势识别及边界检测等领域。一个轮廓可以有无数个包围它的外壳,而其中表面积最小的一个外壳,就是凸包。
凸包绘制步骤
图像灰度处理
灰度图二值化处理
轮廓检测得到候选点
凸包API调用,筛选可用点
绘制显示
API介绍
void convexHull( InputArray points, OutputArray hull,bool clockwise = false, bool returnPoints = true ); /******************************************************************* * points: 轮廓点集 * hull: 凸包点集输出 * clockwise: 凸包方向的标志位 * true:顺时针方向 * false:逆时针 * returnPoints: 返回点个数 *********************************************************************/
注意:
①在做二值化处理之前,建议先用blur函数进行模糊处理(为了降噪)-->再去二值化处理效果会更好
②在画关键点和凸包处是一个重点。
hull[(j+1)%count]随着j不断循环,最后一个点以及j+1取余之后会回到第一个点,实现闭环,完成凸包的绘制。
③ 绘制凸包前,需要得到外部轮廓的关键点,需要使用findContour函数去找并进行相应的存储
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- using namespace cv;
- class ConvexHull
- {
- public:
- ConvexHull() :img(imread("hand.jpg"))
- {
- result["img"] = img;
- }
- void TestConvexHull()
- {
- //图像灰度处理
- cvtColor(result["img"], result["Gray"], COLOR_BGR2GRAY);
- //灰度图二值化处理
- blur(result["Gray"], result["Gray"], Size(3, 3));
- threshold(result["Gray"], result["Binary"], 240, 255, THRESH_BINARY_INV);
- //轮廓检测得到候选点
- vector
> contours; - vector
hierarchy; - findContours(result["Binary"], contours, hierarchy, RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
- //凸包API调用,筛选可用点
- //绘制显示
- for (int i = 0; i < contours.size(); i++)
- {
- vector
hull; - convexHull(contours[i], hull);
- //bool isOk = isContourConvex(contours[i]); //判断当前点是否为有效点
- int count = hull.size();
- for (int j = 0; j < count; j++)
- {
- circle(img, hull[j], 5, Scalar(0, 0, 255));
- line(img, hull[j % count], hull[(j + 1) % count], Scalar(255, 0, 0), 2);
- }
- }
- }
- void Show()
- {
- for (auto& v : result)
- {
- imshow(v.first, v.second);
- }
- waitKey(0);
- }
- private:
- Mat img;
- map
result; - };
-
- int main()
- {
- ConvexHull* p = new ConvexHull;
- p->TestConvexHull();
- p->Show();
- return 0;
- }