How to fill a rounded rectangle in openCV c++ - 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?

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);
}

To get the points from the shape that you constructed with cv::line and cv::ellipse , you could draw the shape on a black background and then find the contours of that image.
Another approach that doesn't use line and ellipse commands is to compute the contour of the shape directly using trig.
import cv2, numpy as np, math
# Define the rectangle parameters
directions, ro, next_corner, radius, increment, angle, leg, corners = [(-1,0),(0,-1),(1,0),(0,1)],[(-1,-1),(1,-1),(1,1),(-1,1)],[3,0,1,2],56, 100, 0, 321, [(500,500)]
# Create list of corners
for side in range(4): corners.append((corners[side][0]+leg*directions[side][0], corners[side][1]+leg*directions[side][1]))
# Distance function
def distance(a,b): return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)
# Compute the contour points for each side and corner
contour_points = []
for i in range(4):
# Do the corner
center = corners[i][0] + radius*ro[i][0], corners[i][1] + radius*ro[i][1]
for angle_increment in range(increment):
contour_points.append((int(center[0] + math.cos(angle) * radius), int(center[1] + math.sin(angle) * radius)))
angle += .5*math.pi/increment
# Do the line
start = corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1]
while distance(start, (corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1])) < leg-2*radius:
contour_points.append(start)
start = start[0]+directions[i][0], start[1]+directions[i][1]
# Draw the contour and show the image
img = np.zeros((600,600), np.uint8)
cv2.drawContours(img, [np.array(contour_points, dtype=np.int32)], 0, 255, -1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Use cv::floodFill with start point inside your rectangle.

Here is my solution in case id of help to anybody.
void FilledRoundedRectangle(cv::Mat& src, //Image where rect is drawn
cv::Point topLeft, //top left corner
cv::Size rectSz, //rectangle size
const cv::Scalar fillColor, //fill color
const int lineType, //type of line
const int delta, //angle between points on the ellipse
const float cornerCurvatureRatio) //curvature of the corner
{
// 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);
int cornerRadius = static_cast<int>(rectSz.height*cornerCurvatureRatio);
std::vector<cv::Point> points;
std::vector<cv::Point> pts;
// Add arcs points
cv::Size rad = cv::Size(cornerRadius, cornerRadius);
// segments:
// s2____s3
// s1 s4
// | |
// s8 s5
// s7_____s6
//
//Add arc s1 to s2
cv::ellipse2Poly(p1 + cv::Point(cornerRadius, cornerRadius) , rad, 180.0, 0, 90, delta , pts);
points.insert(points.end(), pts.begin(), pts.end());
pts.clear();
//Add line s2-s3
points.push_back(cv::Point (p1.x + cornerRadius, p1.y)); points.push_back(cv::Point (p2.x - cornerRadius, p2.y));
//Add arc s3 to s4
cv::ellipse2Poly(p2 + cv::Point(-cornerRadius, cornerRadius) , rad, 270.0, 0, 90, delta, pts);
points.insert(points.end(), pts.begin(), pts.end());
pts.clear();
//Add line s4 to s5
points.push_back(cv::Point (p2.x, p2.y + cornerRadius)); points.push_back(cv::Point (p3.x, p3.y - cornerRadius));
//Add arc s5 to s6
cv::ellipse2Poly(p3 + cv::Point(-cornerRadius, -cornerRadius), rad, 0.0, 0, 90, delta, pts);
points.insert(points.end(), pts.begin(), pts.end());
pts.clear();
//Add line s7 to s8
points.push_back(cv::Point (p4.x + cornerRadius, p4.y)); points.push_back(cv::Point (p3.x - cornerRadius, p3.y));
//Add arc s7 to s8
cv::ellipse2Poly(p4 + cv::Point(cornerRadius, -cornerRadius) , rad, 90.0, 0, 90, delta, pts);
points.insert(points.end(), pts.begin(), pts.end());
//Add line s1 to s8
points.push_back(cv::Point (p1.x, p1.y + cornerRadius)); points.push_back(cv::Point (p4.x, p4.y - cornerRadius));
//fill polygon
cv::fillConvexPoly(src, points, fillColor, lineType);
}
int main(int argc, char** argv)
{
try
{
cv::Mat img = cv::Mat(600, 600,CV_8UC1,cv::Scalar(0));
cv::Point topLeft(179, 179);
cv::Size rectSz(321, 321);
cv::Scalar fillColor(255, 255, 255);
int delta = 1; //every 1 degree
int lineType = cv::LINE_AA;
float cornerCurvatureRatio = 0.1;
FilledRoundedRectangle(img,
topLeft,
rectSz,
fillColor,
lineType,
delta,
cornerCurvatureRatio);
cv::imshow("", img);
cv::waitKey(0);
return 0;
std::cin.get();
} //end try
catch ( std::exception const & ex )
{
std::string errMsg = ex.what();
printf( "%s\n", errMsg.c_str() );
}
catch ( ... )
{
printf( "Error: unknown exception\n" );
}
}

This answer is a generalization of the answer submitted by #Stephen Meschke in case anyone is interested
import cv2
import numpy as np
# Distance function
def distance(a,b):
return np.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)
def RoundedRectPoints(topLeft,rectSz,cornerCurvature):
# Define the rectangle parameters
directions = [(-1,0),(0,-1),(1,0),(0,1)]
ro = [(-1,-1),(1,-1),(1,1),(-1,1)]
radius = cornerCurvature*(rectSz[0]+rectSz[1]);
increment = 100
angle = 0
corners = [(topLeft[0]+rectSz[0],topLeft[1]+rectSz[1])]
# Create list of corners
for side in range(4):
corners.append((corners[side][0]+rectSz[side%2]*directions[side][0], corners[side][1]+rectSz[side%2]*directions[side][1]))
# Compute the contour points for each side and corner
contour_points = []
for i in range(4):
# Do the corner
center = corners[i][0] + radius*ro[i][0], corners[i][1] + radius*ro[i][1]
for angle_increment in range(increment):
contour_points.append((int(center[0] + np.cos(angle) * radius), int(center[1] + np.sin(angle) * radius)))
angle += .5*np.pi/increment
# Do the line
start = corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1]
while distance(start, (corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1])) < np.min(rectSz)-2*radius:
contour_points.append(start)
start = start[0]+directions[i][0], start[1]+directions[i][1]
return contour_points
# Draw the contour and show the image
img = np.zeros((600,600), np.uint8)
topLeft = (179,179)
rectSz = (321,321)
cornerCurvature = 0.09
contour_points = RoundedRectPoints(topLeft,rectSz,cornerCurvature)
cv2.drawContours(img, [np.array(contour_points, dtype=np.int32)], 0, 255, -1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Related

Hough transform old opencv convert into new opencv

i am trying to make hough transformation to parallel programming this is a code that i found online and i am new in using opencv2 in c++ anyone know how to convert this code into new open cv code?
//Next do the Canney and Hough transforms on the smaller image
IplImage* src;
src=cvLoadImage(fileName, 0);
IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
IplImage* final_dst = cvCreateImage( cvGetSize(src), 8, 1 );
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* lines = 0;
int i;
cvCanny( src, dst, 50, 200, 3 );
cvCvtColor( dst, color_dst, CV_GRAY2BGR );
lines = cvHoughLines2( dst,
storage,
CV_HOUGH_STANDARD,
1,
CV_PI/180,
100,
0,
0 );
for( i = 0; i < MIN(lines->total,100); i++ )
{
float* line = (float*)cvGetSeqElem(lines,i);
float rho = line[0];
float theta = line[1];
CvPoint pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 2, 8 );
}
cvCvtColor(color_dst, final_dst, CV_BGR2GRAY);
cvSaveImage(fileName, final_dst);
i have tried a bit but i think i fail
//Next do the Hough transforms on the smaller image
cv::Mat src = cv::imread(fileName);
cv::Mat dst;
cv::Mat color_dst;
cv::Mat final_dst;
//IplImage src;
//src=cvLoadImage(fileName, 0);
//IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
//IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
//IplImage* final_dst = cvCreateImage( cvGetSize(src), 8, 1 );
//CvMemStorage* storage = cvCreateMemStorage(0);
cv::namedWindow(CW_IMG_ORIGINAL, cv::WINDOW_NORMAL);
cv::resizeWindow(CW_IMG_ORIGINAL, 1280, 720);
cv::moveWindow(CW_IMG_ORIGINAL, 10, 10);
cv::Mat lines;
//CvSeq* lines = 0;
//cv::Seq<linesTp>;
int i;
cvHoughLines2;
cv::Canny( src, dst, 50, 200, 3 );
cv::cvtColor( dst, color_dst, CV_GRAY2BGR );
cv::HoughLines( dst,lines,
CV_HOUGH_STANDARD,
1,
CV_PI/180,
100,
0,
0 );
for( i = 0; i < 100; i++ )
{
//float* line = (float*)cv::getSeqElem(lines, i);
float* line = lines.at(i);
float rho = line[0];
float theta = line[1];
cv::Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
cv::line(color_dst, pt1, pt2, CV_RGB(255, 0, 0), 2, 8);
}
cv::cvtColor(color_dst, final_dst, CV_BGR2GRAY);
cv::imshow(CW_IMG_ORIGINAL,final_dst);
I fail due to i dono how to implement the hough lines into the line to do the iteration of the formula previously using cvhoughlines2 but cvhoughlines2 need to insert as cvArr but the cvLoadImage is not currently working in opencv4.1.2 so that I cant use IplImage and cvLoadImage to run this code.

