注明:本博客中所有文章均可转载,但请给出链接!!!
由于画线、画圆,需要在专门的窗口上,因为设计像素点,一般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互换一下即可。否则话会出现如下图所示的情况。
再给出一个我参考的代码实现的博客,此博客两种情况均考虑了:
http://www.xuebuyuan.com/345229.html
看了上面两个博客,基本上对画线就有一定了解了。下面给出我的代码:
- #include <cv.h>
- #include <highgui.h>
- #include <cxcore.h>
- #include <iostream>
- #include <cmath>
- #define RGB R,G,B
- #define SIZE 500
- using namespace std;
- /*
- 算法参考链接:
- http://www.jhmcu.com/lcd-hua-zhi-xian-zhi-bresenham-suan-fa/
- 链接上只给出了|dx|>=|dy|的情况,应该要综合考虑dx>dy和dy>dx两种情况
- */
- //判断是否在窗口内部
- bool isInside(int a,int b){
- if(a>0 && b>0 && a<SIZE &&b<SIZE)
- return true;
- else
- return false;
- }
- //画点
- void drawPoint(IplImage *imgA,int x,int y,int R,int G,int B) {
- imgA->imageData[y * imgA->widthStep + x * 3] = (signed char) R;
- imgA->imageData[y * imgA->widthStep + x * 3 + 1] = (signed char) G;
- imgA->imageData[y * imgA->widthStep + x * 3 + 2] = (signed char) B;
- }
- /**
- 起始点:(x1,y1)
- 终点:(x2,y2)
- 颜色R,G,B
- */
- void Bresenham(IplImage *imgA,int x1,int y1,int x2,int y2,int R,int G,int B,int thickness) {
- int dx, dy;//横轴纵轴差量
- int e;
- int x, y;
- dx = abs (x2 - x1);
- dy = abs (y2 - y1);
- y = y1;
- x = x1;
- int cx, cy;//表明x、y方向的增量
- if (x1 > x2) {
- cx = -1;//x递减方向
- } else {
- cx = 1;//x递增方向
- }
- if (y1 > y2) {
- cy = -1;//y递减方向
- } else {
- cy = 1;//y递增方向
- }
- if(dx==0 && dy==0) {
- printf("The input is not a line. It is just a point. Please input two different points.!\n");
- } else if(dy==0) {
- for(x=x1; (cx ==1 ? x <= x2 : x >= x2); x+=cx) {
- if(isInside(x,y))
- drawPoint(imgA,x,y,RGB);
- for(int i=1; i<=thickness; i++) {
- if(isInside(x,y+i))
- drawPoint(imgA,x,y+i,RGB);
- }
- }
- } else if(dx==0) {
- for (y = y1; (cy ==1 ? y <= y2 : y >= y2); y += cy) {
- if(isInside(x,y))
- drawPoint(imgA,x,y,RGB);
- for(int i=1; i<=thickness; i++) {
- if(isInside(x+i,y))
- drawPoint(imgA,x+i,y,RGB);
- }
- }
- } else if(dx>=dy) {
- e=-dx;
- for (x = x1; (cx ==1 ? x <= x2 : x >= x2); x += cx) {
- if(isInside(x,y))
- drawPoint(imgA,x,y,RGB);
- e+=dy<<1;
- if (e>0) {
- y += cy;
- e -= dx<<1;
- }
- }
- } else {
- e=-dy;
- for (y = y1; (cy >= 0 ? y <= y2 : y >= y2); y += cy) {
- if(isInside(x,y))
- drawPoint(imgA,x,y,RGB);
- e+=dx<<1;
- if (e>0) {
- x += cx;
- e -= dy<<1;
- }
- }
- }
- }
- //加粗
- void drawThickness(IplImage *imgA,int x1,int y1,int x2,int y2,int R,int G,int B,int thickness) {
- int dy=y2-y1;
- int dx=x2-x1;
- /*
- 四个象限加粗方向不同
- */
- int dir1[4][2][2]={{{-1,-1},{1,1}},{{-1,1},{1,-1}},{{1,1},{-1,-1}},{{-1,1},{1,-1}}};
- int a1,a2,b1,b2;
- if(dx>0 && dy<0) {
- for(int i=1; i<=(thickness+1)/2; i++) {
- a1=x1+i*dir1[0][0][0];
- b1=y1+i*dir1[0][0][1];
- a2=x2+i*dir1[0][0][0];
- b2=y2+i*dir1[0][0][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- for(int i=1; i<=(thickness)/2; i++) {
- a1=x1+i*dir1[0][1][0];
- b1=y1+i*dir1[0][1][1];
- a2=x2+i*dir1[0][1][0];
- b2=y2+i*dir1[0][1][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- } else if(dx<0 && dy<0){
- for(int i=1; i<=(thickness+1)/2; i++) {
- a1=x1+i*dir1[1][0][0];
- b1=y1+i*dir1[1][0][1];
- a2=x2+i*dir1[1][0][0];
- b2=y2+i*dir1[1][0][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- for(int i=1; i<=(thickness)/2; i++) {
- a1=x1+i*dir1[1][1][0];
- b1=y1+i*dir1[1][1][1];
- a2=x2+i*dir1[1][1][0];
- b2=y2+i*dir1[1][1][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- }
- else if(dx<0&&dy>0){
- for(int i=1; i<=(thickness+1)/2; i++) {
- a1=x1+i*dir1[2][0][0];
- b1=y1+i*dir1[2][0][1];
- a2=x2+i*dir1[2][0][0];
- b2=y2+i*dir1[2][0][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- for(int i=1; i<=(thickness)/2; i++) {
- a1=x1+i*dir1[2][1][0];
- b1=y1+i*dir1[2][1][1];
- a2=x2+i*dir1[2][1][0];
- b2=y2+i*dir1[2][1][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- }
- else if(dx>0&&dy>0){
- for(int i=1; i<=(thickness+1)/2; i++) {
- a1=x1+i*dir1[3][0][0];
- b1=y1+i*dir1[3][0][1];
- a2=x2+i*dir1[3][0][0];
- b2=y2+i*dir1[3][0][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- for(int i=1; i<=(thickness)/2; i++) {
- a1=x1+i*dir1[3][1][0];
- b1=y1+i*dir1[3][1][1];
- a2=x2+i*dir1[3][1][0];
- b2=y2+i*dir1[3][1][1];
- Bresenham(imgA,a1,b1,a2,b2,RGB,thickness);
- }
- }
- }
- int main (int argc, char *argv[]) {
- int x1,x2,y1,y2;
- int R,G,B;
- int thickness=1;
- CvSize window = { SIZE, SIZE };
- IplImage *imgA = cvCreateImage (window, IPL_DEPTH_8U, 3);
- cvSet (imgA, cvScalarAll (0), 0);
- cvNamedWindow ("window", CV_WINDOW_AUTOSIZE);
- while(true) {
- printf("Please input coordinates of two points(if both points are (0,0),the program exits):\n");
- scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
- if(x1==0 && y1==0 && x2==0 && y2==0) {
- break;
- }
- printf("Please input the color(R,G,B):\n");
- scanf("%d%d%d",&R,&G,&B);
- printf("Please input the thickness of the Line(1~4):\n");
- scanf("%d",&thickness);
- if(thickness<1)
- thickness=1;
- else if(thickness>4)
- thickness=4;
- //画线
- Bresenham(imgA,x1,y1,x2,y2,RGB,thickness);
- //加粗
- drawThickness(imgA,x1,y1,x2,y2,RGB,thickness);
- cvShowImage ("window", imgA);
- cvWaitKey (50);
- }
- cvReleaseImage (&imgA);
- cvDestroyWindow ("window");
- return 0;
- }
程序运行,首先输入两个端点坐标(x1,y1) (x2,y2),然后输入RGB 三原色的值(0~255)之间,最后是线条粗细程度。
其实粗细程度也有专门的算法,不过不在本文讨论范围之内,我只是在原先基础上画了几条平行线。
给个程序运行截图:
二:画圆
先给出bresenham画圆算法的博客:
http://blog.163.com/wind_58335351/blog/static/16466202200999113828597/
非常详细,一看就懂!
贴上我的代码,根据用户输入的圆心坐标,半径,RGB,粗细,然后画圆。
粗细实现的方法是:半径加长或缩短一定长度,接着画圆。
- #include <cv.h>
- #include <highgui.h>
- #include <cxcore.h>
- #include <iostream>
- #include <cmath>
- #define RGB R,G,B
- #define SIZE 500
- using namespace std;
- /*
- Bresenham算法画圆
- 算法参考链接:
- http://blog.163.com/wind_58335351/blog/static/16466202200999113828597/
- */
- void drawPoint(IplImage *imgA,int x,int y,int R,int G,int B){
- imgA->imageData[y * imgA->widthStep + x * 3] = (signed char) R;
- imgA->imageData[y * imgA->widthStep + x * 3 + 1] = (signed char) G;
- imgA->imageData[y * imgA->widthStep + x * 3 + 2] = (signed char) B;
- }
- //判断是否在窗口内部
- bool isInside(int a,int b){
- if(a>0 && b>0 && a<SIZE &&b<SIZE)
- return true;
- else
- return false;
- }
- //八个方向对称
- void drawEightPoints(IplImage *imgA,int xi,int yi,int x0,int y0,int r,int R,int G,int B,int thickness){
- int dirxy[4][2]={{1,1},{1,-1},{-1,-1},{-1,1}};
- int diryx[4][2]={{1,1},{1,-1},{-1,-1},{-1,1}};
- int dir[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
- int a,b;
- int a0,b0,a1,b1;
- for(int i=0;i<4;i++){
- a=x0+dirxy[i][0]*xi;
- b=y0+dirxy[i][1]*yi;
- if(isInside(a,b)){
- drawPoint(imgA,a,b,RGB);
- }
- }
- for(int i=0;i<4;i++){
- a=x0+diryx[i][0]*yi;
- b=y0+diryx[i][1]*xi;
- if(isInside(a,b)){
- drawPoint(imgA,a,b,RGB);
- }
- }
- }
- /*
- 只要计算出第七象限的圆弧坐标,其余通过对称即可。
- 注意这里画第七象限就是对应一般坐标系的第二象限,因为y轴是向下增大的
- */
- void drawCircle(IplImage *imgA,int x0,int y0,int r,int R,int G,int B,int thickness){
- int xi=0,yi=r;
- int e=1-r;
- //double c=-0.25;
- while(xi<=yi){
- drawEightPoints(imgA,xi,yi,x0,y0,r,RGB,thickness);
- if(e<0){
- e+=(xi<<1)+3;
- }
- else{
- e+=((xi-yi)<<1)+5;
- yi--;
- }
- xi++;
- }
- }
- void judge(int &R,int &G,int &B){
- bool flag=false;
- if(R<0){
- R=0;
- flag=true;
- }
- if(G<0){
- G=0;
- flag=true;
- }
- if(B<0){
- B=0;
- flag=true;
- }
- if(R>255){
- R=255;
- flag=true;
- }
- if(G>255){
- G=255;
- flag=true;
- }
- if(B>255){
- B=255;
- flag=true;
- }
- printf("The value is wrong, we change it to: %d %d %d\n",R,G,B);
- }
- int main (int argc, char *argv[]) {
- int r,x0,y0,e;
- int R,G,B;
- int thickness=1;
- //建立窗口
- CvSize window = { SIZE, SIZE };
- IplImage *imgA = cvCreateImage (window, IPL_DEPTH_8U, 3);
- cvSet (imgA, cvScalarAll (0), 0);
- cvNamedWindow ("window", CV_WINDOW_AUTOSIZE);
- while(true) {
- printf("Please input the coordinate of center(if the point are (-1,-1),the program exits):\n");
- scanf("%d%d",&x0,&y0);
- if(x0==-1 && y0==-1) {
- break;
- }
- printf("The radius of the circle:\n");
- scanf("%d",&r);
- e=1-r;
- printf("Please input the color(R,G,B):\n");
- scanf("%d%d%d",&R,&G,&B);
- judge(R,G,B);
- printf("Please input the thickness of the Line(1~5):\n");
- scanf("%d",&thickness);
- if(thickness<1)
- thickness=1;
- else if(thickness>5)
- thickness=3;
- drawCircle(imgA,x0,y0,r,RGB,thickness);
- //增加厚度
- for(int i=1;i<=(thickness+1)/2;i++)
- drawCircle(imgA,x0,y0,r+i,RGB,thickness);
- for(int i=1;i<=thickness/2;i++)
- drawCircle(imgA,x0,y0,r-i,RGB,thickness);
- cvShowImage ("window", imgA);
- cvWaitKey (50);
- }
- cvReleaseImage (&imgA);
- cvDestroyWindow ("window");
- return 0;
- }
再贴个运行测试的截图: