Search code examples
c++opencvdrawrounded-corners

How to fill a rounded rectangle in openCV c++


I figure a way to draw a rounded rectangle using OpenCV C++. My function is:

void RoundedRectangle(cv::Mat& src, 
                      cv::Point topLeft, 
                      cv::Size rectSz, 
                      const cv::Scalar lineColor, 
                      const int thickness, 
                      const int lineType, 
                      const float  cornerCurvatureRatio)
{
    // corners:
    // p1 - p2
    // |     |
    // p4 - p3
    //
    cv::Point p1 = topLeft;
    cv::Point p2 = cv::Point (p1.x + rectSz.width, p1.y);
    cv::Point p3 = cv::Point (p1.x + rectSz.width, p1.y + rectSz.height);
    cv::Point p4 = cv::Point (p1.x, p1.y + rectSz.height);
    float cornerRadius = rectSz.height*cornerCurvatureRatio;

    // draw straight lines
    cv::line(src, cv::Point (p1.x + cornerRadius, p1.y), cv::Point (p2.x - cornerRadius, p2.y), lineColor, thickness, lineType);
    cv::line(src, cv::Point (p2.x, p2.y + cornerRadius), cv::Point (p3.x, p3.y - cornerRadius), lineColor, thickness, lineType);
    cv::line(src, cv::Point (p4.x + cornerRadius, p4.y), cv::Point (p3.x - cornerRadius, p3.y), lineColor, thickness, lineType);
    cv::line(src, cv::Point (p1.x, p1.y + cornerRadius), cv::Point (p4.x, p4.y - cornerRadius), lineColor, thickness, lineType);

     // draw arcs
    cv::Size rad = cv::Size(cornerRadius, cornerRadius);
    cv::ellipse(src, p1 + cv::Point(cornerRadius, cornerRadius),   rad, 180.0, 0, 90, lineColor, thickness, lineType);
    cv::ellipse(src, p2 + cv::Point(-cornerRadius, cornerRadius),  rad, 270.0, 0, 90, lineColor, thickness, lineType);
    cv::ellipse(src, p3 + cv::Point(-cornerRadius, -cornerRadius), rad, 0.0, 0, 90, lineColor, thickness, lineType);
    cv::ellipse(src, p4 + cv::Point(cornerRadius, -cornerRadius),  rad, 90.0, 0, 90, lineColor, thickness, lineType);
}

Now I want to fill the rectangle. I found some fill functions such as cv::fillPoly() and cv::fillConvexPoly however, I need a vector with points. How I can get the list of points from my construction?


Solution

  • Nuzhny was correct, floodFill() is the easiest and potentially the fastest way to fill that rounded rectangle. (Tested with CV 4.1.1)

    One line of code will do it, but here is the entire example.

    void rounded_rectangle( Mat& src, Point topLeft, Point bottomRight, const Scalar lineColor, int thickness, const int lineType , const int cornerRadius)
    {
        Point p1 = topLeft;
        Point p2 = Point (bottomRight.x, topLeft.y);
        Point p3 = bottomRight;
        Point p4 = Point (topLeft.x, bottomRight.y);
    
    
        line(src, Point (p1.x+cornerRadius,p1.y), Point (p2.x-cornerRadius,p2.y), lineColor, thickness, lineType);
        line(src, Point (p2.x,p2.y+cornerRadius), Point (p3.x,p3.y-cornerRadius), lineColor, thickness, lineType);
        line(src, Point (p4.x+cornerRadius,p4.y), Point (p3.x-cornerRadius,p3.y), lineColor, thickness, lineType);
        line(src, Point (p1.x,p1.y+cornerRadius), Point (p4.x,p4.y-cornerRadius), lineColor, thickness, lineType);
    
        ellipse( src, p1+Point(cornerRadius, cornerRadius), Size( cornerRadius, cornerRadius ), 180.0, 0, 90, lineColor, thickness, lineType );
        ellipse( src, p2+Point(-cornerRadius, cornerRadius), Size( cornerRadius, cornerRadius ), 270.0, 0, 90, lineColor, thickness, lineType );
        ellipse( src, p3+Point(-cornerRadius, -cornerRadius), Size( cornerRadius, cornerRadius ), 0.0, 0, 90, lineColor, thickness, lineType );
        ellipse( src, p4+Point(cornerRadius, -cornerRadius), Size( cornerRadius, cornerRadius ), 90.0, 0, 90, lineColor, thickness, lineType );
    
        // choose arbitrary starting point for fill => Top left plus 10,10
        Point fillFrom(topLeft.x+10, topLeft.y+10);
        Scalar fillColor(199, 120, 0);
        // You may want to use `lineColor` instead of `fillColor`
        floodFill(src, fillFrom, fillColor);
    }