先贴一段毛星云大神的一段代码。
#include <opencv2/opencv.hpp>
using namespace cv;
// 描述:定义一些辅助宏
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
// 描述:全局函数的声明
void on_MouseHandle(int event, int x, int y, int flags, void* param);
// 鼠标函数的第一个参数是说明鼠标的事件;flags是CV_EVENT_FLAG的组合;
//x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系);param 用户定义的传递到回调函数的参数
void DrawRectangle( cv::Mat& img, cv::Rect box ); //用于矩形框的绘制
// 描述:全局变量的声明
Rect g_rectangle;
bool g_bDrawingBox = false;//是否进行绘制
RNG g_rng(12345); //定义一个随机函数对象;
//------【main( )函数】---
int main( int argc, char** argv )
{
//【1】准备参数
g_rectangle = Rect(-1,-1,0,0);//初始化g_rectangle;
Mat srcImage(600, 800,CV_8UC3), tempImage;//定义并初始化矩阵(图像)srcImage,长宽分别为600*800;CV_8UC3表示存储类型,3表示通道数;
srcImage.copyTo(tempImage); //将srcImage复制给临时图像tempImage;
srcImage = Scalar::all(255);
//【2】设置鼠标操作回调函数
namedWindow( WINDOW_NAME );
setMouseCallback(WINDOW_NAME,on_MouseHandle,(void*)&srcImage);
//【3】程序主循环,当进行绘制的标识符为真时,进行绘制
while(1)
{
srcImage.copyTo(tempImage);//拷贝源图到临时变量
if( g_bDrawingBox )
DrawRectangle( tempImage, g_rectangle );//当进行绘制的标识符为真,则进行绘制
imshow( WINDOW_NAME, tempImage );
if( waitKey( 10 ) == 27 ) break;//按下ESC键,程序退出
}
return 0;
}
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
Mat& image = *(cv::Mat*) param;
switch( event)
{
//鼠标移动消息
case EVENT_MOUSEMOVE:
{
if( g_bDrawingBox )//如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
//鼠标移动的过程中鼠标的坐标(x,y)是在不断的改变的;
g_rectangle.width = x-g_rectangle.x;
g_rectangle.height = y-g_rectangle.y;
}
}
break;
//左键按下消息
case EVENT_LBUTTONDOWN:
{
g_bDrawingBox = true;
g_rectangle =Rect( x, y, 0, 0 );//记录起始点
}
break;
//左键抬起消息
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;//置标识符为false
//对宽和高小于0的处理
//如果鼠标是向左移动,则将最后生成的矩形的左上角的点作为新的g_rectangle.x和g_rectangle.y;
if( g_rectangle.width < 0 )
{
g_rectangle.x += g_rectangle.width;
g_rectangle.width *= -1;
}
if( g_rectangle.height < 0 )
{
g_rectangle.y += g_rectangle.height;
g_rectangle.height *= -1;
}
//调用函数进行绘制
DrawRectangle( image, g_rectangle );
}
break;
}
}
void DrawRectangle( cv::Mat& img, cv::Rect box )
{
cv::rectangle(img,box.tl(),box.br(),cv::Scalar(g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255)));//随机颜色
}
//-----------------------------------【DrawRectangle( )函数】----------------------------
void DrawRectangle( cv::Mat& img, cv::Rect box )
{
cv::rectangle(img,box.tl(),box.br(),cv::Scalar(g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255)));//随机颜色
}
每段代码后面我都做了一个简短的参数说明。这里主要总结几小点:
1.void on_MouseHandle(int event, int x, int y, int flags, void* param);
// 鼠标函数的第一个参数是说明鼠标的事件;flags是CV_EVENT_FLAG的组合;
x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系);
flags是EVENT_FLAG的组合;
param 用户定义的传递到回调函数(SetMouseCallback)的参数;
2. RNG g_rng(12345);
RNG( )函数的作用为初始化随机数状态的生成器;
将src复制到dst矩阵中;相当于Mat dst=src.clone( ) ;
3. srcImage.copyTo(tempImage)
【1】使用Mat( )构造函数
Mat M(2,2,CV_8UC3,Scalar(0,0,255));
参数:
1)行数和列数;
2)存储元素的数据类型以及每个矩阵点的通道数;CV_8UC3表示使用8位的unsigned char型,每个元素由三个元素组成三通道。
3)Scalar是个short型的向量,能够用指定的定制化的值来初始化矩阵,还可以用于表示颜色。
【2】在C/C++中通过构造函数进行初始化
int sz[3]={2,2,2};
Mat L(3,sz,CV_8UC,Scalar::all(0));
参数:
L()函数中的第一个参数3表示维数;
sz表示指针数组,它包含了每个维度的尺寸;
同样,CV_8UC3表示使用8位的unsigned char型,每个元素由三个元素组成三通道。
Scalar是个short型的向量,能够用指定的定制化的值来初始化矩阵,还可以用于表示颜色。
【3】利用Create( )函数进行Mat类的初始化操作;
5、opencv中的格式化输出方法;
(1)opencv默认风格
cout<<”r (opencv默认风格) =”<< r<<”;”<< endl<< endl;
(2)python分隔风格
cout<<”r (python 风格) =“<< format(r,Formatter::FMT_PYTHON)<< “;”<< endl<< endl;
(3)逗号分隔风格
cout<<”r (逗号 风格) =“<< format(r,Formatter::FMT_CSV)<<”;”<< endl<< endl;
Numpy分隔分隔和C语言风格都是同理 ,相应的换成Formatter::FMT_NUMPY和Formatter::FMT_C就可以了;