图形学实验一:bresenham算法 画线和画圆

时间:2022-07-13 09:48:51

注明:本博客中所有文章均可转载,但请给出链接!!!


由于画线、画圆,需要在专门的窗口上,因为设计像素点,一般c++编程环境中那个运行程序的命令窗口是不行的,所以这里用到了opencv。

我编程环境用的是codeblock,所以我就在此基础上,做关于此实验的讲解。

首先,先要在codeblocks上配置opencv:http://blog.csdn.net/dupei/article/details/6428283
配置好后,接着就开始画线和画图了。


一:画线。
先给出介绍一个bresenham画直线算法的博客,讲得很详细了。
http://www.jhmcu.com/lcd-hua-zhi-xian-zhi-bresenham-suan-fa/

不过上面只考虑了dy<=dx的情况,还应考虑dy>dx的情况,此时只要将x和y互换一下即可。否则话会出现如下图所示的情况。

图形学实验一:bresenham算法 画线和画圆

再给出一个我参考的代码实现的博客,此博客两种情况均考虑了:
http://www.xuebuyuan.com/345229.html

看了上面两个博客,基本上对画线就有一定了解了。下面给出我的代码:

[cpp]  view plain copy
  1. #include  <cv.h>  
  2. #include  <highgui.h>  
  3. #include  <cxcore.h>  
  4. #include  <iostream>  
  5. #include  <cmath>  
  6. #define RGB R,G,B  
  7. #define SIZE 500  
  8. using namespace std;  
  9. /* 
  10. 算法参考链接: 
  11. http://www.jhmcu.com/lcd-hua-zhi-xian-zhi-bresenham-suan-fa/ 
  12. 链接上只给出了|dx|>=|dy|的情况,应该要综合考虑dx>dy和dy>dx两种情况 
  13. */  
  14.   
  15. //判断是否在窗口内部  
  16. bool isInside(int a,int b){  
  17.     if(a>0 && b>0 && a<SIZE &&b<SIZE)  
  18.         return true;  
  19.     else  
  20.         return false;  
  21. }  
  22. //画点  
  23. void drawPoint(IplImage *imgA,int x,int y,int R,int G,int B) {  
  24.     imgA->imageData[y * imgA->widthStep + x * 3] = (signed char) R;  
  25.     imgA->imageData[y * imgA->widthStep + x * 3 + 1] = (signed char) G;  
  26.     imgA->imageData[y * imgA->widthStep + x * 3 + 2] = (signed char) B;  
  27. }  
  28. /** 
  29. 起始点:(x1,y1) 
  30. 终点:(x2,y2) 
  31. 颜色R,G,B 
  32. */  
  33. void Bresenham(IplImage *imgA,int x1,int y1,int x2,int y2,int R,int G,int B,int thickness) {  
  34.     int dx, dy;//横轴纵轴差量  
  35.     int e;  
  36.     int x, y;  
  37.     dx = abs (x2 - x1);  
  38.     dy = abs (y2 - y1);  
  39.     y = y1;  
  40.     x = x1;  
  41.     int cx, cy;//表明x、y方向的增量  
  42.     if (x1 > x2) {  
  43.         cx = -1;//x递减方向  
  44.     } else {  
  45.         cx = 1;//x递增方向  
  46.     }  
  47.     if (y1 > y2) {  
  48.         cy = -1;//y递减方向  
  49.     } else {  
  50.         cy = 1;//y递增方向  
  51.     }  
  52.     if(dx==0 && dy==0) {  
  53.         printf("The input is not a line. It is just a point. Please input two different points.!\n");  
  54.     } else if(dy==0) {  
  55.         for(x=x1; (cx ==1  ? x <= x2 : x >= x2); x+=cx) {  
  56.             if(isInside(x,y))  
  57.             drawPoint(imgA,x,y,RGB);  
  58.             for(int i=1; i<=thickness; i++) {  
  59.                 if(isInside(x,y+i))  
  60.                     drawPoint(imgA,x,y+i,RGB);  
  61.             }  
  62.         }  
  63.     } else if(dx==0) {  
  64.         for (y = y1; (cy ==1 ? y <= y2 : y >= y2); y += cy) {  
  65.             if(isInside(x,y))  
  66.                 drawPoint(imgA,x,y,RGB);  
  67.             for(int i=1; i<=thickness; i++) {  
  68.                 if(isInside(x+i,y))  
  69.                     drawPoint(imgA,x+i,y,RGB);  
  70.             }  
  71.         }  
  72.     } else if(dx>=dy) {  
  73.         e=-dx;  
  74.         for (x = x1; (cx ==1 ? x <= x2 : x >= x2); x += cx) {  
  75.             if(isInside(x,y))  
  76.             drawPoint(imgA,x,y,RGB);  
  77.             e+=dy<<1;  
  78.             if (e>0) {  
  79.                 y += cy;  
  80.                 e -= dx<<1;  
  81.             }  
  82.         }  
  83.     } else {  
  84.         e=-dy;  
  85.         for (y = y1; (cy >= 0 ? y <= y2 : y >= y2); y += cy) {  
  86.             if(isInside(x,y))  
  87.             drawPoint(imgA,x,y,RGB);  
  88.             e+=dx<<1;  
  89.             if (e>0) {  
  90.                 x += cx;  
  91.                 e -= dy<<1;  
  92.             }  
  93.   
  94.         }  
  95.     }  
  96. }  
  97. //加粗  
  98. void drawThickness(IplImage *imgA,int x1,int y1,int x2,int y2,int R,int G,int B,int thickness) {  
  99.     int dy=y2-y1;  
  100.     int dx=x2-x1;  
  101.     /* 
  102.     四个象限加粗方向不同 
  103.     */  
  104.     int dir1[4][2][2]={{{-1,-1},{1,1}},{{-1,1},{1,-1}},{{1,1},{-1,-1}},{{-1,1},{1,-1}}};  
  105.     int a1,a2,b1,b2;  
  106.     if(dx>0 && dy<0) {  
  107.         for(int i=1; i<=(thickness+1)/2; i++) {  
  108.             a1=x1+i*dir1[0][0][0];  
  109.             b1=y1+i*dir1[0][0][1];  
  110.             a2=x2+i*dir1[0][0][0];  
  111.             b2=y2+i*dir1[0][0][1];  
  112.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  113.         }  
  114.         for(int i=1; i<=(thickness)/2; i++) {  
  115.             a1=x1+i*dir1[0][1][0];  
  116.             b1=y1+i*dir1[0][1][1];  
  117.             a2=x2+i*dir1[0][1][0];  
  118.             b2=y2+i*dir1[0][1][1];  
  119.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  120.         }  
  121.     } else if(dx<0 && dy<0){  
  122.         for(int i=1; i<=(thickness+1)/2; i++) {  
  123.             a1=x1+i*dir1[1][0][0];  
  124.             b1=y1+i*dir1[1][0][1];  
  125.             a2=x2+i*dir1[1][0][0];  
  126.             b2=y2+i*dir1[1][0][1];  
  127.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  128.         }  
  129.         for(int i=1; i<=(thickness)/2; i++) {  
  130.             a1=x1+i*dir1[1][1][0];  
  131.             b1=y1+i*dir1[1][1][1];  
  132.             a2=x2+i*dir1[1][1][0];  
  133.             b2=y2+i*dir1[1][1][1];  
  134.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  135.         }  
  136.     }  
  137.     else if(dx<0&&dy>0){  
  138.         for(int i=1; i<=(thickness+1)/2; i++) {  
  139.             a1=x1+i*dir1[2][0][0];  
  140.             b1=y1+i*dir1[2][0][1];  
  141.             a2=x2+i*dir1[2][0][0];  
  142.             b2=y2+i*dir1[2][0][1];  
  143.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  144.         }  
  145.         for(int i=1; i<=(thickness)/2; i++) {  
  146.             a1=x1+i*dir1[2][1][0];  
  147.             b1=y1+i*dir1[2][1][1];  
  148.             a2=x2+i*dir1[2][1][0];  
  149.             b2=y2+i*dir1[2][1][1];  
  150.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  151.         }  
  152.     }  
  153.     else if(dx>0&&dy>0){  
  154.         for(int i=1; i<=(thickness+1)/2; i++) {  
  155.             a1=x1+i*dir1[3][0][0];  
  156.             b1=y1+i*dir1[3][0][1];  
  157.             a2=x2+i*dir1[3][0][0];  
  158.             b2=y2+i*dir1[3][0][1];  
  159.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  160.         }  
  161.         for(int i=1; i<=(thickness)/2; i++) {  
  162.             a1=x1+i*dir1[3][1][0];  
  163.             b1=y1+i*dir1[3][1][1];  
  164.             a2=x2+i*dir1[3][1][0];  
  165.             b2=y2+i*dir1[3][1][1];  
  166.             Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);  
  167.         }  
  168.     }  
  169. }  
  170. int main (int argc, char *argv[]) {  
  171.     int x1,x2,y1,y2;  
  172.     int R,G,B;  
  173.     int thickness=1;  
  174.     CvSize window = { SIZE, SIZE };  
  175.     IplImage *imgA = cvCreateImage (window, IPL_DEPTH_8U, 3);  
  176.     cvSet (imgA, cvScalarAll (0), 0);  
  177.   
  178.     cvNamedWindow ("window", CV_WINDOW_AUTOSIZE);  
  179.     while(true) {  
  180.         printf("Please input coordinates of two points(if both points are (0,0),the program exits):\n");  
  181.         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);  
  182.         if(x1==0 && y1==0 && x2==0 && y2==0) {  
  183.             break;  
  184.         }  
  185.         printf("Please input the color(R,G,B):\n");  
  186.         scanf("%d%d%d",&R,&G,&B);  
  187.         printf("Please input the thickness of the Line(1~4):\n");  
  188.         scanf("%d",&thickness);  
  189.         if(thickness<1)  
  190.             thickness=1;  
  191.         else if(thickness>4)  
  192.             thickness=4;  
  193.         //画线  
  194.         Bresenham(imgA,x1,y1,x2,y2,RGB,thickness);  
  195.         //加粗  
  196.         drawThickness(imgA,x1,y1,x2,y2,RGB,thickness);  
  197.         cvShowImage ("window", imgA);  
  198.         cvWaitKey (50);  
  199.     }  
  200.   
  201.   
  202.     cvReleaseImage (&imgA);  
  203.     cvDestroyWindow ("window");  
  204.   
  205.     return 0;  
  206. }  



