Search code examples
c++opencvbounding-box

Draw rotated bounding box on image without fixed angle


Im new to programming and opencv and i try to detect a hdd using color segmentation. My code so far loads an image, creates 3 masks with different colors and draws an upright bounding box around the non zero points:

int main( int argc, char** argv )
{

//Load the image
Mat img = imread(argv[1], 1);
if (img.empty()){
cout << "No image found..." << endl;
return -1;
}

//Extracting colors - BGR
Mat silver, white, black;

//Silver
inRange(img, Scalar(180, 180, 180), Scalar(200, 200, 200), silver);

//White
inRange(img, Scalar(240, 240, 240), Scalar(255, 255, 255), white);

//Black
inRange(img, Scalar(0, 0, 0), Scalar(30, 30, 30), black);

// logical OR mask
Mat1b mask = silver | white | black;

// Find non zero pixels
vector<Point> pts;

findNonZero(mask, pts);

cout << "Non-Zero Locations = " << pts << endl << endl; // get non zero coordinates

// Compute bounding box

Rect box = boundingRect(pts);

// Show bounding box
rectangle(img, box, Scalar(0, 0, 255), 3);
namedWindow("box", CV_WINDOW_NORMAL);
imshow("box", img); 
imshow("mask", mask);

waitKey(0);
destroyAllWindows;

return 0;}

Now I want to draw the smallest bounding box, so I tried to use

cv::RotatedRect box2 = cv::minAreaRect(pts);

instead. But it doesnt compile when I try to visualize that by replacing

Rect box = boundingRect(pts); 

with

RotatedRect box2 = minAreaRect(pts);

Error Output:

error: no matching function for call to ‘rectangle(cv::Mat&, cv::RotatedRect&, cv::Scalar, int)’
 rectangle(img, box2, Scalar(0, 0, 255), 3);

Solution

  • As per the cv::Rectangle Opencv Docs, the function has only 2 variants:

    void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
    
    void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness=1, int lineType=8, int shift=0 )
    

    So it is clear that it only accepts either cv::Rect or cv::Point. Hence there is no provision to directly input the cv::RotatedRect, due to which you are getting the above mentioned error.

    To fix this issue, you can extract the 4 points of cv::RotatedRect using:

    cv::Point2f points[4];
    rotatedRect.points(points);
    

    And then use cv::line() to draw the edges in pairs as:

    cv::RotatedRect rotatedRect = cv::RotatedRect(cv::Point(70, 70), cv::Size(90, 90), 30);
    
    cv::Mat canvas = cv::Mat(200, 200, CV_8UC3, cv::Scalar(255, 255, 255));
    
    cv::Point2f points[4];
    rotatedRect.points(points);
    
    cv::line(canvas, points[0], points[1], cv::Scalar(0, 255, 0), 3);
    cv::line(canvas, points[1], points[2], cv::Scalar(0, 255, 0), 3);
    cv::line(canvas, points[2], points[3], cv::Scalar(0, 255, 0), 3);
    cv::line(canvas, points[3], points[0], cv::Scalar(0, 255, 0), 3);
    

    enter image description here