【问题标题】:Count percentage of white pixels inside of RotatedRect OpenCV计算RotatedRect OpenCV内白色像素的百分比
【发布时间】:2018-12-03 04:50:49
【问题描述】:

如何计算 cv::RotatedRect 内白色像素的百分比?我的意思是,如何访问我的 cv::RotatedRect 中的单个像素。如果我能做到这一点,我会知道以后该怎么做。谢谢

我已经尝试过这个线程的解决方案,但我遇到了例外。 https://stackoverflow.com/a/28780359

    std::vector<cv::RotatedRect> minRect(count.size());
    for (int i = 0; i < count.size(); i++)
    {
        minRect[i] = cv::minAreaRect(cv::Mat(count[i]));
    }
    for (size_t i = 0; i < count.size(); i++){
        if (cv::contourArea(count[i]) > 200) {
            cv::Point2f rect_points[4];
            minRect[i].points(rect_points);
            // Now I'd like to calculate percentage of white pixels inside of RotatedRect, and if value returned by func would be smaller than 30%,continue;
            for (int j = 0; j < 4; j++) {
                cv::line(mask, rect_points[j], rect_points[(j + 1) % 4], (0, 255, 0), 1, 8);
            }
        }

    }

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    你可以:

    1. 处理cv::boundingRect定义的子图像
    2. 使用cv::fillConvexPoly创建旋转矩形内所有点为白色的蒙版
    3. 与原始图像逻辑与
    4. cv::countNonZero计算白色像素的数量

    John Henkel 提出的方法有效,但在我的(非常快的)测试中慢了 10 到 40 倍。

    这两种方法的代码如下。您会发现结果存在细微差别,因为旋转矩形边框上的白色像素的处理方式不同。

    #include <opencv2\opencv.hpp>
    #include <chrono>
    
    int main()
    {
        // Create binary image with random pixels b/W
        cv::Mat1b img(5000, 5000);
        cv::randu(img, cv::Scalar(0), cv::Scalar(256));
        img = img > 127;
    
        // Define a rotated rect
        cv::Point2f center(2000, 2000);
        cv::Size2f sz(1000, 500);
        float angle = 30.f;
        cv::RotatedRect rr(center, sz, angle);
    
        // Get points
        std::vector<cv::Point2f> points(4);
        rr.points(points.data());
    
        // Work on ROI
        cv::Rect roi = rr.boundingRect();
    
        // Area 
        float area = rr.size.width * rr.size.height;
    
        //// DEBUG, Show rect
        //cv::Mat3b out;
        //cv::cvtColor(img, out, cv::COLOR_GRAY2BGR);
        //for (int i = 0; i < 4; ++i) {
        //  cv::line(out, points[i], points[(i + 1) % 4], cv::Scalar(0, 0, 255));
        //}
    
        {
            // --------------------
            // Method @Miki
            // --------------------
    
            auto tic = std::chrono::high_resolution_clock::now();
    
            cv::Mat1b sub_img = img(roi);
    
            // Create rotated rect mask
            cv::Mat1b mask(roi.size(), uchar(0));
            std::vector<cv::Point> points_in_sub_image(4);
            for (int i = 0; i < 4; ++i) {
                points_in_sub_image[i] = cv::Point(points[i]) - roi.tl();
            }
            cv::fillConvexPoly(mask, points_in_sub_image, cv::Scalar(255));
    
            // AND sub image with mask
            cv::Mat1b inside_roi = sub_img & mask;
    
            //// DEBUG, Draw green points
            //for (int r = 0; r < sub_img.rows; ++r) {
            //  for (int c = 0; c < sub_img.cols; ++c) {
            //      if (inside_roi(r, c) > 0)
            //      {
            //          out(r + roi.y, c + roi.x) = cv::Vec3b(0, 255, 0);
            //      }
            //  }
            //}
    
    
            // Get actual count
            int cnz = cv::countNonZero(inside_roi);
    
            auto toc = std::chrono::high_resolution_clock::now();
            auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(toc - tic);
    
            float percent_white_pixels = cnz / area;
            std::cout << "percent_white_pixels: " << percent_white_pixels << " in " << elapsed.count() << " us" <<  std::endl;
        }
    
        {
            // --------------------
            // Method @John Henkel
            // --------------------
    
            auto tic = std::chrono::high_resolution_clock::now();
    
            int cnz = 0;
            for (int y = roi.y; y < roi.y + roi.height; ++y) {
                for (int x = roi.x; x < roi.x + roi.width; ++x) {
                    if (
                        (img(y, x) > 0) &&
                        (cv::pointPolygonTest(points, cv::Point2f(x, y), false) >= 0.0)
                        ) 
                    {
                        // DEBUG, Draw blue points
                        //out(y, x) = cv::Vec3b(255, 0, 0);
                        ++cnz;
                    }
                }
            }
    
            auto toc = std::chrono::high_resolution_clock::now();
            auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(toc - tic);
    
            float percent_white_pixels = cnz / area;
            std::cout << "percent_white_pixels: " << percent_white_pixels << " in " << elapsed.count() << " us" <<  std::endl;
        }
    
        getchar();
        return 0;
    }
    

    【讨论】:

      【解决方案2】:

      我能想到的获取单个像素的最佳方法是首先获取旋转矩形的bounding box,然后遍历框内的每个像素以查看它们是否在带有@的旋转矩形中987654322@。我不确定是否有更有效的方法来做到这一点,但这应该会给你想要的结果。

      【讨论】:

      • 现在我计算边界矩形内的所有白色像素。完美的情况是,如果大多数这些点都在我的旋转矩形内(比如 whitepixels 除以所有像素将高于 85% )。您能否解释一下,如何将 pointPolygonTest 用于旋转矩形?如我所见,它不接受旋转矩形参数。
      猜你喜欢
      • 2015-05-22
      • 1970-01-01
      • 2014-05-22
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      • 1970-01-01
      相关资源
      最近更新 更多