程序运行,首先输入两个端点坐标(x1,y1) (x2,y2),然后输入RGB 三原色的值(0~255)之间,最后是线条粗细程度。
其实粗细程度也有专门的算法,不过不在本文讨论范围之内,我只是在原先基础上画了几条平行线。


给个程序运行截图:

图形学实验一:bresenham算法 画线和画圆



二:画圆
先给出bresenham画圆算法的博客: 
http://blog.163.com/wind_58335351/blog/static/16466202200999113828597/
非常详细,一看就懂!

贴上我的代码,根据用户输入的圆心坐标,半径,RGB,粗细,然后画圆。

粗细实现的方法是:半径加长或缩短一定长度,接着画圆。

[cpp]  view plain copy
  1. #include  <cv.h>  
  2. #include  <highgui.h>  
  3. #include  <cxcore.h>  
  4. #include  <iostream>  
  5. #include  <cmath>  
  6. #define RGB R,G,B  
  7. #define SIZE 500  
  8. using namespace std;  
  9. /* 
  10. Bresenham算法画圆 
  11. 算法参考链接: 
  12. http://blog.163.com/wind_58335351/blog/static/16466202200999113828597/ 
  13.  
  14. */  
  15.   
  16.   
  17. void drawPoint(IplImage *imgA,int x,int y,int R,int G,int B){  
  18.     imgA->imageData[y * imgA->widthStep + x * 3] = (signed char) R;  
  19.     imgA->imageData[y * imgA->widthStep + x * 3 + 1] = (signed char) G;  
  20.     imgA->imageData[y * imgA->widthStep + x * 3 + 2] = (signed char) B;  
  21. }  
  22. //判断是否在窗口内部  
  23. bool isInside(int a,int b){  
  24.     if(a>0 && b>0 && a<SIZE &&b<SIZE)  
  25.         return true;  
  26.     else  
  27.         return false;  
  28. }  
  29. //八个方向对称  
  30. void drawEightPoints(IplImage *imgA,int xi,int yi,int x0,int y0,int r,int R,int G,int B,int thickness){  
  31.     int dirxy[4][2]={{1,1},{1,-1},{-1,-1},{-1,1}};  
  32.     int diryx[4][2]={{1,1},{1,-1},{-1,-1},{-1,1}};  
  33.     int dir[4][2]={{1,0},{0,-1},{-1,0},{0,1}};  
  34.     int a,b;  
  35.     int a0,b0,a1,b1;  
  36.     for(int i=0;i<4;i++){  
  37.         a=x0+dirxy[i][0]*xi;  
  38.         b=y0+dirxy[i][1]*yi;  
  39.         if(isInside(a,b)){  
  40.             drawPoint(imgA,a,b,RGB);  
  41.         }  
  42.     }  
  43.     for(int i=0;i<4;i++){  
  44.         a=x0+diryx[i][0]*yi;  
  45.         b=y0+diryx[i][1]*xi;  
  46.         if(isInside(a,b)){  
  47.             drawPoint(imgA,a,b,RGB);  
  48.         }  
  49.     }  
  50.   
  51. }  
  52. /* 
  53. 只要计算出第七象限的圆弧坐标,其余通过对称即可。 
  54. 注意这里画第七象限就是对应一般坐标系的第二象限,因为y轴是向下增大的 
  55. */  
  56. void drawCircle(IplImage *imgA,int x0,int y0,int r,int R,int G,int B,int thickness){  
  57.     int xi=0,yi=r;  
  58.     int e=1-r;  
  59.     //double c=-0.25;  
  60.     while(xi<=yi){  
  61.         drawEightPoints(imgA,xi,yi,x0,y0,r,RGB,thickness);  
  62.         if(e<0){  
  63.             e+=(xi<<1)+3;  
  64.         }  
  65.         else{  
  66.             e+=((xi-yi)<<1)+5;  
  67.             yi--;  
  68.         }  
  69.         xi++;  
  70.     }  
  71. }  
  72.   
  73. void judge(int &R,int &G,int &B){  
  74.     bool flag=false;  
  75.     if(R<0){  
  76.         R=0;  
  77.         flag=true;  
  78.     }  
  79.     if(G<0){  
  80.         G=0;  
  81.         flag=true;  
  82.     }  
  83.     if(B<0){  
  84.         B=0;  
  85.         flag=true;  
  86.     }  
  87.     if(R>255){  
  88.         R=255;  
  89.         flag=true;  
  90.     }  
  91.     if(G>255){  
  92.         G=255;  
  93.         flag=true;  
  94.     }  
  95.     if(B>255){  
  96.         B=255;  
  97.         flag=true;  
  98.     }  
  99.     printf("The value is wrong, we change it to: %d %d %d\n",R,G,B);  
  100. }  
  101.   
  102. int main (int argc, char *argv[]) {  
  103.     int r,x0,y0,e;  
  104.     int R,G,B;  
  105.     int thickness=1;  
  106.     //建立窗口  
  107.     CvSize window = { SIZE, SIZE };  
  108.     IplImage *imgA = cvCreateImage (window, IPL_DEPTH_8U, 3);  
  109.     cvSet (imgA, cvScalarAll (0), 0);  
  110.   
  111.     cvNamedWindow ("window", CV_WINDOW_AUTOSIZE);  
  112.     while(true) {  
  113.         printf("Please input the coordinate of center(if the point are (-1,-1),the program exits):\n");  
  114.         scanf("%d%d",&x0,&y0);  
  115.         if(x0==-1 && y0==-1) {  
  116.             break;  
  117.         }  
  118.         printf("The radius of the circle:\n");  
  119.         scanf("%d",&r);  
  120.         e=1-r;  
  121.         printf("Please input the color(R,G,B):\n");  
  122.         scanf("%d%d%d",&R,&G,&B);  
  123.         judge(R,G,B);  
  124.   
  125.         printf("Please input the thickness of the Line(1~5):\n");  
  126.         scanf("%d",&thickness);  
  127.         if(thickness<1)  
  128.             thickness=1;  
  129.         else if(thickness>5)  
  130.             thickness=3;  
  131.         drawCircle(imgA,x0,y0,r,RGB,thickness);  
  132.         //增加厚度  
  133.         for(int i=1;i<=(thickness+1)/2;i++)  
  134.             drawCircle(imgA,x0,y0,r+i,RGB,thickness);  
  135.         for(int i=1;i<=thickness/2;i++)  
  136.             drawCircle(imgA,x0,y0,r-i,RGB,thickness);  
  137.   
  138.         cvShowImage ("window", imgA);  
  139.         cvWaitKey (50);  
  140.     }  
  141.   
  142.   
  143.     cvReleaseImage (&imgA);  
  144.     cvDestroyWindow ("window");  
  145.   
  146.     return 0;  
  147. }  

再贴个运行测试的截图:

图形学实验一:bresenham算法 画线和画圆