Opencv之获取边缘和画轮廓

目录(?)[+]有很多时候,我们需要获得图形上的某物体轮廓,Opencv提供两个函数findContours()和drawContours(),一个是寻找轮廓,一个是画轮廓,下面就来介绍这两个函数:

一、findContours()

[cpp] view plaincopy
  1. void findContours//提取轮廓,用于提取图像的轮廓
  2. (
  3. InputOutputArray image,//输入图像,必须是8位单通道图像,并且应该转化成二值的
  4. OutputArrayOfArrays contours,//检测到的轮廓,每个轮廓被表示成一个point向量
  5. OutputArray hierarchy,//可选的输出向量,包含图像的拓扑信息。其中元素的个数和检测到的轮廓的数量相等
  6. int mode,//说明需要的轮廓类型和希望的返回值方式
  7. int method,//轮廓近似方法
  8. Point offset = Point()
  9. )

CV_RETR_EXTERNAL 只检测出最外轮廓即c0。图2中第一个轮廓指向最外的序列,除此之外没有别的连接。

CV_RETR_LIST 检测出所有的轮廓并将他们保存到表(list)中,图2中描绘了这个表,被找到的9条轮廓相互之间由h_prev和h_next连接。这里并没有表达出纵向的连接关系,没有使用v_prev和v_next.

CV_RETR_COMP 检测出所有的轮廓并将他们组织成双层的结构,第一层是外部轮廓边界,第二层边界是孔的边界。从图2可以看到5个轮廓的边界,其中3个包含孔。最外层边界c0有两个孔,c0之间的所有孔相互间由h_prev和h_next指针连接。

CV_RETR_TREE 检测出所有轮廓并且重新建立网状的轮廓结构。图2中,根节点是最外层的边界c0,c0之下是孔h00,在同一层中与另一个孔h01相连接。同理,每个孔都有子节点(相对于c000和c010),这些子节点和父节点被垂直连接起来。这个步骤一直持续到图像最内层的轮廓,这些轮廓会成为树叶节点。

注意,method 也就是轮廓的近似方法

CV_CHAIN_CODE 用freeman链码输出轮廓,其他方法输出多边形(顶点的序列)。

CV_CHAIN_APPROX_NONE将链码编码中的所有点转换为点。

CV_CHAIN_APPROX_SIMPLE压缩水平,垂直或斜的部分,只保存最后一个点。

CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_QPPROX_TC89_KCOS使用Teh-Chin链逼近算法中的一个。

CV_LINK_RUNS与上述的算法完全不同,连接所有的水平层次的轮廓。

二、drawContours()

[cpp] view plaincopy
  1. void drawContours//绘制轮廓,用于绘制找到的图像轮廓
  2. (
  3. InputOutputArray image,//要绘制轮廓的图像
  4. InputArrayOfArrays contours,//所有输入的轮廓,每个轮廓被保存成一个point向量
  5. int contourIdx,//指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓
  6. const Scalar& color,//绘制轮廓所用的颜色
  7. int thickness = 1, //绘制轮廓的线的粗细,如果是负数,则轮廓内部被填充
  8. int lineType = 8, /绘制轮廓的线的连通性
  9. InputArray hierarchy = noArray(),//关于层级的可选参数,只有绘制部分轮廓时才会用到
  10. int maxLevel = INT_MAX,//绘制轮廓的最高级别,这个参数只有hierarchy有效的时候才有效
  11. //maxLevel=0,绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓
  12. //maxLevel=1, 绘制与输入轮廓同一等级的所有轮廓与其子节点。
  13. //maxLevel=2,绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点
  14. Point offset = Point()
  15. )

三、程序实现

