Search code examples
opencvcomputer-visionroi

Number of non-zero pixels in a cv::RotatedRect


as the title says i'm trying to find the number of non-zero pixels in a certain area of a cv::Mat, namely within a RotatedRect.

For a regular Rect one could simply use countNonZeroPixels on a ROI. However ROIs can only be regular (non rotated) rectangles.

Another idea was to draw the rotated rectangle and use that as a mask. However openCV neither supports the drawing of rotated rectangles nor does countNonZeroPixels accept a mask.

Does anyone have a solution for how to elegantly solve this ?

Thank you !


Solution

  • Ok, so here's my first take at it.

    The idea is to rotate the image reverse to the rectangle's rotation and than apply a roi on the straightened rectangle.

    • This will break if the rotated rectangle is not completely within the image
    • You can probably speed this up by applying another roi before rotation to avoid having to rotate the whole image...

      #include <highgui.h>
      #include <cv.h>
      
      
      // From http://stackoverflow.com/questions/2289690/opencv-how-to-rotate-iplimage
      cv::Mat rotateImage(const cv::Mat& source, cv::Point2f center, double angle)
      {
        cv::Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
        cv::Mat dst;
        cv::warpAffine(source, dst, rot_mat, source.size());
        return dst;
      }
      
      int main()
      {
        cv::namedWindow("test1");
      
        // Our rotated rect
        int x = 300;
        int y = 350;
        int w = 200;
        int h = 50;
        float angle = 47;
        cv::RotatedRect rect = cv::RotatedRect(cv::Point2f(x,y), cv::Size2f(w,h), angle);
      
        // An empty image
        cv::Mat img = cv::Mat(cv::Size(640, 480), CV_8UC3);
      
        // Draw rotated rect as an ellipse to get some visual feedback
        cv::ellipse(img, rect, cv::Scalar(255,0,0), -1);
      
        // Rotate the image by rect.angle * -1
        cv::Mat rotimg = rotateImage(img, rect.center, -1 * rect.angle);
      
        // Set roi to the now unrotated rectangle
        cv::Rect roi;
        roi.x = rect.center.x - (rect.size.width / 2);
        roi.y = rect.center.y - (rect.size.height / 2);
        roi.width = rect.size.width;
        roi.height = rect.size.height;
      
        cv::imshow("test1", rotimg(roi));
        cv::waitKey(0);
      }