《学习OpenCV》第四章第5题

创建一个程序,可以新建一个图像,并将图像所有像素值设置为0,然后将其显示出来。允许用户通过鼠标左键画线、矩形、圆、椭圆以及多边形。并使其能在右击鼠标时,实现橡皮擦功能。

#include<iostream>
#include"highgui.h"
#include"cv.h"
using namespace std;
using namespace cv;
#define WIDTH 512
#define HEIGHT  512

//用来记录多边形的每个点
typedef struct Node {
    CvPoint p;
    Node *next;
}Node;

CvPoint point_start;    //建一个全体量,用来作为各个图形的开始点
CvPoint point_end;  //建一个全体量,用来作为各个图形的结束点
int g_rnd, r_rnd, b_rnd;    //颜色RGB三值随机变量
IplImage *img = cvCreateImage(cvSize(WIDTH, HEIGHT), 8, 3);     //建一个图片,在其上进行画图操作
IplImage *img_copy = cvCreateImage(cvSize(WIDTH, HEIGHT), 8, 3);    //建一个图片,用来储存前一步画好后的图片img
char flag;  //建一个标志,确定当前状态
int flagmove = 0;   //用来判断是否按过左键,来决定移动鼠标是否有响应
int flagstart = 1;  //或多边形操作时,判断是否是第一个点
CvPoint** ps = (CvPoint**)malloc(sizeof(CvPoint*)); //用来存放多边形顶点的二维CvPoint数组
Node *head, *pnode; //Node类型节点,存放顶点数据
int count1 = 0; //记录多边形顶点个数
int a[1];   //存放count1

//先介绍画图操作
void introduce() {
    cout << "按下L键,开始画直线" << endl;
    cout << "按下R键,开始画矩形" << endl;
    cout << "按下C键,开始画圆" << endl;
    cout << "按下E键,开始画椭圆" << endl;
    cout << "按下P键,开始画多边形(按下左键确定顶点,之后右键完成多边形)" << endl;
    cout << "右键清除" << endl;
}

//随机获得一个颜色画图
void getColor() {

    r_rnd = (int)(rand()) % 256;
    b_rnd = (int)(rand()) % 256;
    g_rnd = (int)(rand()) % 256;
}

//画线函数
void drawLine() {
    cvLine(img, point_start, point_end, CV_RGB(r_rnd, g_rnd, b_rnd),2);
}

//画矩形函数
void drawRectangle() {
    cvRectangle(img, point_start, point_end, CV_RGB(r_rnd, g_rnd, b_rnd),2);
}

//画圆函数
void drawCircle() {
    int x, y, r;

    //避免出现负数
    if (point_start.x < point_end.x)
        x = point_end.x - point_start.x;
    else
        x = point_start.x - point_end.x;

    if (point_start.y < point_end.y)
        y = point_end.y - point_start.y;
    else
        y = point_start.y - point_end.y;
    r = (int)sqrt(x*x + y*y);   //半径
    cvCircle(img, cvPoint(point_start.x / 2 + point_end.x / 2, point_start.y / 2 + point_end.y / 2),
        r, CV_RGB(r_rnd, g_rnd, b_rnd),2);
}

//画椭圆函数
void drawEllipse() {
    int x, y;

    if (point_start.x < point_end.x)
        x = point_end.x - point_start.x;
    else
        x = point_start.x - point_end.x;

    if (point_start.y < point_end.y)
        y = point_end.y - point_start.y;
    else
        y = point_start.y - point_end.y;

    cvEllipse(img, cvPoint(point_start.x / 2 + point_end.x / 2, point_start.y / 2 + point_end.y / 2),
        cvSize(x / 2, y / 2), 0, 0, 360, CV_RGB(r_rnd, g_rnd, b_rnd),2);
}

//画多边形函数
void drawPolygon() {
    int i;
    //取出链表中的数据,放入ps中
    pnode = head;
    ps[0] = (CvPoint*)malloc(sizeof(CvPoint) * count1);
    for (i = 0; pnode != NULL; i++, pnode = pnode->next) {
        ps[0][i] = cvPoint(pnode->p.x, pnode->p.y);
    }
    ps[0][i] = cvPoint(head->p.x, head->p.y);

    cvPolyLine(img, ps, a, 1, 1, CV_RGB(r_rnd, g_rnd, b_rnd),2);
}

