opencv自学笔记
OpenCV学习笔记二

OpenCV学习笔记(二)五形态学操作形态学操作简单来讲,形态学操作就是基于形状的一系列图像处理操作。
通过将结构元素作用于输入图像来产生输出图像。
最基本的形态学操作有二:腐蚀与膨胀(Erosion 与Dilation)。
他们的运用广泛:消除噪声分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
寻找图像中的明显的极大值区域或极小值区域。
腐蚀操作腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。
它提取的是内核覆盖下的相素最小值。
进行腐蚀操作时,将内核B 划过图像,将内核B 覆盖区域的最小相素值提取,并代替锚点位置的相素。
我们使用腐蚀操作。
从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。
腐蚀操作函数原型:void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )1可以看到前三个是必要的参数,后面都有默认的参数。
InputArray kernel腐蚀操作的内核膨胀操作此操作将图像A 与任意形状的内核(B),通常为正方形或圆形,进行卷积。
内核B 有一个可定义的锚点, 通常定义为内核中心点。
进行膨胀操作时,将内核B 划过图像,将内核B 覆盖区域的最大相素值提取,并代替锚点位置的相素。
显然,这一最大化操作将会导致图像中的亮区开始”扩展”(因此有了术语膨胀dilation )void dilate(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )12开运算(Opening)开运算是通过先对图像腐蚀再膨胀实现的。
opencv3编程入门学习笔记(一):基本函数介绍

opencv3编程⼊门学习笔记(⼀):基本函数介绍滤波blur (均值滤波)均值滤波是典型的线性滤波算法,主要⽅法为领域平均法(即⽤⼀⽚图像区域的各个像素的平均值来代替原图像中的各个像素值)缺点:不能很好的保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从⽽使图像变得模糊。
函数原型:void blur(InputArray src, OutputArrary dst, Size ksize , Point anchor=Point(-1, -1), int borderType = BORDER_DEFAULT)ksize : 核⼤⼩(kerneal size ),有点类似卷积核阈值化阈值可以被视为最简单的图像分割⽅法(基于图像中物体与背景之间的灰度差异)。
为了从图像中提取我们需要的部分,应该⽤图像中的每⼀个像素点的灰度值与选取的阈值进⾏⽐较,并进⾏相应的判断。
⼀旦找到了需要分割的物体的像素点,可以对这些像素点设定⼀些特定的值来表⽰。
可以将物体的像素点的灰度值设为 ”0“ (⿊⾊),其他像素点的灰度值为 ”255“ (⽩⾊)threshold (固定阈值操作)对灰度图像进⾏阈值操作,得到⼆值图像double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)src: 输⼊单通道数组dst: 处理后的结果thresh: 阈值的具体值maxval: 当像素值满⾜条件时,给该像素赋的值type : CV_THRESH_BINARY 、CV_THRESH_BINARY、CV_THRESH_BINARY_INVfindContours(InputArray img, OutputArray conours, OutputArray hierarchy, int mode, int method, Point offset=Point())img: 输⼊图像,需要为8 位单通道图像contours: 每个轮廓为⼀组点向量hierarchy:mode: 轮廓检索模式,。
Opencv学习笔记

Opencv 学习笔记软软件件下下载载:: /projects/opencvlibrary//index.php/Download/一、opencv 模块(主要):CV 主要的OpenCV 函数:图像处理与视觉算法;ML 机器学习、模式分类和回归分析,统计分离器;HighGUI 图像视频输入/出; CXcore 数据结构与线性代数支持,基本函数;二、常用的视频和图像处理:视频处理:以下处理的demo 在 <opencv-root>/samples/c/彩色跟踪 (camshiftdemo );点跟踪 (lkdemo );运动分割 (motempl);边缘检测 (laplace);图像处理: 以下图像的处理demo 在 <opencv-root>/samples/c/边缘检测 (edge);分割 ( pyramid_segmentation);形态学操作 (morphology);直方图 (demhist);距离变换 (distrans);椭圆拟合 (fitellipse);三、命名规则:OpenCV 使用近似匈牙利命名法的方法,比较值得一提的特色是:它的数据结构几乎都 是大写的Cv 开头,而它提供的函数都是小写的cv函数名:cvActionTargetMod(...) 提高了函数的可读性,指明用什么动作,哪个目标,用什么方法Action = 核心功能(core functionality ) (e.g. set, create)Target = 目标图像区域(target image area ) (e.g. contour, polygon)Mod = (可选的)调整语(optional modifiers ) (e.g. argument type)常遇到的状况有四种:1.cvActionTarget() E.g.:cvCreateImage(),cvNamedWindow()2.cvTarget() E.G.: cvMat(),cvSize(),cvPoint()3.cvMethod() E.g.:cvDCT()离散余弦变换算法 常用于算法或某方法4.cvActionMethod() E.g:cvFindContours()轮廓搜寻算法矩阵数据类型:CV_<bit_depth>(S|U|F)C<number_of_channels>Bit_depth = 位数,也叫做深度位数分別有1bit(黑白二值图),8bits,16bits,32bitsNumber_of_channels = 通道数S = 符号整型U = 无符号整型F = 浮点型E.g.: CV_8UC1 是指一个8位无符号整型单通道矩阵,CV_32FC2是指一个32位浮点型双通道矩阵.图像数据类型:IPL_DEPTH_<bit_depth>(S|U|F)E.g.: IPL_DEPTH_8U 图像像素数据是8位无符号整型.IPL_DEPTH_32F图像像素数据是32位浮点型.头文件:#include <cv.h>#include <cvaux.h>#include <highgui.h>#include <ml.h>#include <cxcore.h> // 一般不需要,cv.h 内已包含该头文件四、基础数据结构:CvPoint:OpenCV的基本数据类型之一,表示一个坐标为整数的二维点,是一个包含integer类型成员x和y的简单结构体。
OpenCV学习笔记(基于OpenCV 2.4)一:哈喽CV

