我想方设法使用OpenCV C ++绘制一个圆角矩形。我的功能是:
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);
}
现在我想填充矩形。我找到了一些填充函数,例如cv::fillPoly() and cv::fillConvexPoly
,但是,我需要一个带点的向量。我如何从我的建筑中获得积分清单?
要从使用cv::line
和cv::ellipse
构造的形状中获取点,可以在黑色背景上绘制形状,然后找到该图像的轮廓。
另一种不使用line
和ellipse
命令的方法是直接使用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()
使用cv :: floodFill和矩形内的起点。
这是我的解决方案,以帮助任何人的id。
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" );
}
}
这个答案是对@Stephen Meschke提交的答案的概括,以防任何人感兴趣
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()