opencv中使用中点画圆算法


假设在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));

     }

 }

效果如图:

猜你喜欢

转载自blog.csdn.net/liuzhijun301/article/details/78318622