How to draw a rotated trapeze in OpenCV?

I know how to draw rotated rectangle using RotatedRect. However I would like to draw a rotated Trapeze using opencv.
I found a solution.
A) Define the four points of the trapeze as a contour:
std::vector<std::vector<cv::Point> > MakeRotatedTrapeze(
const cv::Size& BBSize,
const float& angleRad,
const cv::Point2f& trapezeCenter,
const float& topToBottomRatio)
{
//Make trapeze
cv::Point2f deltaDOWN( BBSize.height/2*sin(angleRad), BBSize.height/2*cos(angleRad));//bottom
cv::Point2f deltaUP = -deltaDOWN;//top
cv::Point2f deltaLEFT(-BBSize.width/2*cos(angleRad), BBSize.width/2*sin(angleRad));//left
cv::Point2f deltaRIGHT = -deltaLEFT;//right
cv::Point2f bl = trapezeCenter + deltaDOWN + deltaLEFT;
cv::Point2f br = trapezeCenter + deltaDOWN + deltaRIGHT;
cv::Point2f tl = trapezeCenter + deltaUP + topToBottomRatio*deltaLEFT;
cv::Point2f tr = trapezeCenter + deltaUP + topToBottomRatio*deltaRIGHT;
cv::Point trapez_pts[4] = {tl, tr, br, bl};
vector<vector<Point> > trapeze(1, vector<Point>(trapez_pts, trapez_pts + 4));
return trapeze;
}
B) Draw the trapeze using drawContours
float trapezTopScale = 0.5;
std::vector<std::vector<cv::Point> > trapeze = MakeRotatedTrapeze( cv::Size(100, 50), 45.0, cv::Point2f(320, 240), trapezTopScale);
cv::Mat image(480, 640, CV_8UC1);
image.setTo(0);
drawContours( image, trapeze, 0, cv::Scalar(255), CV_FILLED, 8, vector<Vec4i>() );

