【问题标题】:Group closer white pixels together and draw a rectangle around them in OpenCV将较近的白色像素组合在一起,并在 OpenCV 中围绕它们绘制一个矩形
【发布时间】:2016-01-09 23:16:32
【问题描述】:

我想将这些彼此靠近的白色像素分组,并在 OpenCV 中使用 C++ 在它们周围绘制一个矩形。

原图:

预期结果:

我是 OpenCV 的新手。任何帮助将不胜感激。

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    您可以使用partition 根据给定谓词对白色像素进行分组。在这种情况下,您的谓词可以是:将给定欧几里得距离内的所有白色像素分组

    然后您可以计算每个组的边界框,保留最大的框(下面的红色),并最终放大它(下面的绿色):

    代码:

    #include <opencv2\opencv.hpp>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    using namespace cv;
    
    int main()
    {
        // Load the image 
        Mat3b img = imread("path_to_image", IMREAD_COLOR);
    
        // Convert to grayscale
        Mat1b gray;
        cvtColor(img, gray, COLOR_BGR2GRAY);
    
        // Get binary mask (remove jpeg artifacts)
        gray = gray > 200;
    
        // Get all non black points
        vector<Point> pts;
        findNonZero(gray, pts);
    
        // Define the radius tolerance
        int th_distance = 50; // radius tolerance
    
        // Apply partition 
        // All pixels within the radius tolerance distance will belong to the same class (same label)
        vector<int> labels;
    
        // With lambda function (require C++11)
        int th2 = th_distance * th_distance;
        int n_labels = partition(pts, labels, [th2](const Point& lhs, const Point& rhs) {
            return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < th2;
        });
    
        // You can save all points in the same class in a vector (one for each class), just like findContours
        vector<vector<Point>> contours(n_labels);
        for (int i = 0; i < pts.size(); ++i)
        {
            contours[labels[i]].push_back(pts[i]);
        }
    
        // Get bounding boxes
        vector<Rect> boxes;
        for (int i = 0; i < contours.size(); ++i)
        {
            Rect box = boundingRect(contours[i]);
            boxes.push_back(box);
        }
    
        // Get largest bounding box
        Rect largest_box = *max_element(boxes.begin(), boxes.end(), [](const Rect& lhs, const Rect& rhs) {
            return lhs.area() < rhs.area();
        });
    
        // Draw largest bounding box in RED
        Mat3b res = img.clone();
        rectangle(res, largest_box, Scalar(0, 0, 255));
    
        // Draw enlarged BOX in GREEN
        Rect enlarged_box = largest_box + Size(20,20);
        enlarged_box -= Point(10,10);
    
        rectangle(res, enlarged_box, Scalar(0, 255, 0));
    
    
        imshow("Result", res);
        waitKey();
    
        return 0;
    }
    

    【讨论】:

    • 非常感谢@Miki。该代码非常有用且易于理解
    • @Miki 有没有办法找出绘制的边界框的中心坐标?
    【解决方案2】:

    您可以在每一行和每一列中计算整数。然后寻找这个积分不断增长的地方。在这里你还可以添加一些移动平均线来排除噪音等。那么这个地方意味着这里比其他地方更白。现在您可以使用 openCV 中的矩形函数在该区域周围绘制矩形 (http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html#rectangle)。

    【讨论】:

    • 感谢@bercik 的建议。你能发布一个完整部分的示例代码吗?
    猜你喜欢
    • 2017-03-05
    • 2018-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    相关资源
    最近更新 更多