Opencv 轮廓等距外扩

文章介绍了三种在OpenCV中处理不规则轮廓的方法,包括自定义的多边形外扩函数和使用图像膨胀操作。着重比较了方法1(基于轮廓点画圆)和方法3(先轮廓提取再画圆)在处理不规则图形时的效果差异。
摘要由CSDN通过智能技术生成

不规则轮廓等距外扩方法:

1、多边形外扩

2、使用图像膨胀

3、基于轮廓上的所有点进行画圆

方法1:

void expand_polygon(vector<cv::Point> pList,vector<cv::Point> &out)
{
    int count = pList.size();
    vector<cv::Point> dpList,ndpList;

    for(int i = 0; i < count; i++)
    {
        int next = (i == (count - 1)) ? 0:(i + 1);
        dpList.push_back(pList.at(next) - pList.at(i));
        float unitLen = 1.0f/sqrt(dpList.at(i).dot(dpList.at(i)));
        ndpList.push_back(dpList.at(i) * unitLen);
        //cout<<"i="<<i<<",pList:"<<pList.at(next)<<","<<pList.at(i)<<",dpList:"<<dpList.at(i)<<",ndpList:"<<ndpList.at(i)<<endl;
    }
    float SAFELINE = 20.0f;//负数为内缩, 正数为外扩。 需要注意算法本身并没有检测内缩多少后折线会自相交,那不是本代码的示范意图
    for(int i = 0; i < count; i++)
    {
        int startIndex = (i==0 ? (count-1):(i-1));
        int endIndex = i;
        float sinTheta = ndpList.at(startIndex).cross(ndpList.at(endIndex));
        cv::Point2f orientVector = ndpList.at(endIndex) - ndpList.at(startIndex);//i.e. PV2-V1P=PV2+PV1
        cv::Point2f temp_out;
        temp_out.x = pList.at(i).x + SAFELINE/sinTheta * orientVector.x;
        temp_out.y = pList.at(i).y + SAFELINE/sinTheta * orientVector.y;
        out.push_back(temp_out);
    }
}

void MainWindow::on_pushButton_103_clicked()
{
    cv::Mat img = cv::imread("TestROI.bmp");
    cv::Mat gray,thresh,imgC;
    imgC = img.clone();

    cv::cvtColor(img,gray,cv::COLOR_BGR2GRAY);
    cv::threshold(gray,thresh,20,255,cv::THRESH_BINARY);

    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> hierarchy;
    cv::findContours(thresh, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    qDebug() << "轮廓数量:" << contours.size();


    for(uint k = 0 ; k < contours.size(); k++)
    {
        vector<cv::Point> points_expand;
        expand_polygon(contours[k],points_expand);
        for(int i=0; i<points_expand.size();i++)
        {
            int next = (i==(points_expand.size()-1) ? 0: (i+1));
            line(imgC,points_expand[i],points_expand[next],cv::Scalar(0,255,0),1);
        }
    }
    cv::imshow("waikuo1",imgC);
 }

方法2:

void MainWindow::on_pushButton_104_clicked()
{
    cv::Mat img = cv::imread("TestROI.bmp");
    cv::Mat gray,thresh,imgC;
    imgC = img.clone();

    cv::cvtColor(img,gray,cv::COLOR_BGR2GRAY);
    cv::threshold(gray,thresh,20,255,cv::THRESH_BINARY);
    cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(21, 21)); //第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
    //膨胀操作
    dilate(thresh, thresh, element);

    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> hierarchy;
    cv::findContours(thresh, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    qDebug() << "轮廓数量:" << contours.size();

    for(uint k = 0 ; k < contours.size(); k++)
    {
        cv::drawContours(imgC,contours,k,cv::Scalar(0,255,0),1,8);
    }
    cv::imshow("waikuo2",imgC);
}

方法3:

void MainWindow::on_pushButton_105_clicked()
{
    cv::Mat img = cv::imread("TestROI.bmp");
    cv::Mat gray,thresh,imgC;
    imgC = img.clone();

    cv::cvtColor(img,gray,cv::COLOR_BGR2GRAY);
    cv::threshold(gray,thresh,20,255,cv::THRESH_BINARY);

    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> hierarchy;
    cv::findContours(thresh, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
    qDebug() << "轮廓数量:" << contours.size();
    for(uint k = 0 ; k < contours.size(); k++)
    {
        for(uint l = 0; l < contours[k].size(); l++)
        {
            cv::circle(img,contours[k][l],10,cv::Scalar(255,0,0));
        }
    }
    contours.clear();
    hierarchy.clear();
    cv::Mat gray1,thresh1;
    cv::cvtColor(img,gray1,cv::COLOR_BGR2GRAY);
    cv::threshold(gray1,thresh1,20,255,cv::THRESH_BINARY);
    cv::findContours(thresh1, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
    for(uint k = 0 ; k < contours.size(); k++)
    {
        cv::drawContours(imgC,contours,k,cv::Scalar(0,255,0),1,8);
    }
    cv::imshow("waikuo3",imgC);
}

使用画圆方法外扩时需要获取轮廓边缘所有点位信息,所以findcontours函数需要使用 cv::CHAIN_APPROX_NONE

效果图 - 方法1:


图像拐角处效果不佳,适用于多边形,不太适合这种不规则图形的外扩

效果图 - 方法2:

在这里插入图片描述
图像拐角处效果不佳,适用于多边形,不太适合这种不规则图形的外扩

效果图 - 方法3

在这里插入图片描述
图像效果满足实际需求,效果较好。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值