【问题标题】:Creating rectangle within a blob using OpenCV使用 OpenCV 在 blob 中创建矩形
【发布时间】:2016-04-26 02:03:26
【问题描述】:

输入图像:

输出图像:

我在图像中有几个彩色斑点,我正在尝试在每种颜色的最大斑点内创建矩形(或正方形——这似乎更容易)。我找到了the answer to how to create a rectangle that bounds a single largest blob,但不确定如何找到一个简单地适合一个blob 的正方形。它不必是最大的,它必须大于某个区域,否则我不会包括它。我还看到了一些关于多边形的工作,但没有针对无定形形状。

【问题讨论】:

  • 如果您提供未压缩的图像,我会将您的图像上的结果也发布到我的答案中。

标签: c++ image opencv image-processing opencv3.0


【解决方案1】:

您可以使用this code 来定位内接任意形状的最大正方形或矩形。虽然它是 MATLAB 而不是 C++/OpenCV,但您可以轻松更改其源代码以满足您的需求。

要定位凸多边形内内接的最大矩形,请查看here(附代码)。

【讨论】:

    【解决方案2】:

    对于单个 blob,问题可以表述为:find the largest rectangle containing only zeros in a matrix

    要在 blob 中找到最大的面向轴的矩形,可以参考 my other answer 中的函数 findMinRect。该代码是来自here 的 Python 原始代码的 C++ 移植。


    那么第二个问题是找到所有颜色相同的斑点。这有点棘手,因为您的图像是 jpeg,并且压缩会在边界附近创建很多人造颜色。所以我创建了一个 png 图像(如下所示),只是为了表明该算法有效。您可以提供没有压缩伪影的图像。

    然后你只需要为每种颜色创建一个遮罩,找到这个遮罩中每个斑点的连通分量,并计算每个斑点的最小矩形。

    初始图片:

    在这里,我显示了为每个 blob 找到的矩形,按颜色划分。然后,您可以只取所需的矩形,可以是每种颜色的最大矩形,也可以是每种颜色的最大 blob 的矩形。

    结果:

    代码如下:

    #include <opencv2/opencv.hpp>
    #include <algorithm>
    #include <set>
    using namespace std;
    using namespace cv;
    
    // https://stackoverflow.com/a/30418912/5008845
    Rect findMinRect(const Mat1b& src)
    {
        Mat1f W(src.rows, src.cols, float(0));
        Mat1f H(src.rows, src.cols, float(0));
    
        Rect maxRect(0, 0, 0, 0);
        float maxArea = 0.f;
    
        for (int r = 0; r < src.rows; ++r)
        {
            for (int c = 0; c < src.cols; ++c)
            {
                if (src(r, c) == 0)
                {
                    H(r, c) = 1.f + ((r>0) ? H(r - 1, c) : 0);
                    W(r, c) = 1.f + ((c>0) ? W(r, c - 1) : 0);
                }
    
                float minw = W(r, c);
                for (int h = 0; h < H(r, c); ++h)
                {
                    minw = min(minw, W(r - h, c));
                    float area = (h + 1) * minw;
                    if (area > maxArea)
                    {
                        maxArea = area;
                        maxRect = Rect(Point(c - minw + 1, r - h), Point(c + 1, r + 1));
                    }
                }
            }
        }
    
        return maxRect;
    }
    
    
    struct lessVec3b
    {
        bool operator()(const Vec3b& lhs, const Vec3b& rhs) {
            return (lhs[0] != rhs[0]) ? (lhs[0] < rhs[0]) : ((lhs[1] != rhs[1]) ? (lhs[1] < rhs[1]) : (lhs[2] < rhs[2]));
        }
    };
    
    int main()
    {
        // Load image
        Mat3b img = imread("path_to_image");
    
        // Find unique colors
        set<Vec3b, lessVec3b> s(img.begin(), img.end());
    
        // Divide planes of original image
        vector<Mat1b> planes;
        split(img, planes);
        for (auto color : s)
        {
            // Create a mask with only pixels of the given color
            Mat1b mask(img.rows, img.cols, uchar(255));
            for (int i = 0; i < 3; ++i)
            {
                mask &= (planes[i] == color[i]);
            }
    
            // Find blobs
            vector<vector<Point>> contours;
            findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    
            for (int i = 0; i < contours.size(); ++i)
            {
                // Create a mask for each single blob
                Mat1b maskSingleContour(img.rows, img.cols, uchar(0));
                drawContours(maskSingleContour, contours, i, Scalar(255), CV_FILLED);
    
                // Find minimum rect for each blob
                Rect box = findMinRect(~maskSingleContour);
    
                // Draw rect
                Scalar rectColor(color[1], color[2], color[0]);
                rectangle(img, box, rectColor, 2);
            }
        }
    
        imshow("Result", img);
        waitKey();
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多