part11. 图像的轮廓
在该系列第三篇文章中,曾经简单地介绍过轮廓和轮廓发现。
11.1 轮廓的基本概念
图像的轮廓是指图像中具有相同颜色或灰度值的连续点的曲线。轮廓和边缘是有联系的,边缘是轮廓的基础,轮廓是边缘的连续集合。
轮廓和边缘的区别是:
轮廓是连续的,边缘可以是连续的,也可以是离散的。
轮廓是完整的,边缘可以是完整的,也可以是不完整的。
轮廓可以有各种形状,边缘通常是线性的。
21.2 轮廓发现和轮廓提取
轮廓发现是指在图像中找到所有可能的轮廓。
轮廓提取是指从图像中找到所有有效的轮廓和轮廓的具体信息。
轮廓发现是轮廓提取的前提,轮廓提取在轮廓发现的基础上进一步提取轮廓的形状和位置信息等等。
下面的代码,经过一系列操作找到二值图像的有效轮廓后,获取这些轮廓的最小外接矩形,最后用线在原图中框出这些外接矩形,从而在原图中找到比较明显的苹果。
#include #include opencv2/imgproc.hpp#include opencv2/highgui.hppusing namespace std;using namespace cv;bool ascendsort(vector a,vector b){ return contourarea(a) > contourarea(b);}int main(int argc, char **argv) { mat src = imread(.../apple.jpg); imshow(src, src); mat hsv,edge; cvtcolor(src, hsv, cv::color_bgr2hsv); // bgr 转换到 hsv 色彩空间 imshow(hsv, hsv); cv::scalar lower_red(0, 43, 46); cv::scalar upper_red(10, 255, 255); // 定义红色的 hsv 范围 mat mask; inrange(hsv, lower_red, upper_red, mask); // 通过 inrange 函数实现二值化 imshow(mask, mask); mat kernel = getstructuringelement(morph_rect, size(15, 15)); morphologyex(mask, mask, morph_close, kernel); // 形态学操作 morphologyex(mask, mask, morph_open, kernel); // 形态学操作 imshow(morphology, mask); vector contours; vector hierarchy; findcontours(mask, contours, hierarchy, retr_external, chain_approx_simple); sort(contours.begin(), contours.end(), ascendsort);//ascending sort for (size_t i = 0; i< contours.size(); i++) { double area = contourarea(contours[i]); if (area < 22000) { continue; } cout << area = << area < contourarea(b);}int main(int argc, char **argv) { mat src = imread(.../paperclip.jpg); imshow(src, src); mat gray,thresh; cvtcolor(src, gray, cv::color_bgr2gray); imshow(gray, gray); threshold(gray,thresh,0,255,thresh_binary_inv | thresh_otsu); imshow(thresh, thresh); vector contours; vector hierarchy; findcontours(thresh, contours, hierarchy, retr_external, chain_approx_simple); sort(contours.begin(), contours.end(), ascendsort);//ascending sort for (size_t i = 0; i< contours.size(); i++) { double area = contourarea(contours[i]); double length = arclength(contours[i],true); if (area < 1000) { continue; } cout << area = << area << , length = << length < contourarea(b);}int main(int argc, char **argv) { mat src = imread(.../fruit.jpg); imshow(src, src); mat gray,thresh; cvtcolor(src, gray, cv::color_bgr2gray); threshold(gray,thresh,0,255,thresh_binary | thresh_otsu); vector contours; vector hierarchy; findcontours(thresh, contours, hierarchy, retr_external, chain_approx_simple); sort(contours.begin(), contours.end(), ascendsort);//ascending sort rotatedrect rrt = minarearect(contours[0]);// 获取最大轮廓的最小外接矩形 point2f pt[4]; rrt.points(pt); line(src, pt[0], pt[1], scalar(255, 0, 0), 8, 8); line(src, pt[1], pt[2], scalar(255, 0, 0), 8, 8); line(src, pt[2], pt[3], scalar(255, 0, 0), 8, 8); line(src, pt[3], pt[0], scalar(255, 0, 0), 8, 8); rect rect = boundingrect(contours[0]);// 获取最大轮廓的外接矩形 rectangle(src,rect,scalar(0, 255, 255), 8, 8);// 绘制外接矩形 imshow(result, src); waitkey(0); return 0;}
通过上述例子可以看到,最小外接矩形能够更精确地描述轮廓的形状和大小。
外接矩形和最小外接矩形有各自的使用场景,例如在对象检测中,可以使用外接矩形来粗略定位物体,而使用最小外接矩形来精确定位物体。
43.2 凸包
凸包(convex hull)是计算几何(图形学)中的概念。在一个实数向量空间 v 中,对于给定集合 x,所有包含 x 的凸集的交集 s 被称为 x 的 凸包。
在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。
平面的一个子集 s 被称为是“凸”的,当且仅当对于任意两点 p,s ∈s,线段 ps 都完全属于s。
一个点集 p 的凸包ch(p),就是包含 p 的最小凸集——即包含p的所有凸集的交。
凸包的性质:
凸包是凸集。
凸包的周长是最小的。
凸包的面积是最小的。
凸包的质心是所有点的质心的均值。
opencv 提供了 convexhull() 函数寻找轮廓的凸包以及 iscontourconvex() 函数用于判断轮廓是否为凸轮廓。凸轮廓是指所有内角都小于或等于 180 度的轮廓。
#include #include opencv2/imgproc.hpp#include opencv2/highgui.hppusing namespace std;using namespace cv;int main(int argc, char **argv) { mat src = imread(.../hand.jpg); imshow(src, src); mat gray,thresh; cvtcolor(src, gray, cv::color_bgr2gray); threshold(gray,thresh,0,255,thresh_binary_inv | thresh_otsu); imshow(thresh, thresh); mat mask; mat kernel = getstructuringelement(morph_rect, size(31, 31)); morphologyex(thresh, mask, morph_close, kernel); // 形态学操作 imshow(morphology, mask); vector contours; vector hierarchy; findcontours(mask, contours, hierarchy, retr_external, chain_approx_simple); vector hull(contours.size()); mat drawing = mat::zeros(mask.size(),cv_8uc3); for (size_t i = 0; i< contours.size(); i++) { double area = contourarea(contours[i]); if (area < 100) { continue; } convexhull(contours[i], hull[i], false); bool ishull = iscontourconvex(contours[i]); cout << ishull = << ishull << endl; drawcontours(drawing, contours, i, scalar(0, 0, 255), 8, 8); drawcontours(drawing, hull, i, scalar(255, 0, 0), 8, 8); drawcontours(src, hull, i, scalar(255, 0, 0), 8, 8); } imshow(result,src); imshow(drawing,drawing); waitkey(0); return 0;}
执行结果:
ishull = 0ishull = 0
part44. 总结
轮廓的基础特征是计算机视觉中的重要工具,这些特征可以应用于对象检测、形状识别、测量等各种应用场景。后续还会介绍更多的轮廓特征。
彩电的白平衡与暗平衡的调整
基于STC89C55RD+单片机的LED点阵显示系统的设计
工业除静电离子风机的维护与保养
博世ESP电子车身稳定系统保障人们的行车安全
什么是电子电气架构
OpenCV4之图像的轮廓
索尼xperia xz premium贵破天:骁龙835+4K屏幕+拍照卖5699元,买不起靠边!
全方位测评海马福美来M5 1.6L
电力系统中接地的作用和种类
iPhone8上市时间确定:实拍iPhone8中国生产,运往美国,卖回中国!搞事情
湖南大学等发表柔性SAW传感综述论文,被期刊选为亮点论文
浦东欲将打造国内顶级机器人产业高地
DDR3成主流产品 海力士增NAND Flash产能
2018i-VISTA智能网联汽车国际研讨会正式召开
iPhone11Pro价格大幅度下调的原因是什么?
无人机黑飞监管难 有商家千元“破解”禁飞区
邀请函|WPT2023第23届中国国际(西部)信息通信博览会 暨成都国际数字智能展 (X)
PCB厚铜板的设计,这一点一定要注意
PCBA加工立碑产生的原因和解决方法
旗舰处理器之神,高通骁龙835发布,规格撼人