• 11---OpenCV:图像进阶操作之①轮廓②凸包操作


    一、图像轮廓操作

    图像轮廓

    图像轮廓是一系列相连的点组成的曲线,代表了物体的基本外形,相对于边缘,轮廓是连续的,边缘并不全部连续。一般地,获取图像轮廓要经过下面几个步骤

    • 读取图片

    • 灰度处理-->imread("testMin.jpg", IMREAD_GRAYSCALE)

    • 二值化处理,查找轮廓

      • 二值化---> threshold(result["Gray"], result["Binary"], 125, 255, THRESH_BINARY);

    • 显示轮廓边缘

    查找轮廓

    1. void findContours( InputArray image, OutputArrayOfArrays contours,int mode, int method, Point offset = Point());
    2. /*******************************************************************
    3. * image: 单通道灰度图
    4. * contours:   检测到的轮廓,存储的是点坐标
    5. * mode: 轮廓检索模式
    6. * method: 轮廓逼近方法
    7. * offset:   按照偏移量移动所有的轮廓 一般不使用
    8. *********************************************************************/
    1. void findContours( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode,int method, Point offset = Point());
    2. /*******************************************************************
    3. * image: 输入单通道灰度图
    4. * contours:   检测到的轮廓,存储的是点坐标
    5. * hierarchy: 轮廓的拓扑信息
    6. * contours[i]包含4个hierarchy[i]元素,
    7. * hierarchy[i][0]:后一个轮廓
    8. * hierarchy[i][1]:前一个轮廓
    9. * hierarchy[i][2]:父轮廓
    10. * hierarchy[i][3]:内嵌轮廓
    11. * mode: 轮廓检索模式
    12. * method: 轮廓逼近方法
    13. * offset:   按照偏移量移动所有的轮廓 一般不使用
    14. *********************************************************************/
    1. //mode取值:
    2. enum RetrievalModes {
    3.    RETR_EXTERNAL  = 0,//只检索最外面的轮廓
    4.    RETR_LIST      = 1,//检索所有轮廓,并保存到一条链表中
    5.    RETR_CCOMP     = 2,//检索所有轮廓,组织为顶层(外部边界)和次层(内部边界)
    6.    RETR_TREE      = 3,//检索所有的轮廓,并重构嵌套轮廓的整个层次
    7.    RETR_FLOODFILL = 4 //支持CV_32SC1图像,不等于仅支持CV_8UC1图像
    8. };
    9. //method取值:
    10. enum ContourApproximationModes {
    11.    CHAIN_APPROX_NONE      = 1, //保存所有轮廓点
    12.    CHAIN_APPROX_SIMPLE    = 2, //压缩水垂直对角线,只保留线的两端点
    13.    CHAIN_APPROX_TC89_L1   = 3, //使用teh-Chinl chain 近似算法
    14.    CHAIN_APPROX_TC89_KCOS = 4 //使用teh-Chinl chain 近似算法
    15. };

    绘制轮廓

    1. void drawContours( InputOutputArray image, InputArrayOfArrays contours,int contourIdx, const Scalar& color,
    2. int thickness = 1, int lineType = LINE_8,InputArray hierarchy = noArray(),int maxLevel = INT_MAX, Point offset = Point());
    3. /*******************************************************************
    4. * image: 输出单通道灰度图
    5. * contours: 所有的输入轮廓
    6. * contourIdx: 指定轮廓列表的索引 ID(将被绘制)
    7. * 若为负数,则所有的轮廓将会被绘制
    8. * color: 绘制轮廓的颜色
    9. * thickness: 绘制轮廓线条的宽度
    10. * lineType: 线条的类型,8连通型或4连通型
    11. * hierarchy: 层次结构信息
    12. * maxLevel: 绘制轮廓的最高级别
    13. * 0:绘制指定轮廓
    14. * 1:绘制该轮廓和所有嵌套轮廓
    15. * 2:绘制该轮廓、嵌套轮廓子轮廓等
    16. * offset: 按照偏移量移动所有的轮廓
    17. *********************************************************************/

    综合代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace cv;
    7. using namespace std;
    8. class OutLine
    9. {
    10. public:
    11. OutLine() :img(imread("testMin.jpg", IMREAD_GRAYSCALE))
    12. {
    13. result["Gray"] = img;
    14. }
    15. void Show()
    16. {
    17. for (auto& v : result)
    18. {
    19. imshow(v.first, v.second);
    20. }
    21. waitKey(0);
    22. }
    23. //查找轮廓
    24. void FindOutLine()
    25. {
    26. threshold(result["Gray"], result["Binary"], 125, 255, THRESH_BINARY);
    27. findContours(result["Binary"], contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
    28. }
    29. //着色
    30. void DrawOutLine()
    31. {
    32. result["OutLine"] = Mat::zeros(result["Binary"].size(), CV_8UC3);
    33. for (int i = 0; i < contours.size(); i++)
    34. {
    35. Scalar color = Scalar(0, 255, 0);
    36. //drawContours(result["OutLine"], contours, i, color, 1, 8, hierarchy);
    37. drawContours(result["OutLine"], contours, i, color);
    38. }
    39. }
    40. private:
    41. Mat img;
    42. map result;
    43. vector> contours;
    44. vector hierarchy;
    45. };
    46. int main()
    47. {
    48. OutLine* p = new OutLine;
    49. p->FindOutLine();
    50. p->DrawOutLine();
    51. p->Show();
    52. return 0;
    53. }

    二、图像凸包操作

    凸包

            凸包指如果在集合A内连接任意两个点的直线段都在A的内部,则称集合A是凸形的。

            简单点理解,就是一个多边型,没有凹的地方。凸包(凸壳)能包含点集中所有的点,凸包检测常应用在物体识别、手势识别及边界检测等领域。一个轮廓可以有无数个包围它的外壳,而其中表面积最小的一个外壳,就是凸包。

    凸包绘制步骤

    • 图像灰度处理

    • 灰度图二值化处理

    • 轮廓检测得到候选点

    • 凸包API调用,筛选可用点

    • 绘制显示

    API介绍

    1. void convexHull( InputArray points, OutputArray hull,bool clockwise = false, bool returnPoints = true );
    2. /*******************************************************************
    3. * points: 轮廓点集
    4. * hull:   凸包点集输出
    5. * clockwise: 凸包方向的标志位
    6. * true:顺时针方向
    7. *   false:逆时针
    8. * returnPoints: 返回点个数
    9. *********************************************************************/

    综合代码

    注意:

            ①在做二值化处理之前,建议先用blur函数进行模糊处理(为了降噪)-->再去二值化处理效果会更好

            ②在画关键点和凸包处是一个重点。

     hull[(j+1)%count]随着j不断循环,最后一个点以及j+1取余之后会回到第一个点,实现闭环,完成凸包的绘制。

            ③ 绘制凸包前,需要得到外部轮廓的关键点,需要使用findContour函数去找并进行相应的存储

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. using namespace cv;
    8. class ConvexHull
    9. {
    10. public:
    11. ConvexHull() :img(imread("hand.jpg"))
    12. {
    13. result["img"] = img;
    14. }
    15. void TestConvexHull()
    16. {
    17. //图像灰度处理
    18. cvtColor(result["img"], result["Gray"], COLOR_BGR2GRAY);
    19. //灰度图二值化处理
    20. blur(result["Gray"], result["Gray"], Size(3, 3));
    21. threshold(result["Gray"], result["Binary"], 240, 255, THRESH_BINARY_INV);
    22. //轮廓检测得到候选点
    23. vector> contours;
    24. vector hierarchy;
    25. findContours(result["Binary"], contours, hierarchy, RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
    26. //凸包API调用,筛选可用点
    27. //绘制显示
    28. for (int i = 0; i < contours.size(); i++)
    29. {
    30. vector hull;
    31. convexHull(contours[i], hull);
    32. //bool isOk = isContourConvex(contours[i]); //判断当前点是否为有效点
    33. int count = hull.size();
    34. for (int j = 0; j < count; j++)
    35. {
    36. circle(img, hull[j], 5, Scalar(0, 0, 255));
    37. line(img, hull[j % count], hull[(j + 1) % count], Scalar(255, 0, 0), 2);
    38. }
    39. }
    40. }
    41. void Show()
    42. {
    43. for (auto& v : result)
    44. {
    45. imshow(v.first, v.second);
    46. }
    47. waitKey(0);
    48. }
    49. private:
    50. Mat img;
    51. map result;
    52. };
    53. int main()
    54. {
    55. ConvexHull* p = new ConvexHull;
    56. p->TestConvexHull();
    57. p->Show();
    58. return 0;
    59. }

  • 相关阅读:
    图像处理之LSB替换隐写算法的实现
    c语言用json解析库(jansson)检测字符串是否是json格式的数据
    rk3568 buildroot
    文未有福利 | 接口自动化你不懂?听HttpRunner的作者怎么说
    期货开户保证金能极端行情保安全
    Java调用FFmpeg
    android12 super.image 解压缩及其挂载到ubuntu
    详解光耦合器是什么
    使用PowerShell脚本来一键开启、关闭FTP服务
    CodeChecker的安装及基本使用
  • 原文地址:https://blog.csdn.net/zjjaibc/article/details/126626511