[cpp] view plaincopy
  1. #include <opencv2/opencv.hpp>
  2. #include<iostream>
  3. using namespace std;
  4. using namespace cv;
  5. #define WINDOWN_1 "原图"
  6. #define WINDOWN_2 "CANNY图"
  7. #define WINDOWN_3 "效果图"
  8. Mat srcImage, grayImage, out_Canny;
  9. int min_Thresh = 50;
  10. int max_Thresh = 250;
  11. vector<vector<Point>> g_vContours;
  12. vector<Vec4i> g_vHierarchy;
  13. RNG G_RNG(1234);
  14. void Find_Draw_COntours(int ,void*);
  15. int main()
  16. {
  17. srcImage = imread("D://vvoo//BMW_1.jpg");
  18. namedWindow(WINDOWN_1,1);
  19. imshow(WINDOWN_1, srcImage);
  20. cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
  21. blur(grayImage, grayImage, Size(3, 3));
  22. createTrackbar("CANNY 值:", WINDOWN_1, &min_Thresh, max_Thresh, Find_Draw_COntours);
  23. Find_Draw_COntours(0, 0);
  24. waitKey(0);
  25. return 0;
  26. }
  27. void Find_Draw_COntours(int, void*)
  28. {
  29. Canny(grayImage, out_Canny, min_Thresh, max_Thresh *2, 3);
  30. imshow(WINDOWN_2, out_Canny);
  31. findContours(out_Canny, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
  32. Mat Drawing = Mat::zeros(out_Canny.size(), CV_8UC3);
  33. for(int i= 0;i <g_vContours.size(); i++)
  34. {
  35. Scalar color = Scalar(G_RNG.uniform(0, 255), G_RNG.uniform(0, 255), G_RNG.uniform(0, 255));
  36. drawContours(Drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point());
  37. }
  38. imshow(WINDOWN_3, Drawing);
  39. }

结果:

三、实际应用

提取到轮廓后,其实我们更关心的是如果把这些轮廓转换为可以利用的特征,也就是涉及到轮廓的描述问题,这时就有多种方法可以选择,比如矢量化为多边形、矩形、椭圆等。OpenCV里提供了一些这样的函数。

[cpp] view plaincopy
  1. // 轮廓表示为一个矩形
  2. Rect r = boundingRect(Mat(contours[0]));
  3. rectangle(result, r, Scalar(255), 2);
  4. // 轮廓表示为一个圆
  5. float radius;
  6. Point2f center;
  7. minEnclosingCircle(Mat(contours[1]), center, radius);
  8. circle(result, Point(center), static_cast<int>(radius), Scalar(255), 2);
  9. // 轮廓表示为一个多边形
  10. vector<Point> poly;
  11. approxPolyDP(Mat(contours[2]), poly, 5, true);
  12. vector<Point>::const_iterator itp = poly.begin();
  13. while (itp != (poly.end() - 1))
  14. {
  15. line(result, *itp, *(itp + 1), Scalar(255), 2);
  16. ++itp;
  17. }
  18. line(result, *itp, *(poly.begin()), Scalar(255), 2);
  19. // 轮廓表示为凸多边形
  20. vector<Point> hull;
  21. convexHull(Mat(contours[3]), hull);
  22. vector<Point>::const_iterator ith = hull.begin();
  23. while (ith != (hull.end() - 1))
  24. {
  25. line(result, *ith, *(ith + 1), Scalar(255), 2);
  26. ++ith;
  27. }
  28. line(result, *ith, *(hull.begin()), Scalar(255), 2);

程序中我们依次画了矩形、圆、多边形和凸多边形。最终效果如下:

[cpp] view plaincopy
  1. #include<opencv2\opencv.hpp>
  2. #include<iostream>
  3. using namespace cv;
  4. using namespace std;
  5. #define WINDOW_1 "原图"
  6. #define WINDOW_2 "效果图"
  7. int min_area = 13;
  8. int max_area = 100;
  9. vector<vector<Point>> g_vContours;
  10. vector<Vec4i> g_vHierarchy;
  11. RNG g_rng(12345);
  12. Mat srcImage,grayImage,b_grayImage,binaryImage;
  13. Mat foreground, d_foreground, c_foreground;
  14. void on_ThreshChange(int, void*);
  15. int main()
  16. {
  17. srcImage=imread("D://vvoo//soldier.jpg",1);
  18. cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
  19. blur(grayImage, b_grayImage, Size(3, 3));
  20. threshold(b_grayImage, binaryImage, 100, 255, CV_THRESH_BINARY);
  21. Mat element_1 = getStructuringElement(MORPH_RECT, Size(3,3));
  22. Mat element_2 = getStructuringElement(MORPH_RECT, Size(5,5));
  23. erode(binaryImage, foreground, element_1);
  24. dilate(foreground, d_foreground, element_2);
  25. namedWindow(WINDOW_1, WINDOW_AUTOSIZE);
  26. /*imshow(WINDOW_1, srcImage);*/
  27. createTrackbar("area 值:", WINDOW_1, &min_area, max_area, on_ThreshChange);
  28. on_ThreshChange(0, 0);
  29. /*  imshow("二值化", binaryImage);
  30. imshow("形态学处理后前景", d_foreground);*/
  31. /*imshow("Canny", c_foreground);*/
  32. waitKey(0);
  33. return 0;
  34. }
  35. void on_ThreshChange(int, void*)
  36. {
  37. Canny(d_foreground, c_foreground, 100, 200,3);
  38. findContours(c_foreground, g_vContours, g_vHierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
  39. Mat drawing = Mat::zeros(srcImage.size(), CV_8UC3);
  40. for (int i = 0; i< g_vContours.size(); i++)
  41. {
  42. drawContours(drawing, g_vContours, i, Scalar(255,255,255), 3, 18, g_vHierarchy, 0, Point());
  43. double area = contourArea(Mat(g_vContours[i]));//计算轮廓面积
  44. if (area>min_area && area < 100)
  45. {
  46. Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值
  47. Rect rect = boundingRect(Mat(g_vContours[i]));//计算点集的最外面矩形边界
  48. rectangle(drawing, rect,color, 2);
  49. rectangle(srcImage, rect, /*Scalar(0,0,255)*/color, 2);
  50. rectangle(c_foreground, rect, color, 2);
  51. }
  52. }
  53. imshow(WINDOW_1, srcImage);
  54. imshow(WINDOW_2, drawing);
  55. imshow("Canny", c_foreground);
  56. }

不明白哪里错了,为什么在原图srcImage上画的矩形基本上不随着滑动按钮而变化呢?求解!

按理说三幅图的矩形框应该是一样的,但最后一张和前两张不一样,why?

五、参考资料

1.http://mobile.51cto.com/aengine-435442.htm

2.http://blog.csdn.net/qq_20823641/article/details/52143637

Opencv之获取边缘和画轮廓相关推荐

  1. 【笔记】opencv图像轮廓 获得平均灰度值在原图上画轮廓 观察灰度图的分解

    调整大小: image = cv2.resize(image,dst=None,fx=0.5,fy = 0.5,dsize=None) img = cv2.resize(img,dst=None,fx ...

  2. 【OpenCV】获取轮廓(连通域)的面积、周长、矩形度、圆形度、宽长比、周径比

    1.轮廓面积获取函数 输入当前轮廓点集,输出该轮廓点集的面积 area = contourArea(contours[t]);//计算轮廓面积 2.轮廓周长获取函数 输入当前轮廓点集,第二个参数:bo ...

  3. OpenCV学习笔记(Python)———— 画轮廓

    画轮廓 : 1)运用cv2.findContours()函数 import cv2# 读取数据 mupian = cv2.imread(r"图片地址,例:E:\dataset\train\i ...

  4. 在OpenCV里用drawContours画轮廓

    在OpenCV里,找到物体的轮廓是最常用的功能,为什么这样说呢?因为太多的应用要使用这个功能了,比如数物体的个数,在种子实验室里常常要使用计算种子的个数,这时就需要拍照种子的照片,然后根据照片来数出种 ...

  5. opencv进阶学习笔记12:轮廓发现和对象测量

    基础版笔记目录: python3+opencv学习笔记汇总目录(适合基础入门学习) 进阶版笔记目录链接: python+opencv进阶版学习笔记目录(适合有一定基础) 轮廓发现 1轮廓发现介绍 基础 ...

  6. 【OpenCV 4开发详解】轮廓外接多边形

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  7. opencv学习笔记20:图像轮廓

    图像轮廓 Contours:轮廓 轮廓是将没有连着一起的边缘连着一起. 边缘检测检测出边缘,边缘有些未连接在一起. 注意问题 1.对象为二值图像,首先进行阈值分割或者边缘检测. 2.查找轮廓需要更改原 ...

  8. opencv 图像 抠图 算法_opencv提取轮廓与抠图

    自然图像抠图/视频抠像技术梳理(image matting, video matting)-计算机视视觉专题1 图像抠图算法学习 - Shared Sampling for Real-Time Alp ...

  9. 【OpenCV 例程300篇】200.轮廓的基本属性

    OpenCV 例程200篇 总目录-202206更新 文章目录 [youcans 的 OpenCV 例程300篇]200.轮廓的基本属性 2.4 轮廓的基本属性 2.4.1 轮廓的宽高比(Aspect ...

  10. OpenCV(六)之图像轮廓检测

    OpenCV(六)之图像轮廓检测 Contour detection系列 Contour detection-图像金字塔 图像金字塔-高斯金字塔 图像金字塔-拉普拉斯金字塔 Contour detec ...

最新文章

  1. 方向对了?MIT新研究:GPT-3和人类大脑处理语言的方式惊人相似
  2. uboot环境变量实现分析
  3. 解决编译apache出现的问题:configure: error: APR not found . Please read the documentation
  4. HHT变换基本理论-学习笔记
  5. mysql dal_Entity Framework连接Mysql数据库并生成Model和DAL层
  6. jquery让页面滚动到底部
  7. centos7 docker安装和使用_入门教程
  8. 马斯克认怂和解,特斯拉股价大涨17%,市值回涨78亿美元
  9. 5.3.6 原子操作对非原子的操作排序
  10. 提取身份证信息的自定义函数
  11. 运营商iptv服务器,电信运营商IPTV业务发展趋势浅析
  12. bio linux 创建_[转载]biolinux包含软件
  13. 【百页AI报告】2017人工智能现状、创业图景与未来(98PPT)
  14. postman中文汉化版
  15. Windows 7 修改系统临时文件夹
  16. [PHP] 新浪企业邮箱登录功能难点梳理
  17. SQLSTATE[HY000]: General error: 1366 Incorrect string value: ‘\xF0\x9F\x98\x84‘ for column ‘content‘
  18. 微信小程序手机号绑定功能(登录后绑定)
  19. MVC中的ViewData、ViewBag和TempData
  20. phpstudy打不开localhost【已解决】

热门文章

  1. python爬虫之BeautifulSoup4基础教程
  2. C++11 关键字default和delete
  3. EsayExcel简单的读和写
  4. raft算法_MIT 6.824 分布式系统 | Lab 2A:Raft选举
  5. python int函数 向上取整_【Python小课】 print()函数
  6. Cesium:向地图中添加线的方法
  7. 计算机辅助教学研究现状,国内计算机辅助口译教学研究的现状与思考.docx
  8. php前段时间戳转字符串,JavaScript_js获取时间并实现字符串和时间戳之间的转换,废话少说,直接上代码 复制 - phpStudy...
  9. 论文笔记_S2D.06-2018-BMVC-用于实时语义分割的轻量级精细网络RefineNet
  10. ML/DL-复习笔记【二】- L1正则化和L2正则化