//判断当前为何种操作
void draw() {
    if (flag == 'l' || flag == 'L') drawLine();
    else if (flag == 'c' || flag == 'C')    drawCircle();
    else if (flag == 'r' || flag == 'R')    drawRectangle();
    else if (flag == 'e' || flag == 'E')    drawEllipse();
    else if (flag == 'p' || flag == 'P')    drawPolygon();
}
//鼠标响应函数
void on_my_mouse(int event, int x, int y, int flags, void* userdata) {
    //因为多边形操作不同,单独提出
    if (flag == 'p' || flag == 'P')
        switch (event) {
            //每当按下左键,记录下当前坐标,若是起始点,将head复制为pnode,同时计数点值0
            case CV_EVENT_LBUTTONDOWN:  cvCopy(img_copy, img);  if (flagstart) {
                head = new Node;
                pnode = new Node;
                count1 = 0;
                head = pnode;
                getColor();
                point_start = cvPoint(x,y);
                pnode->p.x = x;
                pnode->p.y = y;
                pnode->next = new Node;
                pnode = pnode->next;
                count1++;
            }
                flagmove = 1;
                flagstart = 0;
                break;
            case CV_EVENT_MOUSEMOVE:    if (flagmove) {
                cvCopy(img_copy,img);
                point_end = cvPoint(x, y);
                cvLine(img, point_start, point_end, CV_RGB(r_rnd, g_rnd, b_rnd), 2);
                cvShowImage("test", img);
            }
                break;
            case CV_EVENT_LBUTTONUP:    cvCopy( img,img_copy); point_start = cvPoint(x, y); flagmove = 0;
                pnode->p.x = x;
                pnode->p.y = y;
                pnode->next = new Node;
                pnode = pnode->next;
                count1++; break;
            //按下右键,画出多边形,以及清除功能
            case CV_EVENT_RBUTTONDOWN:  if (pnode == NULL) {
                cvZero(img);
                cvCopy(img, img_copy);
            }
            else {
                pnode->next = NULL; a[0] = count1; draw();
                cvCopy(img, img_copy); flagstart = 1;
            } 
            break;
        }
    //其余的操作响应
    else
        switch (event) {
            //按下左键,记录点坐标到起始点point_start中,并将flagmove值1,代表鼠标移动有响应
            case CV_EVENT_LBUTTONDOWN:  cvCopy(img_copy, img); point_start = cvPoint(x, y);
                getColor(); flagmove = 1; break;
            //flagmove为1时,将鼠标坐标值入结束点point_end中,动态展现当前作图情况
            case CV_EVENT_MOUSEMOVE:    if (flagmove) {
                cvCopy(img_copy, img);
                point_end = cvPoint(x, y);
                draw();
                cvShowImage("test", img);
            }break;
            //抬起左键,flagmove值0,鼠标移动相应结束
            case CV_EVENT_LBUTTONUP:    cvCopy(img, img_copy); flagmove = 0;    break;
            //点击右键,图片清除
            case CV_EVENT_RBUTTONDOWN:  cvZero(img); cvZero(img_copy);  break;
        }
}

int main(void) {
    //初始化造作
    char c;
    cvNamedWindow("test");
    cvZero(img);
    cvZero(img_copy);

    introduce();
    setMouseCallback("test", on_my_mouse);

    while (1) {
        cvShowImage("test", img);
        c = cvWaitKey(30);
        //判断选择的操作情况
        if (c == 'P' || c == 'p' || c == 'C' || c == 'c' || c == 'e' ||
            c == 'E' || c == 'l' || c == 'L' || c == 'R' || c == 'r')
            flag = c;
        if ((int)(c) == 27)
            break;
    }
    return 0;
}

画线:
画线

画矩形:
这里写图片描述

画圆:
这里写图片描述

画椭圆:
这里写图片描述

画多边形:
这里写图片描述

大杂烩:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值