认识画图函数
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
//#include<iostream>
#define w 400
using namespace cv;
/*
大量使用 Point 和 Scalar 这两个结构:
Point数据结构表示了由其图像坐标 x 和 y 指定的2D点;
也可以用Point2f表示坐标由浮点数表示。
Scalar是一个由长度为4的数组作为元素构成的结构体,Scalar最多可以存储四个值,没有提供的值默认是0;
此类型在OpenCV中被大量用于传递像素值,如用它来表示RGB颜色值(三个参数):
Scalar( a, b, c ),那么定义的RGB颜色值为: Red = c, Green = b and Blue = a
*/
/// Function Declaration
void MyEllipse(Mat img, double angle)
{
int thickness = 2;
int lineType = 8;//线形为8连通线型
ellipse(img,
Point(int(w / 2.0), int(w / 2.0)),//中心点
Size(w / 4, w / 16),//大小
angle,//椭圆旋转角度
0,//扩展弧度起始点
360,//终点
Scalar(255, 0, 0), //使用Scalar类型数据设置color
thickness,
lineType);
}
//void MyFilledCircle(Mat img, Point2f center);
void MyFilledCircle(Mat img, Point2f center)
{
int thickness = -1; //封闭曲线,则要填充图像
int lineType = 8;
circle(img,
center,
w / 32,
Scalar(0, 0, 255), //设置color
thickness,
lineType);
}
int main(int argc, char **argv)
{
/// Windows names
char atom_window[] = "Drawing 1: Atom";
/// Create black empty images
Mat atom_image = Mat::zeros(w, w, CV_8UC3);
//创建Mat类的对象atom_image,使用Mat类的zeros方法
//参数CV_8UC3表示unsigned 8 bits,3通道(Channels)
/// 1. Draw a simple atom:
/// -----------------------
/// 1.a. Creating ellipses
MyEllipse(atom_image, 90);
MyEllipse(atom_image, 0);
MyEllipse(atom_image, 45);
MyEllipse(atom_image, -45);
/// 1.b. Creating circles
MyFilledCircle(atom_image, Point2f(w / 2.0, w / 2.0));
//PointF,由于这里(System.Drawing)的“点”设计用于屏幕显示用,
//而屏幕显示以像素为单位,一般使用整数形式的Point就足够了
/// 2. Display your stuff!
imshow(atom_window, atom_image);
imwrite("C:\\Users\\77607\\Desktop\\atom_image.jpg", atom_image);
//需要将opencv*.dll拷贝一份放在和exe相同文件夹下
waitKey(0);
return(0);
}
使用鼠标当画笔画图
目标:
- 学习使用OpenCV处理鼠标事件
- 学习函数:cv::setMouseCallback()
void setMousecallback(const string& winname, MouseCallback onMouse, void* userdata=0)
winname:窗口的名字
onMouse:鼠标响应函数,回调函数。指定窗口里每次鼠标时间发生的时候,被调用的函数指针。 这个函数的原型应该为void on_Mouse(int event, int x, int y, int flags, void* param);
userdate:传给回调函数的参数
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui_c.h>
#include<opencv2\opencv.hpp>
#include<opencv2\imgproc\imgproc.hpp>
using namespace cv;
char *window_name = "image";
// mouse callback function
void draw_circle(int event, int x, int y, int flags, void* param);
int main()
{
Mat img = Mat::zeros(512, 512, CV_8UC3);
namedWindow(window_name);
imshow(window_name, img);
setMouseCallback(window_name, draw_circle, (void*)&img);
while (1)
{
if (cvWaitKey(20))
break;
}
waitKey(0);
return 0;
}
void draw_circle(int event, int x, int y, int flags, void* param)
{
Mat depth_img = *(Mat*)param; // 先转换类型,再取数据
if (event == CV_EVENT_LBUTTONDBLCLK)//位于highgui_c.h
{
circle(depth_img, cvPoint(x, y), 100, CV_RGB(0, 0, 255), -1);
imshow(window_name, depth_img);
}
}
可以通过鼠标输入改变绘图模式
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui_c.h>
#include<opencv2\opencv.hpp>
#include<opencv2\imgproc\imgproc.hpp>
using namespace cv;
char *window_name = "test";
bool mode = true;
void drawByMouse(int event, int x, int y, int flags, void *param);
int main(int argc, char* argv[])
{
Mat img = Mat::zeros(800, 600, CV_8UC3);
namedWindow(window_name);
imshow(window_name, img);
setMouseCallback(window_name, drawByMouse, (void*)&img);
while (1)
{
//imshow(window_name, img);
int k = cvWaitKey(1);
if (k == 'm')
mode = !mode;
else if (k == 27)
break;
}
waitKey(0);
return 0;
}
void drawByMouse(int event, int x, int y, int flags, void *param)
{
Mat depth_img = *(Mat*)param; // 先转换类型,再取数据
static CvPoint point_start, point_end;
static bool draw_flag = false;
switch (event)
{
case CV_EVENT_LBUTTONDOWN://位于highgui_c.h
{
draw_flag = true;
point_start = cvPoint(x, y);
break;
}
case CV_EVENT_LBUTTONUP:
{
draw_flag = false;
break;
}
case CV_EVENT_MOUSEMOVE:
{
if (draw_flag == true)
if (mode == true)
{
point_end = cvPoint(x, y);
rectangle(depth_img, point_start, point_end, CV_RGB(0, 255, 0), -1);
imshow(window_name, depth_img);
}
else
{
circle(depth_img, cvPoint(x, y), 3, CV_RGB(0, 0, 255), -1);
imshow(window_name, depth_img);
}
}
}
}
生产非填充的矩形
//#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui_c.h>
//#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace cv;
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
//c和c++中允许用一个标识符来表示一个字符串,称为“宏”
/*****************鼠标操作*****************/
Rect g_rect;
//Recg类用于创建一个矩形对象,矩形左上角的横坐标、纵坐标以及矩形的宽度、高度均为零。
bool g_DrawFlag = false;
RNG g_rng(12345);
//RNG类是opencv里C++的随机数产生器。它可产生一个64位的int随机数。
//RNG可以产生3种随机数
//RNG(int seed) 使用种子seed产生一个64位随机整数,默认 - 1
//计算机产生的随机数都是伪随机数,是根据种子seed和特定算法计算出来的。
//所以,只要种子一定,算法一定,产生的随机数是相同的
//RNG::uniform() 产生一个均匀分布的随机数
//RNG::gaussian() 产生一个高斯分布的随机数
void on_MouseHandle(int event, int x, int y, int flag, void* param);
void DrawRectangle(Mat& img, Rect box);
void main()
{
//准备参数
g_rect = Rect(-1, -1, 0, 0);
Mat srcImage(600, 600, CV_8UC3), tempImage;
srcImage.copyTo(tempImage);
//image.copyTo(imageROI)。作用是把image的内容复制粘贴到imageROI上
//g_rect = Rect(-1, -1, 0, 0);
srcImage = Scalar::all(0);
//设置鼠标操作回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImage);
//绘画
while (1)
{
srcImage.copyTo(tempImage);
if (g_DrawFlag)
{
DrawRectangle(tempImage, g_rect);
}
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27)
break;//ESC 退出
}
}
//鼠标回调事件
void on_MouseHandle(int event, int x, int y, int flag, void* param)
{
Mat& image = *(Mat*)param;
switch (event)
{
case EVENT_MOUSEMOVE://移动
if (g_DrawFlag)
{
//计算,g_rect宽高=鼠标当前位置坐标-g_rect左上角的坐标
g_rect.width = x - g_rect.x;
g_rect.height = y - g_rect.y;
}
break;
case EVENT_LBUTTONDOWN://左键按下
g_DrawFlag = true;
//设置g_rect的初始值在同一个点
g_rect = Rect(x, y, 0, 0);
break;
case EVENT_LBUTTONUP://左键抬起
//在画填充矩形的程序中,鼠标移动时开始画,非填充矩形是左键抬起开始画
g_DrawFlag = false;
//当g_rect宽高小于0
//起始点xy坐标置为较小靠左上角的点
//宽高取绝对值
if (g_rect.width < 0)
{
g_rect.x += g_rect.width;
g_rect.width *= -1;
}
if (g_rect.height < 0)
{
g_rect.y += g_rect.height;
g_rect.height *= -1;
}
//画矩形
DrawRectangle(image, g_rect);
break;
}
}
//矩形绘制函数
void DrawRectangle(Mat& img, Rect box)
{
//rectangle画矩形
//tl左上角的点,br右下角的点
//Scalar设置颜色,设置为3通道
//g_rng.uniform(0, 255)随机颜色
rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255),
g_rng.uniform(0, 255), g_rng.uniform(0, 255)));
//box.tl(); //返回box的左上顶点的坐标
//box.br(); //返回box的右下顶点的坐标
}