原文地址:/archives/2632.htmlOpenCV学习笔记(基于OpenCV 2.4)一:哈喽CV0 写在最前面这份笔记主要记录自己一个简单的学习过程,此过程从OpenCV零基础开始到实现一个或若干个图像处理算法为止,中间可能会穿插部分自己遇到的比较典型的并认为需要记录的问题进行解析,每章节内容尽量做到简短而充实,方便学习及回顾。
此外,苦于很多初学者(我也是零基础)难以找到较新版本的OpenCV的中文学习资料或文档(旧版的1.X系列与2.X系列差距巨大,2.X是重构过的),因此,这份笔记也会针对OpenCV最新版官方文档(这里基于2.4.X版)里的一些基础内容进行翻译(相信大家走过了基础期,以后再读英文文档就不会那么费劲)。
笔者是国内某高校一小硕,研究方向为医学图像处理,将于2013年6月份毕业,因此,在2012年12月21世界末日到来之前,这份为零基础入门的学习笔记定会截稿,否则,小僧就毕不了业了。
当然,若干月后,小僧还会遇到类似的问题或发现笔记有不妥的地方,那么,小僧也会及时更新过来的。
摘要:本文主要在以下几个方面做介绍:1) OpenCV简介,什么是OpenCV;2) OpenCV的模块结构;3) OpenCV的下载、安装、配置及使用;4)OpenCV版HelloWorld代码及详解;关键词:OpenCV;OpenCV教程;OpenCV学习笔记;OpenCV中文教程;OpenCV下载;1 OpenCV简介OpenCV(Open Source Computer Vision)是一个用于实时处理的计算机视觉函数库,它基于BSD许可证授权并且可免费用于学术研究和商业应用。
它拥有C/C++、Python、和Java(仅用于Android)接口,并可在Windows、Linux、Mac和Android平台上运行。
OpenCV库包含大于2500个优化算法,拥有5M的下载量和47K+的用户群体。
Opencv学习笔记(四)图像的邻域操作(简单滤波算法)

Opencv学习笔记(四)图像的邻域操作(简单滤波算法)原理:很多时候,我们对图像处理时,要考虑它的邻域,⽐如3*3是我们常⽤的,这在图像滤波、去噪中最为常见,下⾯我们介绍如果在⼀次图像遍历过程中进⾏邻域的运算。
下⾯我们进⾏⼀个简单的滤波操作,滤波算⼦为[0 –1 0;-1 5 –1;0 –1 0]。
它可以让图像变得尖锐,⽽边缘更加突出。
核⼼公式即:sharp(i.j)=5*image(i,j)-image(i-1,j)-image(i+1,j )-image(i,j-1)-image(i,j+1)。
程序:#include "stdafx.h"#include "highgui.h"#include < Windows.h >#includeusing namespace std;using namespace cv;void ImgFilter2d(const Mat &image,Mat& result)//传进来的两个参数,第⼀个是要进⾏变换的图像,第⼆个是将要显⽰的结果图像{result.create(image.size(),image.type());//创建⼀个和image的⼤⼩类型都相同的空间int nr=image.rows;//⾏数int nc=image.cols*image.channels();//每⼀⾏有多少个通道for(int i=1;i{const uchar* up_line=image.ptr(i-1);//指向上⼀⾏const uchar* mid_line=image.ptr(i);//当前⾏const uchar* down_line=image.ptr(i+1);//下⼀⾏uchar* cur_line=result.ptr(i);//Mat::ptr()来获得指向某⾏元素的指针for(int j=1;j{cur_line[j]=saturate_cast(5*mid_line[j]-mid_line[j-1]-mid_line[j+1]-up_line[j]-down_line[j]);}}// 把图像边缘像素设置为0result.row(0).setTo(Scalar(0));result.row(result.rows-1).setTo(Scalar(0));result.col(0).setTo(Scalar(0));result.col(result.cols-1).setTo(Scalar(0));}void main(){Mat image;Mat image1;image = imread("E:\\2.jpg");namedWindow("tuxiang");int n = 4000;imshow("tuxiang", image);ImgFilter2d(image, image1);namedWindow("image1");imshow("image1", image1);waitKey(0);}结果显⽰:上⾯的程序有以下⼏点需要说明:1,staturate_cast是⼀个类型转换函数,程序⾥是为了确保运算结果还在uchar范围内。
OPENCV学习笔记

