c++ - 使用 OpenCV 在 blob 中创建矩形

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

输入图像:

输出图像:

我在图像中有几个彩色 Blob ,我试图在每种颜色的最大 Blob 内创建矩形(或正方形 - 这似乎更容易)。我找到了 the answer to how to create a rectangle that bounds a single largest blob ,但我不确定如何找到一个完全适合 blob 的正方形。它不一定是最大的,它只需要比某个区域大,否则我就不会包括它。我还看到了一些关于多边形的工作,但没有看到关于非晶形状的工作。

最佳答案

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

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


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

然后您只需要为每种颜色创建一个蒙版,为该蒙版中的每个 Blob 找到连通分量,并计算每个 Blob 的最小矩形。

初始图像:

enter image description here

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

结果:

enter image description here

这里是代码:

#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;
}

关于c++ - 使用 OpenCV 在 blob 中创建矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34896431/

相关文章:

c++ - odeint 复杂状态类型示例无法编译

渲染时 JavaFX 图像 (PNG) 透明清晰度丢失

java - 从 PDF 中提取 TIFF 图像而不解码

c++ - OpenCV 从堆中的数组创建 Mat

OpenCV 图像比较

c++ - 在 C++ 中使用 Well44497a 生成随机数

c++ - 如何使用socket编程获取系统日期和时间

c++ - std::replace on std::string invalid operands to binary expression

c++ - 如何提取给定特定颜色的图像的一部分?

opencv - 在cv2.stereoCalibrate中选择了哪个摄像机作为原点?