【问题标题】:How to increase contours precision?如何提高轮廓精度?
【发布时间】:2011-10-04 08:16:47
【问题描述】:

我正在使用 OpenCV 开发一个项目。我需要从高清照片中精确裁剪出一些对象。 我正在使用四叉树将照片切成碎片,然后计算每个四边形的同质性以确定物体的一部分是否在四边形中。 我根据四边形的同质性应用了一些具有不同阈值的过滤器作为 Canny。 我希望这个描述是可以理解的。

该算法适用于某些类型的对象,但我对其他一些对象感到困惑。 这里有一些我的问题的例子:我想要一种方法来压平我的轮廓。 第一个屏幕截图是使用 canny 过滤器和填充后的屏幕截图。第二个是最终的掩码结果。

http://pastebin.com/91Pgrd2D


为了达到这个结果,我使用cvFindContours(),所以我有轮廓,但我找不到像我想要的那样处理它们的方法。

【问题讨论】:

  • 您的轮廓有什么问题?你想让它们更平滑吗?
  • @AdrianPopovici:有点意思,我希望他们能在不拥有所有人工制品的情况下与我的对象的曲线结合。这是原始作品:imageshack.us/photo/my-images/15/ex5gl.jpg
  • 您可以在找到轮廓之前在黑白图像上运行一些过滤器,例如高斯过滤器和阈值,这会使轮廓稍微平滑,但可能完全不适合确切的对象点。您可以对轮廓做的另一件事是使用 AproxPoly,然后应用样条曲线或其他东西。
  • @AdrianPopovici:感谢您的帮助,我使用了 ApproxPoly,但我给了我太“方形”的结果,即使之后使用样条,我丢失了太多信息。我正在寻找一种近似曲线而不是多边形的方法,例如:imageshack.us/photo/my-images/821/ex6a.jpgimageshack.us/photo/my-images/269/ex7f.jpg

标签: c++ c opencv


【解决方案1】:

也许您可以使用某种平均滤波器来近似曲线,然后使用带有小梯度的 AproxPoly 来平滑它。 这是一个类似的方法:

void AverageFilter(CvSeq * contour, int buff_length)
{
    int n = contour->total, i, j;
    if (n > buff_length)
    {
        CvPoint2D32f* pnt;
        float* sampleX = new float[buff_length];
        float* sampleY = new float[buff_length];

        pnt = (CvPoint2D32f*)cvGetSeqElem(contour, 0);
        for (i = 0; i < buff_length; i++)
        {
            if (i >= buff_length / 2)
            {
                pnt = (CvPoint2D32f*)cvGetSeqElem(contour, i + 1 - buff_length / 2 );
            }
            sampleX[i] = pnt->x;
            sampleY[i] = pnt->y;
        }

        float sumX = 0, sumY = 0;

        for (i = 1; i < n; i++)
        {
            pnt = (CvPoint2D32f*)cvGetSeqElem(contour, i);
            for (j = 0; j < buff_length; j++)
            {
                sumX += sampleX[j];
                sumY += sampleY[j];
            }
            pnt->x = sumX / buff_length;
            pnt->y = sumY / buff_length;
            for (j = 0; j < buff_length - 1; j++)
                {
                    sampleX[j] = sampleX[j+1];
                    sampleY[j] = sampleY[j+1];
                }
            if (i <= (n - buff_length / 2))
            {
                pnt = (CvPoint2D32f*)cvGetSeqElem(contour, i + buff_length / 2 + 1);
                sampleX[buff_length - 1] = pnt->x;
                sampleY[buff_length - 1] = pnt->y;
            }
            sumX = 0;
            sumY = 0;
        }
        delete[] sampleX;
        delete[] sampleY;
    }
} 

你给它轮廓和你想要平均的点缓冲区的大小。 如果您认为轮廓太粗是因为一些平均点太靠近捆绑在一起,那么这就是 Aproxpoly 的用武之地,因为它减少了点的数量。 但请选择合适的渐变,以免显得过于前卫。

srcSeq = cvApproxPoly(srcSeq,sizeof(CvContour),storage, CV_POLY_APPROX_DP, x, 1);

玩弄“x”,看看如何获​​得更好的结果。

【讨论】:

  • 谢谢,这正是我所需要的。但它为我使用的每一片制作了奇怪的东西。 buff_lenght 越高,“线条”越强。 imageshack.us/f/831/seqs.png 我正在研究它,但如果你直接知道它的来源会有所帮助:)
  • 嗯,buff_length 是要包含多少个点作为当前点的平均值,也应该是奇数(13,15,17,19...),所以对于 buff_length 13,每个点将根据前 6 个点的平均值重新计算,它本身和接下来的 6 个点。如果您使用 CV_CHAIN_APPROX_NONE 获得轮廓,您将获得更多点,因此您可以获得更好的平均值。之后,您可以使用带有小值参数的 AproxPoly,例如 1-2
  • @Adrien:感谢您的编辑,它更适用于奇数,我的错 :)
猜你喜欢
  • 2012-06-23
  • 2022-01-17
  • 2021-06-15
  • 2015-03-10
  • 2014-03-21
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
相关资源
最近更新 更多