OPENCV学习笔记1、键盘响应事件While(1){If(cvWaitKey(100)==27)break;}括号里为延时等待ms等于的数值为ASCLL码(27)ESC建。
2、回调函数callback键盘响应回调函数参数事件位置需要注册回调函数到OPCV中,实现注册的函数是Cvsetmousecallback(){const char*window_name,Cvmousecallback on_mouseVoid param=null.}第一个参数指定了回调函数需要注册到的窗口即产生事件的窗口。
只有在这个指定窗口中发生的事件才会掉用这个函数。
第二个参数为回调函数。
最后,第三个参数用来传递额外的信息给前面的void*param3、OPENCV的基本数据类型Points size rectangles scalar三元结构Cvpoint int x y图像中的点Cvpoint2D32f float x,y二维空间中的点Cvpoint3D32F float x,y,z三维空间中的点Cvsize int width height图像的尺寸Cvrect int x y width height图像的部分区域Cvscalar double val[4]RGBA值假设要在(5,10)(20,30)间画一个白色矩形,只需要简单调用Cvrectangle(Myimg,Cvpoint(5,10)Cvpoint(20,30)Cvscalar(255,255,255)//RGB值全满为白色);3、使用OPENCV时会频繁遇到Iplimage数据类型IplImage是我们用来为通常所说的“图像”进行编码的基本结构。
这些图像可能是灰度,色彩,4通道的(RGB+alpha),其中的每个通道可以包含任意的整数或浮点数。
因此,该类型比常见的、易于理解的3通道8位RGB图像更通用。
Ipllmage由cvmat派生,cvmat由cvarr派生。
opencv学习笔记

opencv学习笔记一、背景知识:(自己看这块的一些笔记)(1)数字电视的色彩空间和计算机不同,不是RGB空间,而是采用一个亮度信号(Y)和两个色差信号(R-Y、B-Y)的YUV空间或者叫YCbCr空间。
数字电视采用YUV(YCbCr)色彩空间的原因主要就是为了减少数据储存空间和数据传输带宽,同时又能非常方便的兼容黑白电视(R-Y和B-Y信号为零)(2)来源上的差异yuv色彩模型来源于rgb模型,该模型的特点是将亮度和色度分离开,从而适合于图像处理领域。
应用:basic color model used in analogue color TV broadcasting.YCbCr模型来源于yuv模型。
YCbCr is a scaled and offset version of the YUV color space.应用:数字视频,ITU-R BT.601 recommendation(3)YCbCr其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。
人的肉眼对视频的Y分量更敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到的图像质量的变化。
主要的子采样格式有 YCbCr 4:2:0、YCbCr 4:2:2 和 YCbCr 4:4:4。
(4)皮肤检测主要是根据肤色在颜色空间上的分布特征来检测图像中的肌肤区域。
利用颜色信息对皮肤检测,应为不同人的肤色在排除亮度、室环境等影响对肤色的影响,皮肤的色调基本一致。
因此可以利用颜色信息来进行皮肤检测。
YCbCr色彩模型被广泛应用在电视的色彩显示领域。
CbCr其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量,而且在空间将色度与亮度分离的特点。
且是二维独立分布,能较好的限制肤色分布区域。
通过对肤色的像素点在YCbCr空间投影,聚类得到了肤色聚类成椭圆形。
(5)首先采集肤色样本,进行颜色空间转化,并进行图像平滑处理,将噪声减小。
OpenCV学习笔记(一)

OpenCV学习笔记(一)摘要:由于最近AR(增强现实)这个概念非常火爆,各种基于AR的应用及游戏逐渐面向大众,而在AR中最重要的两个技术就是跟踪识别和增强渲染,其中跟踪识别是通过OpenCV这个开源的计算机视觉库来实现的,所以我就想着研究一下这个库,这里是个人的学习笔记,不是什么权威的教程,如果你们有错误也麻烦帮我指出哈。
====================================== =======分割线========================================= =========前言:什么是OpenCV?可能还有人不清楚吧,简单地说,OpenCV——Open Source Computer Vision Library,即开源计算机视觉库,它是基于C语言和部分C++语言来开发,可用于计算机视觉、图像处理以及模式识别和跟踪。
一、准备工作:1.下载OpenCV安装包:到OpenCV的官网()下载最新版本的OpenCV安装包,由于OpenCV针对不同平台都有安装程序,所以我们只需要根据当前开发环境选择合适的平台版本即可,这里我们是在win7 64bit操作系统下进行开发,所以应该下载OpenCV for Windows:我们选择了当前的最新版本3.1,下载完毕后,我们得到其安装文件:opencv-3.1.0.exe2.安装Visual Studio 2015二、安装配置:1.安装:双击打开下载好的opencv-3.1.0.exe文件,进行安装(其实是解压),选择安装目录:安装完毕之后,在其安装目录下可以看到两个文件夹:build和sources,其中build是OpenCV使用时要用到的一些库文件,而sources中则是OpenCV为我们提供的一些demo示范源码:2.环境变量配置:上面步骤只是完成了安装,但是要能够正常使用OpenCV来进行开发,我们还需要进行环境变量的配置,我的电脑—>属性—>高级系统设置—>环境变量,找到Path变量,选中并点击编辑:64位系统的需要在path添加“;opencv安装路径\build 64\vc14\bin”(注:英文输入法中的“;”是分割符,用于与前面其他软件的配置参数分开),例如我的配置参数应该为:;E:\OpenCV\opencv\build 64\vc14\bin。
opencv笔记 二

异或操作bitwise_xor(变量,变量,输出变量)std::vector<Mat>mv;列:mv数组-mv[0],mv[1],mv[2],获取像素值split(image,mv)通道合并转换彩色图像merge(mv,输出变量)通道混合操作mixChannels(&image,&输出变量,1,数组名,数组里几对通道数)int 数组名[]={0,2,1,1,2,0}; 两两一对,共3对图像彩色空间转换-提取指定色彩区域inRange(变量图像名,Scalar(hsv最小值,hsv最小值,hsv最小值),Scalar(hsv最大值,hsv最大值,hsv最大值),输出变量)图像像素值统计求最小最大值minMaxLoc(image,&最小值变量,&最大值变量,&最小值的位置,&最大值的位置,Mat());Pointment 最小值的位置变量,最大值位置变量;图像像素值统计最小值min图像像素值统计最大值max图像像素值统计均值方差meanStdDev(image,变量1,变量2);图像像素值统计均值mean图像像素值统计标准方差standard deviation图像几何形状绘制绘制矩形Rect 等同于int 可以定义列:变量.x |y |width=100绘制矩形rectangle(image,Rect的变量,Scalar(0,0,255),大于等于0是线宽|小于0是填充,8,0)绘制圆形circle(image,Point(绘制的位置350,400),15是圆半径,Scalar(255,0,0),线宽和填充2,8,0)调节亮度addWeighted(image,0.7,Mat变量,0.3,0,变量输出dst)绘制线line(变量,Point(左上角坐标100,100),Point(右下角坐标350,400),Scalar(0,255,0),2,8或者LINE_AA反锯齿,0);绘制椭圆ellipse(image,rrt,Scalar(0,255,255),2,8);绘制椭圆-中心位置RotatedRect rrt;rrt.center=Point(200,200);绘制椭圆-大小弧度的高低rrt.Size(100,200)绘制椭圆-角度rrt.angle=0.0;随机数与随机颜色void drawing();//空函数Mat canvas=Mat::zeros(Size(512,512),CV_8UC3);int w=canvas.cols;int h=canvas.rows;RNG rng(12345);RNG 产生随机数while(true){ int c= waitKey(500);if(c==27){//退出break;}int x1=rng.uniform(0,w);int y1=rng.uniform(0,h);int x2=rng.uniform(0,w);int y2=rng.uniform(0,h);int b=rng.uniform(0,255);int g=rng.uniform(0,255);int r=rng.uniform(0,255);canvas=Scalar(0,0,0);//随机绘制一条线,不加上这个就是随机绘制多条线line(canvas,Point(x1,y1),Point(x2,y2),Scalar(b,g,r),1,LINE_AA,0);}多边形的填充与绘制Mat canvas=Mat::zeros(Size(512,512),CV_8UC3);Point p1(100,100);Point p2(350,100);std::vector<Point>pts;pts.push_back(p1);pts.push_back(p2);polylines(canvas,pts,true,Scalar(0,0,255),2,8,0);fillPoly(canvas,pts,Scalar(255,255,0)2,LINE_AA,0);//填充多边形一个API绘制多边形填充std::vector<std::vector<Point>>countours;contours.push_back(pts);drawContours(canvas,contours支持多个多边形,-1一次性绘制100个,Scalar(255,0,0),2填充); //-1一次性填充鼠标操作与响应Point sp(-1,-1);Point ep(-1,-1);Mat temp;static void on_draw(int event,int x,int y,int flas,void *userdata){Mat image=*((Mat*)userdata);if(event==EVENT_LBUTTONDOWN){sp.x=x;sp.y=y;std::cout<<"start point"<<sp<<std::endl;}else if(event==EVENT_LBUTTONUP){ep.x=x;ep.y=y;int dx=ep.x-sp.x;int dy=ep.y-sp.y;if(dx>0&&dy>0){Rect box(sp.x,sp.y,dx,dy);rectangle(image,box,Scalar(0,0,255),2,8,0);imshow("鼠标绘制",image);imshow("截取区域",image(box));sp.x=-1;sp.y=-1;}}else if(event==EVENT_MOUSEMOVE){if(sp.x>0&&sp.y>0){ep.x=x;ep.y=y;int dx=ep.x-sp.x;int dy=ep.y-sp.y;if(dx>0&&dy>0){Rect box(sp.x,sp.y,dx,dy);temp.copyTo(image);rectangle(image,box,Scalar(0,0,255),2,8,0);imshow("鼠标绘制",image);}}void QuickDemo::mouse_drawing_demo(Mat &image){ namedwindow("鼠标绘制",WINDOW_AUTOSIZE); setMouseCallback("鼠标绘制",on_draw,(void*)(&image)); imshow("鼠标绘制",image);temp=image.clone();}。
opencv笔记

opencv笔记⼀ Contour FindingContours使⽤ STL-style vector<> 表⽰,如 vector<cv::Point>, vector<cv::Point2f>。
opencv 中,使⽤函数 cv::findContours() 寻找contours,具体函数定义如下:void cv::findContours(cv::InputOutputArray image,cv::OutputArrayofArrays contours,cv::OutputArray hierarchy,int mode,int method,cv::Point offset = cv::Point());void cv::findContours(cv::InputOutputArray image,cv::OutputArrayofArrays contours,int mode,int method,cv::Point offset = cv::Point());参数 image 为8位单通道输⼊图像,⼀般情况下,该图像可能由 cv::threshold(),cv::adaptiveThreshold ⽣成。
当 image 由 cv::Canny() ⽣成时,cv::findContours() 仅当边缘图像为宽度为1的细区域图像,对于闭合边缘,可以使⽤内边缘或者外边缘代替边缘图像进⾏后续分析;但对于⾮闭合边缘,个⼈认为 cv::Canny() ⽣成的边缘图像不适合使⽤ cv::findContours()进⾏查找;替代⽅案是使⽤边缘跟踪算法,将 cv::Canny() ⽣成边缘保存在 vector<cv::Point>中,然后使⽤ Contours 相关分析进⾏更多分析。
参数 contours 为 vector<vector<cv::Point>>, vector<vector<cv::Point2f>>, 使⽤ array of arrays 结构可以同时保存多条 contours。
opencv 学习笔记、函数、方法、重难点、教程

1)通道拆分:b,g,r = cv2.spliti(img);b = cv2.split(img)[0];2)通道合并:img = cv2.merge([b,g,r]3)Np.arr: item(), itemset(),彩色图像必须包括行、列、列索引/通道;4)图像属性包括:shape(行,列,通道数)size(行*列*通道数)Dtype 数据类型5)“+”或cv2.add()对图像进行加法运算;区别:“+”a+b≤255时,取值a+ba+b>255时,取值mod(a+b,256)cv2.add()a+b≤255时,取值a+ba+b>255时,取值255注:cv2.add(),参数:(图像,图像);(图像,数值);(数值,图像)6)图像加权和:计算两幅图像的像素值之和时,将每幅图像的权重考虑进来:dst = saturate(src1*α+src2*β+γ);saturate()表示取饱和值7)Opencv中提供了函数cv2.addWeighted(),用来实现图像的加权和dst = cv2.addweighted(src1,alpha,src2,beta,gamma);该函数实现的功能是src1*α+src2*β+γ;α+β可以等于1,也可以不等于1,gamma可以是0,但是是必选参数,不能省略;8)按位逻辑运算:9)位平面分解代码:import cv2import numpy as npJieyi = cv2.imread("jieyi.jpg",0)cv2.imshow("lena",lena)r,c = lena.shapex = np.zeros((r,c,8),dtype = np.uint8) for i in range(8):x[:,:,i] = 2**ir = np.zeros((r,c,8),dtype = np.uint8)for i in range(8):r[:,:,i] = cv2.bitwise_and(lena,x[:,:,i]) mask = r[:,:,i]>0r[mask] = 255cv2.imshow(str(i),r[:,:,i])cv2.waitKey()cv2.destroyAllWindows()10)HSV色彩空间:色调(Hue,也称色相),饱和度(saturation)、亮度(value)●色调:详见附录二色调环,范围[0,360]●饱和度:指相对纯净度,或一种颜色混合白光的数量,饱和度与所加白光的数量成反比,范围[0,1]●亮度:反应的是人眼感受到的光的明暗程度,该指标与物体的反射程度有关。
OPENCV学习笔记(2)

