【OpenCV学习笔记】2.4制作绘图板

来源:互联网 发布:魔女之泉3 知乎 编辑:程序博客网 时间:2024/05/17 05:04

学了几天OpenCV,写个小程序把这几天的所得综合实践一下。

一、功能简介

绘图板小程序主要实现以下几个方面功能:
1. 滑动条控制画笔参数(颜色、粗细);
2. 鼠标控制绘图(停顿为实心圆,移动为平滑轨迹);
3. 设置按键功能(重来,保存,退出);
4. 调色盘显示取色。
5. 新增功能:右键漫水填充填色 2015/12/29

1.滑动条控制

设立4个滑动条控制画笔的颜色(B、G、R)和粗细(Thick)

(1)、为画笔颜色、粗细定义全局变量并赋初值

//全局变量double Brush_r = 255.0;double Brush_g = 255.0;double Brush_b = 255.0;int Brush_thick = 5;

(2)、响应滑动条的回调函数

void ON_TRACKBAR_B(int t, void*){//更改蓝色    Brush_b = t;    Brush_color=Scalar(Brush_b,Brush_g,Brush_r);}void ON_TRACKBAR_G(int t, void*){//更改绿色    Brush_g = t;    Brush_color = Scalar(Brush_b, Brush_g, Brush_r);}void ON_TRACKBAR_R(int t, void*){//更改红色    Brush_r = t;    Brush_color = Scalar(Brush_b, Brush_g, Brush_r);//注意颜色为BGR}void ON_TRACKBAR_THICK(int t, void*){//更改画笔粗细    Brush_thick = t;}


2、鼠标控制

响应鼠标的3种事件。

(1)、鼠标左键按下开始绘图

鼠标事件:EVENT_LBUTTONDOWN
动作:改变bool值drawflag表示开始绘图,记录当前坐标Current,并画点(实心圆)circle()

(2)、在左键按下的同时移动鼠标,绘制鼠标移动的轨迹

鼠标事件:EVENT_MOUSEMOVE
动作:识别是否同时左键按下,更新上一个坐标(Pre)和当前坐标(Current),绘制轨迹线line()

(3)、左键抬起停止绘图

鼠标事件:EVENT_LBUTTONUP
动作:改变bool值drawflag表示停止绘图


void ON_MOUSE_HANDLE(int event,int x,int y,int flags,void* param){    Mat& picture = *(Mat *)param;    switch (event)    {    case EVENT_LBUTTONDOWN://左键按下        {            drawflag = 1;            Current=Point(x,y);            circle(picture, Current, Brush_thick/2, Brush_color, -1);//参数依据滑动条改变            break;        }    case EVENT_MOUSEMOVE://鼠标移动        {            if (drawflag){//左键是否为按下状态                Point Pre = Current;                Current = Point(x, y);                line(picture, Pre, Current, Brush_color, Brush_thick);//参数依据滑动条改变            }               break;        }    case EVENT_LBUTTONUP://左键抬起        {            drawflag = 0;            break;        }    }}

新增功能:漫水填充

case EVENT_RBUTTONDOWN:    {        floodFill(picture, Point(x, y), Brush_color);        break;    }

要特别注意每条CASE后的break语句,不然Switch的各种Case会依次执行。


3、调色盘功能

区别“=”和copyTo:

  • “Mat A=B”意味着 A将指向B的同一块内存;
  • “A.copyTo(B)”意味着A的内容复制给了B,B的地址不变。
        Mat platte = tempImage(Rect(0, 0, 50, 50));//调色盘指向的是图像上的左上角矩形区域        Mat temp = Mat(50, 50, CV_8UC3, Scalar(Brush_b, Brush_g, Brush_r));//参数随滑动条变化        temp.copyTo(platte);//只改变调色盘的内容,即改变当前图像左上角矩形区域的颜色      

第3行 不能用 “platte = temp”代替, 它会令调色盘指向了temp


4、按键功能

在程序的主循环中用waitKey()重复获取按键信息,以switch语句判别应该完成的功能,添加按键功能重来,保存,退出功能。

  • waitKey()参数为n表示每等待n毫秒获取按键值一次;但当n为0时,表示无限等待。
  • default项很重要,没有default,当没有输入时,主循环无法继续。
        int c = waitKey(1);//不为0即可        switch (c)        {        case 114://按'r'键 清空绘图板            srcImage.copyTo(tempImage);            imshow(WINDOW_NAME1, tempImage);            break;        case 115://按's'键 save图像            platte.copyTo(temp2);//暂存调色盘            temp = Mat(50, 50, CV_8UC3, Scalar(0, 0,0));            temp.copyTo(platte);            imwrite("……/temp.jpg", tempImage);//保存不显示调色盘的图像            temp2.copyTo(platte);            break;        case 27: //按ESC键,程序退出            loopflag = 0; //退出主循环的控制值            break;        default://未获取以上按键、无按键输入时的操作            break;        }       


二、main函数的写法

#include<opencv2/opencv.hpp>using namespace cv;#define WINDOW_NAME1 "【绘图板】 Press 'r' restart ; Press 's' save ; Press 'Esc' quit . "#define WINDOW_WIDTH 600//全局函数声明void ON_MOUSE_HANDLE(int event, int x, int y, int flags, void* param);void ON_TRACKBAR_B(int t, void*);void ON_TRACKBAR_G(int t, void*);void ON_TRACKBAR_R(int t, void*);//全局变量声明bool drawflag = 0;Point Current;double Brush_r = 255.0;double Brush_g = 255.0;double Brush_b = 255.0;int Brush_thick = 5;String trackbarname_r = "红色值";String trackbarname_g = "绿色值";String trackbarname_b = "蓝色值";String trackbarname_thick = "画笔粗细";Scalar Brush_color = Scalar(255,255,255);//入口函数int main(){    system("color 9F");    Current = Point(0, 0);    Mat srcImage(600, 800, CV_8UC3), tempImage;    srcImage = Scalar(0, 0, 0);    srcImage.copyTo(tempImage);//保护源图    namedWindow(WINDOW_NAME1);      //创建滑动条控件    int threshold_b=255;    createTrackbar(trackbarname_b, WINDOW_NAME1, &threshold_b, 255, ON_TRACKBAR_B);    ON_TRACKBAR_B(threshold_b,0);//响应滑动条的回调函数    int threshold_g=255;    createTrackbar(trackbarname_g, WINDOW_NAME1, &threshold_g, 255, ON_TRACKBAR_G);    ON_TRACKBAR_G(threshold_g, 0);    int threshold_r=255;    createTrackbar(trackbarname_r, WINDOW_NAME1, &threshold_r, 255, ON_TRACKBAR_R);    ON_TRACKBAR_R(threshold_r, 0);    int threshold_thick = 5;    createTrackbar(trackbarname_thick, WINDOW_NAME1, &threshold_thick, 100, ON_TRACKBAR_THICK);    ON_TRACKBAR_THICK(threshold_thick, 0);    //设置鼠标操作回调函数    setMouseCallback(WINDOW_NAME1, ON_MOUSE_HANDLE, (void*)&tempImage);//tempImage是传递到回调函数中的参数param    //程序主循环,当进行绘制的标识符为真时,进行绘制    bool loopflag = 1;    while (loopflag)//    {        Mat platte = tempImage(Rect(0, 0, 50, 50));//将绘图板左上角小块矩形区域创建为调色盘        Mat temp = Mat(50, 50, CV_8UC3, Scalar(Brush_b, Brush_g, Brush_r));        temp.copyTo(platte);        imshow(WINDOW_NAME1, tempImage);        int c = waitKey(1);//获取按键        Mat temp2 = Mat(50, 50, CV_8UC3);//用于暂存调色盘        switch (c)        {        case 114://'r'            srcImage.copyTo(tempImage);            imshow(WINDOW_NAME1, tempImage);            break;        case 115://'s'            platte.copyTo(temp2);//避免保存图像显示调色盘            temp = Mat(50, 50, CV_8UC3, Scalar(0, 0,0));            temp.copyTo(platte);            imwrite("……/temp.jpg", tempImage);            temp2.copyTo(platte);            break;        case 27: //esc            loopflag = 0;             break;//按下ESC键,程序退出        default:            break;        }           }    return 0;   }


三、运行效果

从运行效果一起来看一下绘图板发展:

1、跟随鼠标轨迹

该版本错误的将绘图操作放在了主循环里,每循环一次才画一个点,导致了不连续。并且每个点都是用circle()画空心的圆。
这里写图片描述

2、平滑绘图

改在EVENT_MOUSEMOVE中用line()画极短的线。
这里写图片描述

3、加入颜色调整

该版本缺点是不知道将会出来什么样的颜色。
这里写图片描述

4、设立调色盘

同时优化保存画面时去掉调色盘。
这里写图片描述

5、加入调整粗细

同时调整笔触,落点为实心圆。
这里写图片描述

6、新增:漫水填充

增加右键功能——floodFill填充颜色
这里写图片描述
大功告成!欢迎朋友们指点……

1 0
原创粉丝点击