Draw the lines detected by cv::HoughLines

On this site(tutorial), it show us how to draw the lines detected by cv::HoughLines,but I can't understand how could it find out the Point between the lines.
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b)); //??
pt1.y = cvRound(y0 + 1000*(a)); //??
pt2.x = cvRound(x0 - 1000*(-b)); //??
pt2.y = cvRound(y0 - 1000*(a)); //??
line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
Example from the openCV cookbook, I could understand the reason these codes
but it is more verbose
for(auto const &data : lines){
float const rho = data[0];
float const theta = data[1];
if((theta < PI/4. || theta > 3. * PI/4.)){
cv::Point pt1(rho / std::cos(theta), 0);
cv::Point pt2( (rho - result.rows * std::sin(theta))/std::cos(theta), result.rows);
cv::line(result, pt1, pt2, cv::Scalar(255), 1);
}else if{
cv::Point pt1(0, rho / std::sin(theta));
cv::Point pt2(result.cols, (rho - result.cols * std::cos(theta))/std::sin(theta));
cv::line(result, pt1, pt2, cv::Scalar(255), 1);
}
}
Hough Line transform returns Polar coordinates. To display the lines on 2D picture, coordinates have to be converted do Cartesian coordinates. Here is some more info about this: http://www.mathsisfun.com/polar-cartesian-coordinates.html
Lines, returned from Hough Transform have only one Cartesian point (intersect between blue and red line):
So to display the line author converts the coordinates to Cartesian and then calculates start and end points which are set to fixed position -1000 and +1000 pixels from the converted point:
pt1.x = cvRound(x0 + 1000*(-b)); //??
pt1.y = cvRound(y0 + 1000*(a)); //??
pt2.x = cvRound(x0 - 1000*(-b)); //??
pt2.y = cvRound(y0 - 1000*(a)); //??
One option to find intersection between returned lines is to use this equation:
For more information about implementation of this see this tutorial.