OPENCV学习笔记(2)OpenCV学习笔记(三)人脸检测的代码分析一、预备知识:1、动态内存存储及操作函数CvMemStorage1.typedef struct CvMemStorage2.{3.struct CvMemBlock*bottom;/*first allocated block*/4.struct CvMemBlock*top;/*the current memoryblock-top of the stack*/5.struct CvMemStorage*parent;/*borrows new blocks from*/6.int block_size;/*block size*/7.int free_space;/*free space in the top block(in bytes)*/8.}CvMemStorage;内存存储器是一个可用来存储诸如序列,轮廓,图形,子划分等动态增长数据结构的底层结构。
它是由一系列以同等大小的内存块构成,呈列表型---bottom域指的是列首,top域指的是当前指向的块但未必是列尾.在bottom和top之间所有的块(包括bottom,不包括top)被完全占据了空间;在top和列尾之间所有的块(包括块尾,不包括top)则是空的;而top块本身则被占据了部分空间--free_space指的是top块剩余的空字节数。
新分配的内存缓冲区(或显示的通过cvMemStorageAlloc函数分配,或隐示的通过cvSeqPush,cvGraphAddEdge 等高级函数分配)总是起始于当前块(即top块)的剩余那部分,如果剩余那部分能满足要求(够分配的大小)。
分配后,free_space就减少了新分配的那部分内存大小,外加一些用来保存适当列型的附加大小。
当top块的剩余空间无法满足被分配的块(缓冲区)大小时,top块的下一个存储块被置为当前块(新的top块)--free_space被置为先前分配的整个块的大小。
opencv笔记 三

