如何合并图像中的斑块/轮廓

6

我使用findContours进行斑点检测。现在我想要合并靠近或相似的斑点。

以下是一些示例图像:

enter image description here enter image description here enter image description here

使用普通的Opencv是否可以实现?


最好加上一张图片。上传到imageshack.us并在此处提供链接。同时请说明您所说的“相似”是指形状相似还是面积相似等。 - Abid Rahman K
好的,我想合并相邻的相似形状。以下是三个例子(标记为黄色)。谢谢帮忙!图片1 图片2 图片3 - rouge
这些二进制图像都经过形态学开闭运算处理。 - rouge
所以,基本上你是在找到每个斑点之间的距离,如果距离d小于25,则将它们合并? - Mzk
但是还有一个问题,如何处理新合并的blob?因为如果一个合并了两个,可能还需要合并第三个... - rouge
我能想到的是您可能希望膨胀合并的斑块,然后再次执行CCL。 - Mzk
2个回答

3

您提供的输入图像非常容易处理:

enter image description here enter image description here enter image description here

第一步是将黄色斑点与其他部分分离,简单的颜色分割技术可以完成这项任务。您可以看一下这篇文章:颜色分割和物体检测或者在OpenCV中跟踪彩色对象来了解如何实现。

enter image description here enter image description here enter image description here

然后,是时候合并斑点了。其中一个特别有用的技术是边界框将所有斑点放入一个矩形框中。请注意下面的图像,绿色矩形框围绕着斑点:

enter image description here enter image description here enter image description here

之后,您只需要用您选择的颜色填充矩形框,即可连接所有斑点。我把这个留给您作为作业。

这是我能想到的最快、最简单的方法。以下代码演示了如何实现我刚才描述的内容:

#include <cv.h>
#include <highgui.h>

#include <iostream>
#include <vector>

int main(int argc, char* argv[])
{
    cv::Mat img = cv::imread(argv[1]);
    if (!img.data)
    {
        std::cout "!!! Failed to open file: " << argv[1] << std::endl;
        return 0;
    }

    // Convert RGB Mat into HSV color space
    cv::Mat hsv;
    cv::cvtColor(img, hsv, CV_BGR2HSV);

    // Split HSV Mat into HSV components
    std::vector<cv::Mat> v;
    cv::split(hsv,v);

    // Erase pixels with low saturation
    int min_sat = 70;
    cv::threshold(v[1], v[1], min_sat, 255, cv::THRESH_BINARY);

    /* Work with the saturated image from now on */

// Erode could provide some enhancement, but I'm not sure.
//  cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
//  cv::erode(v[1], v[1], element);

    // Store the set of points in the image before assembling the bounding box
    std::vector<cv::Point> points;
    cv::Mat_<uchar>::iterator it = v[1].begin<uchar>();
    cv::Mat_<uchar>::iterator end = v[1].end<uchar>();
    for (; it != end; ++it)
    {
        if (*it) points.push_back(it.pos());
    }

    // Compute minimal bounding box
    cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));

    // Display bounding box on the original image
    cv::Point2f vertices[4];
    box.points(vertices);
    for (int i = 0; i < 4; ++i)
    {
            cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA);
    }

    cv::imshow("box", img);
    //cv::imwrite(argv[2], img);

    cvWaitKey(0);

    return 0;
}

谢谢你的回答...但是你有点误解我的意思了。黄色斑点实际上并不是真正的黄色。我只是为了向你展示我想要合并的斑点而将它们染成了黄色。因此,我不能使用颜色分割来隔离其他斑点。而且,像区域这样的信息也行不通,因为可能会有一些更大的斑点,我不想将它们合并... - rouge
算了吧!= \ 以后再想其他的事情。 - karlphillip
不,我只对那些可能是交通标志的斑点感兴趣,因为它们的大小/比率/面积。 - rouge
1
你必须在问题中提供尽可能多的细节,否则我们将会盲目猜测。这是一个复杂的问题!如果你不分享你已经尝试过什么,你可能得不到任何答案。 - karlphillip
让我这样说吧:从你给我们的图像中,你怎么知道哪个斑块是交通标志?在我看来,最大的斑块听起来很合理。我错了吗? - karlphillip
如果我让你感到困惑,我很抱歉。问题可能是可能有一个更大的噪点 Blob(当它是一个蓝色标志时,可能是天空的一部分),或者一张图像中可能也有更多的交通标志。我能做的就是隔离非常小和最大的那些 Blob。但是我的问题是:有时交通标志会分成两个部分,现在我想将它们合并成一个... - rouge

2
我想我做到了,感谢您的程序细节,我找到了这个解决方案:(欢迎评论)
vector<vector<Point> > contours;
    vector<vector<Point> > tmp_contours;
    findContours(detectedImg, tmp_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    vector<vector<Point> >::iterator it1;
    it1 = tmp_contours.begin();

    Mat test;
    test = Mat(FImage.size(), CV_32FC3);

    while (it1 != tmp_contours.end()) {
        vector<Point> approx1;
        approxPolyDP(Mat(*it1), approx1, 3, true);
        Rect box1 = boundingRect(approx1);
        float area1 = contourArea(approx1);



        if ((area1 > 50) && (area1 < 13000) && (box1.width < 100) && (box1.height < 120)) {

            vector<vector<Point> >::iterator it2;
            it2 = tmp_contours.begin();

            while (it2 != tmp_contours.end()) {
                vector<Point> approx2;
                approxPolyDP(Mat(*it2), approx2, 3, true);

                Moments m1 = moments(Mat(approx1), false);
                Moments m2 = moments(Mat(approx2), false);
                float x1 = m1.m10 / m1.m00;
                float y1 = m1.m01 / m1.m00;
                float x2 = m2.m10 / m2.m00;
                float y2 = m2.m01 / m2.m00;

                vector<Point> dist;
                dist.push_back(Point(x1, y1));
                dist.push_back(Point(x2, y2));
                float d = arcLength(dist, false);

                Rect box2 = boundingRect(approx2);
                if (box1 != box2) {

                    if (d < 25) {
                        //Method to merge the vectors
                        approx1 = mergePoints(approx1, approx2);
                    }

                }
                ++it2;

            }
            Rect b = boundingRect(approx1);
            rectangle(test, b, CV_RGB(125, 255, 0), 2);
            contours.push_back(approx1);
        }
        ++it1;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接