OpenCV-图像处理(29、凸包-Convex Hull)

概念介绍

什么是凸包(Convex Hull),在一个多变形边缘或者内部任意两个点的连线都包含在多边形边界或者内部。
正式定义:包含点集合S中所有点的最小凸多边形称为凸包。凸包可以想象为一条刚好包着所有点的橡皮圈,用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。

在这里插入图片描述

在这里插入图片描述

常见的检测算法

  • Graham扫描法(也可以参考博客:https://blog.csdn.net/keith_bb/article/details/70194073)
    • 首先选择Y方向最低的点作为起始点p0
    • 从p0开始极坐标扫描,依次添加p1….pn(排序顺序是根据极坐标的角度大小,逆时针方向)
    • 对每个点pi来说,如果添加pi点到凸包中导致一个左转向(逆时针方法)则添加该点到凸包, 反之如果导致一个右转向(顺时针方向)删除该点从凸包中

在这里插入图片描述

  • Jarvis步进法
    其算法流程如下:
    1.照横坐标最小的点(如有一样则取相同点纵坐标更小的点)
    2.从这点开始卷包裹,照最靠近外侧的点(通过叉积比较)
    3.遍历所有点,直到重新找到起点,退出。

API说明cv::convexHull

convexHull(
InputArray points,// 输入候选点,来自findContours
OutputArray hull,// 凸包
bool clockwise,// default true。操作方向,当标识符为真时,输出凸包为顺时针方向,否则为逆时针方向。
bool returnPoints)//操作标识符,默认值为true,此时返回各凸包的各个点,否则返回凸包各点的指数,当输出数组时std::vector时,此标识被忽略。
)

步骤

  1. 首先把图像从RGB转为灰度
  2. 然后再转为二值图像
  3. 在通过发现轮廓得到候选点
  4. 凸包API调用
  5. 绘制显示。

程序代码

 #include <iostream>
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;

Mat srcImage, grayImage;
int thresh = 100;
const int threshMaxValue = 255;
RNG rng(12345);

//定义回调函数
void thresh_callback(int, void*);

int main()
{
    srcImage = imread("E:/Experiment/OpenCV/Pictures/HandTest.jpg");

    //判断图像是否加载成功
    if (srcImage.empty()){
        cout << "图像加载失败" << endl;
        return -1;
    }

    //图像灰度图转化并平滑滤波
    cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
    blur(grayImage, grayImage, Size(3, 3));

    namedWindow("原图像", WINDOW_AUTOSIZE);
    imshow("原图像", grayImage);

    //创建轨迹条
    createTrackbar("Threshold:", "原图像", &thresh, threshMaxValue, thresh_callback);
    thresh_callback(thresh, 0);
    waitKey(0);

    return 0;
}

void thresh_callback(int, void*)
{
    Mat src_copy = srcImage.clone();
    Mat threshold_output;
    vector<vector<Point>>contours;
    vector<Vec4i>hierarchy;

    //使用Threshold检测图像边缘,对图像进行二值化
    threshold(grayImage, threshold_output, thresh, 255, THRESH_BINARY);

    //寻找图像轮廓
    findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    //寻找图像凸包
    vector<vector<Point>>hull(contours.size());
    for (int i = 0; i < contours.size(); i++){
        convexHull(Mat(contours[i]), hull[i], false);
    }

    //绘制轮廓和凸包
    Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
    for (int i = 0; i < contours.size(); i++){
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        drawContours(drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point());
        drawContours(drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point());
    }

    namedWindow("凸包", WINDOW_AUTOSIZE);
    imshow("凸包", drawing);
}

运行结果

在这里插入图片描述

参考博客

  1. https://blog.csdn.net/keith_bb/article/details/70194073
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值