图像像素类型转换与归一化Mat dst;std::cout<<image.type()<<std::endl;image.convertTo(dst,CV_32F);//变成每个通道32位,浮点数类型//原本CV_8UC3,每个通道8位std::cout<<dst.type()<<std::endl;normalize(image,dst,1.0,1,NORM_MINMAX);std::cout<<dst.type()<<std::endl;imshow("",std);图像放缩与差值Mat zoomin,zoomout;int h=image.rows;int w=image.cols;resize(image,zoomin,Size(w/2,h/2),0,0,INTER_LINEAR);imshow("zoomin"zoomin);resize(image,zoomout,Size(w*1.5,h*1.5),0,0,INTER_LINEAR);imshow("zoomout"zoomout);图像翻转Mat dst;filp(image,dst,0);//0是上下翻转,1是左右,-1是旋转180度imshow("图像翻转"dst);图像旋转Mat dst,M;int h=image.rows;int w=image.cols;M=getRotationMatrix2D(原来图像中心位置Point2f(w/2,h/2),旋转角度45,1.0); warpAffine(image,M,image,size(),INTER_LINEAR,0,Scalar(255,0,0));imshow("旋转演示“,dst);Mat dst,M;int h=image.rows;int w=image.cols;M=getRotationMatrix2D(原来图像中心位置Point2f(w/2,h/2),旋转角度45,1.0);double cos=abs(M.at<double>(0,0));double sin=abs(M.at<double>(0,1));int nw=cos*w+sin*h;int nh=sin*w+cos*h;M.at<double>(0,2)+=(nw/2-w/2);M.at<double>(1,2)+=(nh/2-h/2);warpAffine(image,M,image,size(nw,nh),INTER_LINEAR,0,Scalar(255,255,0));imshow("旋转演示“,dst);视频文件摄像头使用VideoCapture capture(0);//0是直接用的摄像头//"视频路径"Mat frame;while(true){capture.read(frame);flip(frame,frame,1);if(frame.empty()){break;}imshow("frame"frame);int c=waitKey(10);if(c==27){break;//退出}}视频处理与保存VideoCapture capture("视频路径");//0是直接用的摄像头//"视频路径"int frame_width=capture.get(CAP_PROP_FRAME_WIDTH);int frame_height=capture.get(CAP_PROP_FRAME_HEIGHT);int count=capture.get(CAP_PROP_FRAME_COUNT);int fps=capture.get(CAP_PROP_FPS);std;;cout<<""frame width"<<frame_width<<std::endl;std;;cout<<""frame width"<<frame_height<<std::endl;std;;cout<<""frame width"<<fps<<std::endl;std;;cout<<""frame width"<<cout<<std::endl;VideoWriterwriter("",capture.get(CAP_PROP_FOURCC),FPS,Size(frame_width,frame_height),ture); Mat frame;while(ture){capture.read(frame);flip(frame,frame,1);if(frame.empty()){break;}imshow("",frame);colorSpace_Demo(frame);writer.writer(frame);int c=waitKey(10);if(c==27){break;//退出}}capture.release();writer.release();}图像直方图std::vector<Mat>bgr_plane; //三通道分离split(image,bgr_plane);const int channels[1]={0}; //定义参数变量const int bins[1]={256};float hranges[2]={0,255};const float*ranges[1]={hranges};Mat b_hist;Mat g_hist;Mat r_hist;calcHist(&bgr_plane[0],1,0,Mat(),b_hist,1,bins,ranges); //计算通道的直方图calcHist(&bgr_plane[1],1,0,Mat(),g_hist,1,bins,ranges);calcHist(&bgr_plane[2],1,0,Mat(),r_hist,1,bins,ranges);int hist_w=512; //显示直方图int hist_h=400;int hist_w=cvRound((double)hist_w/bins[0]);Mat histImage=Mat::zeros(hist_h,hist_w,CV_8UC3);normalize(b_hist,b_hist,0,histImage.rows,NORM_MINMAX,-1,Mat());//归一化直方图数据normalize(g_hist,g_hist,0,histImage.rows,NORM_MINMAX,-1,Mat());normalize(r_hist,r_hist,0,histImage.rows,NORM_MINMAX,-1,Mat());for(int i=1;i<bins[0];i++){ //绘制直方图曲线line(histImage,Point(bin_w*(i-1),hist_h-cvRound(b_hist.at<float>(i-1)));Point(bin_w*(i),hist_h-cvRound(b_hist.at<float>(i))),Scalar(255,0,0),2,8,0);line(histImage,Point(bin_w*(i-1),hist_h-cvRound(g_hist.at<float>(i-1)));Point(bin_w*(i),hist_h-cvRound(g_hist.at<float>(i))),Scalar(0,255,0),2,8,0); line(histImage,Point(bin_w*(i-1),hist_h-cvRound(r_hist.at<float>(i-1))); Point(bin_w*(i),hist_h-cvRound(r_hist.at<float>(i))),Scalar(0,255,0),2,8,0); namedWindow("",WINDOW_AUTOSIZE);//显示直方图imshow("",hisImage);二维直方图Mat hsv,hs_hist;cvtColor(image,hsv,COLOR_BGR2HSV);int hbins=30,sbins=32;int hist_bins[]={hbins,sbins};float h_range[]={0,180};float s_range[]={0,256};const float*hs_ranges[]={h_range,s_range};int hs_channels[]={0,1};calcHist(&hsv,1,hs_channels,Mat(),hs_hist,2,hist_bins,hs_range,true,false); double maxVal=0;minMaxLoc(hs_hist,0,&maxVal,0,0);int scale=10;Mat hist2d_image=Mat::zeros(sbins*scale,hbins*scale,CV_8UC3);for(int h=0;h<hbins;h++){for(int s=0;s<sbins;s++){float binVal=hs_hist.at<float>(h,s);int intensity=cvRound(binVal*255/maxVal);rectangle(hist2d_image,Point(h*scale,s*scale);Point(h+1)*scale-1,(s+1)*scale-1),Scalar::all(intensity),-1);}}applyColorMap(hist2d_image,hist2d_image,COLORMAP_IET);imshow("H-S Histogram",hist2d_image);imshow("D:/hist_2d.png",hist2d_image);直方图均衡化Mat gray;cvtColor(image,gray,COLOR_BGR2GRAY);imshow("灰图",gray);Mat dst;equalizeHist(gray,dst);imshow("均衡化演示",dst);图像卷积操作Mat dst;blur(image,dst,Size(15,1),Point(-1,-1));imshow("图像模糊",dst);高斯模糊Mat dst;GaussianBlur(image,dst,Size(15,1),15);imshow("图像模糊",dst);高斯双边模糊Mat dst;bilateralFilter(image,dst,0,100,10);imshow("双边模糊",dst);图像像素类型转换与归一化。
OpenCV2学习笔记(一)

OpenCV2学习笔记(⼀)Mat - 图像的容器在对图像进⾏处理时,⾸先需要将图像载⼊到内存中,⽽Mat就是图像在内存中的容器,管理着图像在内存中的数据。
Mat是C++ 的⼀个类,由于OpenCV2中引⼊了内存⾃动管理机制,所以不必⼿动的为Mat开辟内存空间以及⼿动的释放内存。
Mat中包含的数据主要由两个部分构成:矩阵头(矩阵尺⼨、存储⽅法、存储地址等信息)和⼀个指向存储图像所有像素值的矩阵(根据所选的存储⽅法不同的矩阵可以是不同的维数)的指针。
在图像处理中,对图像的处理不可能是在⼀个函数中完成的,这就需要在不同的函数间传递Mat。
同时,图像处理的计算量是很⼤,除⾮万不得已就不要去传递⽐较⼤的Mat。
这就要求使⽤某种机制来实现Mat的快速传递。
Mat中主要有矩阵头和⼀个指向矩阵的指针,矩阵头是⼀个常数值,但是矩阵保存了图像所有的像素值,通常会⽐矩阵头⼤⼏个数量级,因此传递Mat是主要的消耗是在矩阵复制上。
为了解决这个问题,OpenCV中引⼊了计数机制。
每个Mat都有⾃⼰的信息头,但是共享同⼀个矩阵,也就是在传递Mat时,只复制矩阵头和指向矩阵的指针。
1: Mat a,c ;2: a = imread("d:\\test.jpg",1) ;3: Mat b(a) ; //拷贝构造函数4: a = c ; //复制运算符上⾯代码中3个Mat对象a,b,c指向同⼀个矩阵,由于都指向了同⼀个矩阵,某⼀个对象对矩阵进⾏操作时也会影响到其他对象读取到的矩阵。
多个对象同时使⽤⼀个矩阵,那么当不需要该矩阵时,谁来负责清理?简单的回答是,最后⼀个使⽤它的对象。
通过引⽤计数机制,⽆论什么时候Mat对象的信息头被复制了,都会增加矩阵的引⽤次数加1;反之,当⼀个Mat的信息头被释放后,引⽤计数就会被减1;当计数被减到0时,矩阵就会被释放。
当然,有些时候还是需要拷贝矩阵本⾝的,这时候可以使⽤clone和 copyTo。
OpenCV笔记(3)(Canny边缘检测、高斯金字塔、拉普拉斯金字塔、图像轮廓、模板匹配)

OpenCV笔记(3)(Canny边缘检测、⾼斯⾦字塔、拉普拉斯⾦字塔、图像轮廓、模板匹配)⼀、Canny边缘检测Canny边缘检测是⼀系列⽅法综合的结果。
其中主要包含以下步骤:1.使⽤⾼斯滤波器,平滑图像,滤除噪声。
2.计算图像中每个像素点的梯度强度和⽅向。
3.应⽤⾮极⼤值抑制(NMS:Non-Maximum Suppression),以消除边缘检测带来的杂散相应。
4.应⽤双阈值(Double-Threshold)检测来确定真实和潜在的边缘。
5.通过抑制孤⽴的弱边缘最终完成边缘检测。
1.⾼斯滤波器平滑图像。
2.计算梯度和⽅向使⽤X和Y⽅向的Sobel算⼦来分别计算XY⽅向梯度:每个点的梯度强度有XY⽅向的梯度计算出来:计算每个点梯度的⽅向:3.使⽤NMS有两种⽅法,第⼀种⽅法(插值法,⽐较复杂):通过计算出的梯度⽅向,找到与周边临近点的边的交点,然后使⽤权重计算交点的值,假设g1和g2之间的交点(左上的⿊点)处于6/4的位置,那么他的值为M = g1*(1-0.6)+g2*(0.4)。
当算出左上的⿊点和右下的⿊点值后,⽤这两个点与C的值进⾏⽐较,如果都⼩于C,则C归为边界。
如果有⼀个⽐C⼤,则丢弃C,这就叫抑制。
第⼆种⽅法(指定8个⽅向,不⽤插值,简化版):4.双阈值检测在NMS的基础上,判断⼀个边界点的梯度强度: (1) 如果值⼤于maxVal,则处理为边界 (2) 如果值minVal<梯度值<maxVal,再检查是否挨着其他边界点,如果旁边没有边界点,则丢弃,如果连着确定的边界点,则也认为其为边界点。
(3) 梯度值<minVal,舍弃。
通过以上步骤,完成Canny边缘检测。
调⽤Canny API如下:# 使⽤Canny边界检测def use_canny(image):# 后⾯两个参数代表双阈值检测的minVal和maxValimg1 = cv.Canny(image, 50, 100)cv.imshow('img1', img1)# 这⾥使⽤更⼤的minVal和maxVal,细节边界变少了img2 = cv.Canny(image, 170, 250)cv.imshow('img2', img2)⼆、⾼斯⾦字塔图像⾦字塔:Image pyramid如图中所⽰,从0到3是⼀个下采样过程(指图⽚越来越⼩的⽅向),从3到0是⼀个上采样过程(将图⽚变⼤的过程),⼀次下采样加⼀次上采样不等于原图像,因为会损失⼀些细节信息。
OpenCV学习笔记(2)

第二章数据结构OpenCV核心库的数据结构一、基本数据结构CvPoint、CvPoint2D32f、CvPoint3D32f、CvSize、CvSize2D32f、CvSize3D32f、CvRectCvScalar(N元组)CvMat、CvMatND、CvSpareseMat、CvTermCriteria、CvArr、Iplimage例题4-1:基本数据类型使用说明:cvFlip:垂直,水平或即垂直又水平翻转二维数组void cvFlip( const CvArr* src, CvArr* dst=NULL, int flip_mode=0); flip_mode :指定怎样去翻转数组。
flip_mode = 0 沿X-轴翻转,flip_mode > 0 (如1) 沿Y-轴翻转,flip_mode < 0 (如-1) 沿X-轴和Y-轴翻转.见下面的公式函数cvFlip 以三种方式之一翻转数组(行和列下标是以0为基点的):dst(i,j)=src(rows(src)-i-1,j) if flip_mode = 0dst(i,j)=src(i,cols(src1)-j-1) if flip_mode > 0dst(i,j)=src(rows(src)-i-1,cols(src)-j-1) if flip_mode < 0二、数组有关的结构1、数组定义IplImage和cvMat结构的基本使用方法IplImage:图像结构typedef struct _IplImage{int nSize; /* IplImage大小*/int ID; /* 版本(=0)*/int nChannels; /* 大多数OPENCV函数支持1,2,3 或4 个通道*/int alphaChannel; /* 被OpenCV忽略*/int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S,IPL_DEPTH_16U,IPL_DEPTH_16S, IPL_DEPTH_32S,IPL_DEPTH_32F and IPL_DEPTH_64F 可支持*/ char colorModel[4]; /* 被OpenCV忽略*/char channelSeq[4]; /* 同上*/int dataOrder; /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道.cvCreateImage只能创建交叉存取图像*/ int origin; /* 0 - 顶—左结构,1 - 底—左结构(Windows bitmaps 风格) */int align; /* 图像行排列(4 or 8). OpenCV 忽略它,使用widthStep 代替*/int width; /* 图像宽像素数*/int height; /* 图像高像素数*/struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理*/struct _Iplimage *maskROI; /* 在OpenCV中必须置NULL */void *ImageId; /* 同上*/struct _IplTileInfo *tileInfo; /*同上*/int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/char *imageData; /* 指向排列的图像数据*/int widthStep; /* 排列的图像行大小,以字节为单位*/int BorderMode[4]; /* 边际结束模式, 被OpenCV忽略*/int Borderconst[4]; /* 同上*/char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的*/}IplImage;IplImage结构来自于Intel Image Processing Library(是其本身所具有的)。
opencv学习笔记(六)直方图比较图片相似度

opencv学习笔记(六)直⽅图⽐较图⽚相似度opencv学习笔记(六)直⽅图⽐较图⽚相似度 opencv提供了API来⽐较图⽚的相似程度,使我们很简单的就能对2个图⽚进⾏⽐较,这就是直⽅图的⽐较,直⽅图英⽂是histogram, 原理就是就是将图⽚转换成直⽅图,然后对直⽅图进⾏⽐较,在某些程度,真实地反映了图⽚的相似度。
代码如下:1 #include <iostream>2 #include <cv.h>3 #include <highgui.h>4using namespace std;5using namespace cv;67int main(void)8 {9 Mat pic1 = imread("pic1.jpg");10 Mat pic2 = imread("pic2.jpg");11//计算相似度12if (pic2.channels() == 1) {//单通道时,13int histSize = 256;14float range[] = { 0, 256 };15const float* histRange = { range };16bool uniform = true;17bool accumulate = false;1819 cv::Mat hist1, hist2;2021 cv::calcHist(&pic2, 1, 0, cv::Mat(), hist1, 1, &histSize, &histRange, uniform, accumulate);22 cv::normalize(hist1, hist1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());2324 cv::calcHist(&pic1, 1, 0, cv::Mat(), hist2, 1, &histSize, &histRange, uniform, accumulate);25 cv::normalize(hist2, hist2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());2627double dSimilarity = cv::compareHist(hist1, hist2, CV_COMP_CORREL);//,CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA CV_COMP_CORREL 2829 cout << "similarity = " << dSimilarity << endl;30 }31else {//三通道时32 cv::cvtColor(pic2, pic2, cv::COLOR_BGR2HSV);33 cv::cvtColor(pic1, pic1, cv::COLOR_BGR2HSV);3435int h_bins = 50, s_bins = 60;36int histSize[] = { h_bins, s_bins };37float h_ranges[] = { 0, 180 };38float s_ranges[] = { 0, 256 };39const float* ranges[] = { h_ranges, s_ranges };40int channels[] = { 0, 1 };4142 cv::MatND hist1, hist2;4344 cv::calcHist(&pic2, 1, channels, cv::Mat(), hist1, 2, histSize, ranges, true, false);45 cv::normalize(hist1, hist1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());4647 cv::calcHist(&pic1, 1, channels, cv::Mat(), hist2, 2, histSize, ranges, true, false);48 cv::normalize(hist2, hist2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());4950double dSimilarity = cv::compareHist(hist1, hist2, CV_COMP_CORREL); //,CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA CV_COMP_CORREL 5152 cout << "similarity = " << dSimilarity << endl;53 }54 waitKey(0);55return1;5657 } pic1: pic2: 使⽤相关系数法(CV_COMP_CORREL)进⾏图⽚相似度⽐较时,取值范围为[-1,1];越接近1说明两幅图⽚越相似; ⽐较pic1与pic2得到的结果为: similarity =0.926247 pic与本⾝进⾏⽐较时, similarity =1。
OpenCV看书笔记 所有基本操作 图形

struct _IplROI *roi;//图像ROI,若不为NULL则表示需要处理的图像区域
char *imageDataOrigin;//指针指向图像数据原点(用来校准图像存储单元的重新分配)
double* db; // 针对double矩阵的数据指针
CvMatND //N-维数组
int type;//元素类型(uchar,short,int,float,double)
int dims; // 数组维度
union data;
....
break;
case 'i':
...
break;
}
}
处理滚动条事件:
int pos=cvGetTrackbarPos("bar1","win1");
设定滚动条位置:
cvSetTrackbarPos("bar1","win1",25);
图像数据结构
IPL图像:
{
switch(event){
case CV_EVENT_LBUTTONDOWN:
if(flags & CV_EVENT_FLAG_CTRLKEY)
printf(Left button down with CTRL pressed\n);
GUI命令:
窗口管理
建立并放置一个窗口
cvNamedWindow("win1",CV_WINDOW_AUTOSIZE);
cvMoveWindow("win1",100,100);//以屏幕左上角为起点的偏移量
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
OPENCV
一、Opencv 基本架构分析
多模块组合起来的一个软件开发工具包(SDK)
1、【calib3d】
2、【cntrib】
3、【core】:核心功能模块。
4、【imgproc】:图像处理模块。
5、【features2d】
6、【flann】
7、【gpu】
8、【highgui】:高层GUI图形用户界面,包含媒体的输
入输出、视频捕捉、图像视频的编码和解码、图形交互界面的接口内容等。
9、【legacy】
…
二、HighGui图形用户界面初步
1、opencv的命名空间:opencv的C++类和函数都是定
义在命名空间cv之内的,访问方法:(1)、在代码
开头的适当位置加上using namespace cv (2)、在
使用opencv的每个内和函数时,都加入cv::命名
空间。
2、图像的载入:imread()函数
Mat imread(const string& filename, int flags=1);
(1)、const string&类型的filename,填我们需要载
入的图片路径名称。
(2)、int类型的flags,为载入标志,它指一个加载
图像的颜色类型。
3、图像的显示:imshow()函数
Void imshow(const string& winname, InputArray mat);
(1)、const string&类型的winname,填需要显示的窗口标识名称。
(2)、InputArray类型的mat,填需要显示的图像。
4、创建窗口:namedWindow()函数
void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE);
(1)、const string&类型的name,填写被作用窗口的标识符的窗口名称。
(2)、int类型的flags,窗口的标识,可填写WINDOW_AUTOSIZE、WINDOW_NORMAL或WINDOW_OPENGL
5、输出到文件:imwrite()函数
bool imwrite(const string& finename, InputArray img , const vector<int>& params=vector<int>() );
(1)、const string&类型的finename,填需要写入的文件名。
注意带上后缀,如“123.jpg”
(2)、InputArray类型的img,一般填一个Mat类型的图像数据。
(3)、const wector<int>&类型的params,表示为特定格式保存的参数编码。
它有默认值vector<int>0,所以一般情况下不需要写。
6、创建滑动条:createTrackbar()函数
C++: int createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0);
(1)、conststring&类型的trackbarname,轨迹条的名字,用来代表我们创建的轨迹条。
(2)、conststring&类型的winname,窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应namedWindow()创建窗口时填写的某一个窗口名。
(3)、int*类型的value,一个指向整形的指针,表示滑块的位置。
在创建时,滑块的初始位置就是该变量当前的值。
(4)、int类型的count,表示滑块可以达到的最大位置的值。
滑块最小位置的值始终为0.
(5)、TrackbarCallback类型的onChange,它有默认
值0。
这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。
并且这个函数的原型必须为void XXX(int void*);,其中第一个参数是轨迹条的位置,第二个参数是用户数据。
如果回调是NULL指针,则表示没有回调函数的调用,仅第三个参数value有变化。
(6)、void*类型的userdata,默认值0.这个参数是用户传给回调函数的数据,用来处理轨迹条事件。
如果使用的第三个参数value实参是全局变量的话,完全可以不去管userdata参数。
7、获取当前轨迹条的位置:getTrackbarPos()函数
C++: int getTrackbarPos(conststring& trackbarname, conststring& winname);
(1)、conststring&类型的trackbarname,表示轨迹条的名字。
(2)、conststring&类型的winname,表示轨迹条的父窗口的名称。
8、鼠标操作:SetMouseCallback()
C++: void SetMouseCallback(conststring& winname, MouseCallback onMouse, void* userdata=0)
(1)、conststring&类型的winname,窗口的名字。
(2)、MouseCallback类型的onMouse,指定窗口里每次鼠标时间发生的时候,被调用的函数指针。
这个
函数的原型大概为void Foo(int event, int x, int y, int flags, void* param)。
其中event是EVENT_+变量之一,x、y是鼠标指针在图像坐标系中的坐标值,flags是EVENT_FLAG的组合,param是用户定义的传递到SetMouseCallback函数调用的参数。
如EVENT_MOUSEMOVE为鼠标移动消息、EVENT_LBUTTONDOWN为鼠标左键按下消息等。
(3)、void*类型的userdata,用户定义的传递到回调函数的参数,默认值0。