How to draw a rounded rectangle (rectangle with rounded corners) with OpenCV?

How can I draw a rectangle with rounded corners in OpenCV? I know that the functions ellipse() and line() can be simply put together to draw it. I just wonder if someone has done it before and has put it in a proper function so I can use it? Ideally the corner radius is to calibrate in a parameter.
I searched a lot for that, but it seems no one had that problem before. If no one has such I function I will probably post my own solution here in a few days.
I realized, this is much easier that I thought. Here is my function. I hope it is helpful for someone.
/**
* Draws a rectangle with rounded corners, the parameters are the same as in the OpenCV function #see rectangle();
* #param cornerRadius A positive int value defining the radius of the round corners.
* #author K
*/
void rounded_rectangle( Mat& src, Point topLeft, Point bottomRight, const Scalar lineColor, const int thickness, const int lineType , const int cornerRadius)
{
/* corners:
* p1 - p2
* | |
* p4 - p3
*/
Point p1 = topLeft;
Point p2 = Point (bottomRight.x, topLeft.y);
Point p3 = bottomRight;
Point p4 = Point (topLeft.x, bottomRight.y);
// draw straight lines
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);
// draw arcs
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 );
}
Here is the python version with filled/not filled feature and corner_radius automatically calculated based on the image's height.
import cv2
import numpy as np
def rounded_rectangle(src, top_left, bottom_right, radius=1, color=255, thickness=1, line_type=cv2.LINE_AA):
# corners:
# p1 - p2
# | |
# p4 - p3
p1 = top_left
p2 = (bottom_right[1], top_left[1])
p3 = (bottom_right[1], bottom_right[0])
p4 = (top_left[0], bottom_right[0])
height = abs(bottom_right[0] - top_left[1])
if radius > 1:
radius = 1
corner_radius = int(radius * (height/2))
if thickness < 0:
#big rect
top_left_main_rect = (int(p1[0] + corner_radius), int(p1[1]))
bottom_right_main_rect = (int(p3[0] - corner_radius), int(p3[1]))
top_left_rect_left = (p1[0], p1[1] + corner_radius)
bottom_right_rect_left = (p4[0] + corner_radius, p4[1] - corner_radius)
top_left_rect_right = (p2[0] - corner_radius, p2[1] + corner_radius)
bottom_right_rect_right = (p3[0], p3[1] - corner_radius)
all_rects = [
[top_left_main_rect, bottom_right_main_rect],
[top_left_rect_left, bottom_right_rect_left],
[top_left_rect_right, bottom_right_rect_right]]
[cv2.rectangle(src, rect[0], rect[1], color, thickness) for rect in all_rects]
# draw straight lines
cv2.line(src, (p1[0] + corner_radius, p1[1]), (p2[0] - corner_radius, p2[1]), color, abs(thickness), line_type)
cv2.line(src, (p2[0], p2[1] + corner_radius), (p3[0], p3[1] - corner_radius), color, abs(thickness), line_type)
cv2.line(src, (p3[0] - corner_radius, p4[1]), (p4[0] + corner_radius, p3[1]), color, abs(thickness), line_type)
cv2.line(src, (p4[0], p4[1] - corner_radius), (p1[0], p1[1] + corner_radius), color, abs(thickness), line_type)
# draw arcs
cv2.ellipse(src, (p1[0] + corner_radius, p1[1] + corner_radius), (corner_radius, corner_radius), 180.0, 0, 90, color ,thickness, line_type)
cv2.ellipse(src, (p2[0] - corner_radius, p2[1] + corner_radius), (corner_radius, corner_radius), 270.0, 0, 90, color , thickness, line_type)
cv2.ellipse(src, (p3[0] - corner_radius, p3[1] - corner_radius), (corner_radius, corner_radius), 0.0, 0, 90, color , thickness, line_type)
cv2.ellipse(src, (p4[0] + corner_radius, p4[1] - corner_radius), (corner_radius, corner_radius), 90.0, 0, 90, color , thickness, line_type)
return src
Usage:
top_left = (0, 0)
bottom_right = (500, 800)
color = (255, 255, 255)
image_size = (500, 800, 3)
img = np.zeros(image_size)
img = rounded_rectangle(img, top_left, bottom_right, color=color, radius=0.5, thickness=-1)
cv2.imshow('rounded_rect', img)
cv2.waitKey(0)
Here's a Python implementation(in case anyone was looking for one): it draws a rounded corner (of random radius and line thickness --- change that if you want) border around an image:
def addRoundedRectangleBorder(img):
height, width, channels = img.shape
border_radius = int(width * random.randint(1, 10)/100.0)
line_thickness = int(max(width, height) * random.randint(1, 3)/100.0)
edge_shift = int(line_thickness/2.0)
red = random.randint(230,255)
green = random.randint(230,255)
blue = random.randint(230,255)
color = (blue, green, red)
#draw lines
#top
cv2.line(img, (border_radius, edge_shift),
(width - border_radius, edge_shift), (blue, green, red), line_thickness)
#bottom
cv2.line(img, (border_radius, height-line_thickness),
(width - border_radius, height-line_thickness), (blue, green, red), line_thickness)
#left
cv2.line(img, (edge_shift, border_radius),
(edge_shift, height - border_radius), (blue, green, red), line_thickness)
#right
cv2.line(img, (width - line_thickness, border_radius),
(width - line_thickness, height - border_radius), (blue, green, red), line_thickness)
#corners
cv2.ellipse(img, (border_radius+ edge_shift, border_radius+edge_shift),
(border_radius, border_radius), 180, 0, 90, color, line_thickness)
cv2.ellipse(img, (width-(border_radius+line_thickness), border_radius),
(border_radius, border_radius), 270, 0, 90, color, line_thickness)
cv2.ellipse(img, (width-(border_radius+line_thickness), height-(border_radius + line_thickness)),
(border_radius, border_radius), 10, 0, 90, color, line_thickness)
cv2.ellipse(img, (border_radius+edge_shift, height-(border_radius + line_thickness)),
(border_radius, border_radius), 90, 0, 90, color, line_thickness)
return img
based on the code from #author K. make the function have ability to draw filled rounded rectangle if pass -1 as thickness
python version
def DrawRoundedRectangle(img, topLeft, bottomRight, radius=1, color=255, thickness=1, line_type=cv.LINE_AA):
min_half = int(min((bottomRight[0] - topLeft[0]), (bottomRight[1] - topLeft[1])) * 0.5)
radius = min(radius, min_half)
# /* corners:
# * p1 - p2
# * | |
# * p4 - p3
# */
p1 = topLeft
p2 = (bottomRight[0], topLeft[1])
p3 = bottomRight
p4 = (topLeft[0], bottomRight[1])
if(thickness < 0):
# // draw rectangle
cv.rectangle(img, (p1[0] + radius, p1[1]), (p3[0] - radius, p3[1]), color, thickness, line_type)
cv.rectangle(img, (p1[0], p1[1] + radius), (p3[0], p3[1] - radius), color, thickness, line_type)
else:
# // draw straight lines
cv.line(img, (p1[0] + radius, p1[1]), (p2[0] - radius, p2[1]), color, thickness, line_type);
cv.line(img, (p2[0], p2[1] + radius), (p3[0], p3[1] - radius), color, thickness, line_type);
cv.line(img, (p4[0] + radius, p4[1]), (p3[0]-radius, p3[1]), color, thickness, line_type);
cv.line(img, (p1[0], p1[1] + radius), (p4[0], p4[1] - radius), color, thickness, line_type);
# // draw arcs
if(radius > 0):
cv.ellipse( img, (p1[0] + radius, p1[1] + radius), ( radius, radius ), 180.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, (p2[0] - radius, p2[1] + radius), ( radius, radius ), 270.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, (p3[0] - radius, p3[1] - radius), ( radius, radius ), 0.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, (p4[0] + radius, p4[1] - radius), ( radius, radius ), 90.0, 0, 90, color, thickness, line_type );
javascript version
function DrawRoundedRectangle(img, topLeft, bottomRight, radius=1, color=255, thickness=1, line_type=cv.LINE_AA){
let min_half = Math.floor(Math.min((bottomRight.x - topLeft.x), (bottomRight.y - topLeft.y)) * 0.5)
radius = Math.min(radius, min_half)
/* corners:
# * p1 - p2
# * | |
# * p4 - p3
# */
let p1 = topLeft
let p2 = new cv.Point(bottomRight.x, topLeft.y)
let p3 = bottomRight
let p4 = new cv.Point(topLeft.x, bottomRight.y)
if(thickness < 0){
// draw rectangle
cv.rectangle(img, new cv.Point(p1.x + radius, p1.y), new cv.Point(p3.x - radius, p3.y), color, thickness, line_type)
cv.rectangle(img, new cv.Point(p1.x, p1.y + radius), new cv.Point(p3.x, p3.y - radius), color, thickness, line_type)
}
else{
// draw straight lines
cv.line(img, new cv.Point(p1.x + radius, p1.y), new cv.Point(p2.x - radius, p2.y), color, thickness, line_type);
cv.line(img, new cv.Point(p2.x, p2.y + radius), new cv.Point(p3.x, p3.y - radius), color, thickness, line_type);
cv.line(img, new cv.Point(p4.x + radius, p4.y), new cv.Point(p3.x-radius, p3.y), color, thickness, line_type);
cv.line(img, new cv.Point(p1.x, p1.y + radius), new cv.Point(p4.x, p4.y - radius), color, thickness, line_type);
}
// draw arcs
if(radius > 0){
cv.ellipse( img, new cv.Point(p1.x + radius, p1.y + radius), new cv.Size( radius, radius ), 180.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, new cv.Point(p2.x - radius, p2.y + radius), new cv.Size( radius, radius ), 270.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, new cv.Point(p3.x - radius, p3.y - radius), new cv.Size( radius, radius ), 0.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, new cv.Point(p4.x + radius, p4.y - radius), new cv.Size( radius, radius ), 90.0, 0, 90, color, thickness, line_type );
}
}

