假设在opencv中有一个正方形的M*M的图像,现在要在这个图像上面画一个半径M的圆。现在假设只能打点的方法来画,则中点画圆法是一个很好的方法。opencv中的图像就是一个M行M列的矩阵,坐标(0,0)代表第0行第0列的点。
1 圆的方程与圆的特性
取半径r=M/2,要画的圆心坐标是(r,r),则圆的方程是(x1-r)2+(y1-r)2=r2。选取x=x1-r,y=r-y1,则在新坐标系中有x2+y2=r2。新坐标系圆心位于图像的中心(r,r)处。
如下图,当某点(x,y)在圆上时(假定圆心坐标为(0,0)),则(x,-y),(-x,y),(-x,-y),(y,x),(y,-x),(-y,x),(-y,-x)都将在这个圆周上。
2 中点画圆法
如下图所示,考虑圆的方程x2+y2=r2,构造判别式f(x,y)= x2+y2-r2,当某点在圆上时,f(x,y)=0;当某点在圆内时,f(x,y)<0;当某点在圆外时,f(x,y)>0。依据圆的八分法特性,只要画出圆在第一象限中的上半部分。设某点P(xi,yi)在圆周上,要取的新点只会是P1(xi+1,yi)或者P2(xi+1,yi-1),P1和P2的中点为M(xi+1,yi-0.5),当f(xi +1, yi – 0.5)< 0时,M点在圆内,说明P1点离实际圆弧更近,应该取P1作为圆的下一个点。同理分析,当F(xi + 1, yi – 0.5)> 0时,P2离实际圆弧更近,应取P2作为下一个点。当F(xi + 1, yi – 0.5)= 0时,P1和P2都可以作为圆的下一个点,算法约定取P2作为下一个点。
现在将M点坐标(xi+ 1, yi–0.5)带入判别函数F(x,y),得到判别式d:
d= F(xi+1, yi–0.5)= (xi+1)2+(yi–0.5)2–R2
若d< 0,则取P1为下一个点,此时P1的下一个点的判别式为:
d’=F(xi+2, yi–0.5)= (xi+2)2+(yi–0.5)2–R2
展开后将d带入可得到判别式的递推关系:
d’=d + 2xi+3
若d> 0,则取P2为下一个点,此时P2的下一个点的判别式为:
d’=F(xi+2, yi–1.5)= (xi+ 2)2+(yi–1.5)2–R2
展开后将d带入可得到判别式的递推关系:
d’= d + 2(xi-yi)+5
特别的,在第一个象限的第一个点(0, R)时,可以推倒出判别式d的初始值d0:
d0 = F(1, R–0.5) = 1–(R–0.5)2–R2=1.25 - R
3 贴出程序
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
//此程序对于OpenCV3版需要额外包含头文件:
#include <opencv2/imgproc/imgproc.hpp>
#define WINDOW_NAME1 "【绘制图1】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【绘制图2】" //为窗口标题定义的宏
#define WINDOW_WIDTH 600//定义窗口大小的宏
void DrawLine( Mat img, Point start, Point end );//绘制线段
void MP_Circle(Mat img,intr);
int main( void )
{
// 创建空白的Mat图像
Mat rookImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3 );
MP_Circle(rookImage,WINDOW_WIDTH/2);
//---------------------------<3>显示绘制出的图像------------------------
namedWindow(WINDOW_NAME1);
imshow( WINDOW_NAME1, rookImage );
waitKey( 0 );
return(0);
}
void drawPoint(Mat img,Point pt)
{
intthickness = 1;
intlineType = 8;
line( img,
pt,
Point(pt.x+1,pt.y),
Scalar( 255, 255, 255 ),
thickness,
lineType );
}
void MP_Circle(Mat img,intr)
{
int x, y;
double d;
x = 0;
y = r;
d = 1.25-r;
drawPoint(img,Point(x,y));
while(x< y)
{
if(d< 0)
{
d = d + 2 * x + 3;
}
else
{
d = d + 2 * ( x - y ) + 5;
y--;
}
x++;
drawPoint(img,Point(x+r , r-y));
drawPoint(img,Point(x+r,r+y));
drawPoint(img,Point(-x+r,r-y));
drawPoint(img,Point(-x+r,r+y));
drawPoint(img,Point(r-y,x+r));
drawPoint(img,Point(r+y,x+r));
drawPoint(img,Point(r-y,-x+r));
drawPoint(img,Point(r+y,-x+r));
}
}
效果如图: