OpenCV,如何使用点阵列来平滑和采样轮廓?

Que*_*ann 13 c++ opencv contour sampling

我有一个问题是在OpenCV(C++ API)中平滑和采样轮廓.假设我已经从中检索了一系列点数cv::findContours(例如应用于此图像:

在此输入图像描述

最终,我想要

  1. 使用不同的内核平滑一系列点.
  2. 使用不同类型的插值调整序列的大小.

平滑后,我希望得到如下结果:

在此输入图像描述

我还考虑在a中绘制轮廓cv::Mat,过滤Mat(使用模糊或形态学操作)并重新找到轮廓,但速度慢且次优.因此,理想情况下,我可以专门使用点序列来完成工作.

我在上面阅读了几篇帖子并天真地认为我可以简单地将一个std::vector(of cv::Point)转换为a cv::Mat然后像模糊/调整大小的OpenCV函数将为我做的工作......但他们没有.

这是我尝试过的:

int main( int argc, char** argv ){

    cv::Mat conv,ori;
    ori=cv::imread(argv[1]);
    ori.copyTo(conv);
    cv::cvtColor(ori,ori,CV_BGR2GRAY);

    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Vec4i > hierarchy;

    cv::findContours(ori, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);

    for(int k=0;k<100;k += 2){
        cv::Mat smoothCont;

        smoothCont = cv::Mat(contours[0]);
        std::cout<<smoothCont.rows<<"\t"<<smoothCont.cols<<std::endl;
        /* Try smoothing: no modification of the array*/
//        cv::GaussianBlur(smoothCont, smoothCont, cv::Size(k+1,1),k);
        /* Try sampling: "Assertion failed (func != 0) in resize"*/
//        cv::resize(smoothCont,smoothCont,cv::Size(0,0),1,1);
        std::vector<std::vector<cv::Point> > v(1);
        smoothCont.copyTo(v[0]);
        cv::drawContours(conv,v,0,cv::Scalar(255,0,0),2,CV_AA);
        std::cout<<k<<std::endl;
        cv::imshow("conv", conv);
        cv::waitKey();
    }
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释如何做到这一点?

另外,由于我可能使用更小的轮廓,我想知道这种方法如何处理边界效应(例如,当平滑时,由于轮廓是圆形的,序列的最后一个元素必须用于计算新值第一要素......)

非常感谢您的建议,

编辑:

我也尝试了,cv::approxPolyDP()但正如你所看到的,它往往会保留极值点(我想删除):

小量= 0

在此输入图像描述

小量= 6

在此输入图像描述

小量= 12

在此输入图像描述

小量= 24

在此输入图像描述

编辑2: 正如Ben所建议的,似乎cv::GaussianBlur()不支持但是cv::blur().它看起来非常接近我的期望.以下是我使用它的结果:

K = 13

在此输入图像描述

K = 53

在此输入图像描述

K = 103

在此输入图像描述

为了解决边界效应,我做了:

    cv::copyMakeBorder(smoothCont,smoothCont, (k-1)/2,(k-1)/2 ,0, 0, cv::BORDER_WRAP);
    cv::blur(smoothCont, result, cv::Size(1,k),cv::Point(-1,-1));
    result.rowRange(cv::Range((k-1)/2,1+result.rows-(k-1)/2)).copyTo(v[0]);
Run Code Online (Sandbox Code Playgroud)

我仍在寻找内插/采样轮廓的解决方案.

Ben*_*Ben 2

您的高斯模糊不起作用,因为您在列方向上模糊,但只有一列。GaussianBlur()当尝试将向量复制回 a 时,使用会导致 OpenCV 中出现“功能未实现”错误(这可能就是代码中cv::Mat出现这种奇怪情况的原因),但使用 一切正常,无需使用。例如尝试 Size(0,41)。用于边界问题似乎也不起作用,但这找到解决方法的人的另一个线程。resize()cv::blur()resize()cv::BORDER_WRAP

哦...还有一件事:你说你的轮廓可能要小得多。以这种方式平滑你的轮廓会缩小它。极端情况是k = size_of_contour,它会产生一个点。所以不要选择太大的 k 。