OpenCV, Rotation around specific point

I am trying to rotate four points(rectangle) around the middle point of them.
But the result looks strange.
I use the formula found here and on wikipedia
p.x'=p.x*cos(alpha) + p.y*sin(alpha);
p.y'=(-1)p.x*sin(alpha) + p.y*cos(alpha);
Is this formula applicable for my purpose (rotating rectangle)?
Here is the source, I try to rotate 33 degrees counter clockwise
Thank You, very much
Mat img(480, 800, CV_8UC4, Scalar(255,255,255,255));
Mat dst(480, 800, CV_8UC4, Scalar(255,255,255,255));
Point p1, p2, p3, p4;
Point center;
p1.x=501; p1.y=247;
p2.x=429; p2.y=291;
p3.x=388; p3.y=222;
p4.x=451; p4.y=186;
circle(img, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(img, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(img, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(img, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
center.x = (p1.x+p2.x+p3.x+p4.x)/4;
center.y = (p1.y+p2.y+p3.y+p4.y)/4;
double alpha = -33 * 0.0174532925;
double s = sin(alpha);
double c = cos(alpha);
p1.x = (+c*(p1.x-center.x)* + s*(p1.y-center.y)) + center.x;
p1.y = (-s*(p1.x-center.x) + c*(p1.y-center.y)) + center.y;
p2.x = (+c*(p2.x-center.x)* + s*(p2.y-center.y)) + center.x;
p2.y = (-s*(p2.x-center.x) + c*(p2.y-center.y)) + center.y;
p3.x = (+c*(p3.x-center.x)* + s*(p3.y-center.y)) + center.x;
p3.y = (-s*(p3.x-center.x) + c*(p3.y-center.y)) + center.y;
p4.x = (+c*(p4.x-center.x)* + s*(p4.y-center.y)) + center.x;
p4.y = (-s*(p4.x-center.x) + c*(p4.y-center.y)) + center.y;
circle(dst, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(dst, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(dst, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(dst, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
imshow("src", img);
imshow("dst", dst);
cvMoveWindow("dst", 0, img.cols+50);
waitKey(0);
return 0;
Your formula is correct. Your math looks fine. Your problem is probably just the extra * symbol:
p1.x = (+c*(p1.x-center.x)* + s*(p1.y-center.y)) + center.x;
^
This gets evaluated as:
p1.x = ((+c*(p1.x-center.x))* (+ s*(p1.y-center.y))) + center.x;
Just remove the *
So, i find the solution.
I noob overwrite previous x value with new computed values
This is the solution
for(int i = 0; i<360; i++)
{
Mat img(480, 800, CV_8UC4, Scalar(255,255,255,255));
Mat dst(480, 800, CV_8UC4, Scalar(255,255,255,255));
Point p1, p2, p3, p4;
Point center;
p1.x=501; p1.y=247;
p2.x=429; p2.y=291;
p3.x=388; p3.y=222;
p4.x=451; p4.y=186;
circle(img, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(img, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(img, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(img, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
center.x = (p1.x+p2.x+p3.x+p4.x)/4;
center.y = (p1.y+p2.y+p3.y+p4.y)/4;
double alpha = -i * 0.0174532925;
double s = sin(alpha);
double c = cos(alpha);
int x = 0, y = 0;
x=p1.x; y=p1.y;
p1.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p1.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
x=p2.x; y=p2.y;
p2.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p2.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
x=p3.x; y=p3.y;
p3.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p3.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
x=p4.x; y=p4.y;
p4.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p4.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
circle(dst, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(dst, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(dst, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(dst, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
imshow("src", img);
imshow("dst", dst);
cvMoveWindow("dst", 0, img.cols+50);
waitKey(20);