📄 c+m+b mmvi opencv 编程入门.htm
字号:
<P></P>
<UL>
<LI>响应鼠标事件:
<UL>
<LI>定义鼠标handler: <PRE> void mouseHandler(int event, int x, int y, int flags, void* param)<BR> {<BR> switch(event){<BR> case CV_EVENT_LBUTTONDOWN:<BR> if(flags & CV_EVENT_FLAG_CTRLKEY) <BR> printf("Left button down with CTRL pressed\n");<BR> break;<BR><BR> case CV_EVENT_LBUTTONUP:<BR> printf("Left button up\n");<BR> break;<BR> }<BR> }<BR><BR> // x,y: 针对左上角的像点坐标<BR><BR> // event: CV_EVENT_LBUTTONDOWN, CV_EVENT_RBUTTONDOWN, CV_EVENT_MBUTTONDOWN,<BR> // CV_EVENT_LBUTTONUP, CV_EVENT_RBUTTONUP, CV_EVENT_MBUTTONUP,<BR> // CV_EVENT_LBUTTONDBLCLK, CV_EVENT_RBUTTONDBLCLK, CV_EVENT_MBUTTONDBLCLK,<BR> // CV_EVENT_MOUSEMOVE:<BR><BR> // flags: CV_EVENT_FLAG_CTRLKEY, CV_EVENT_FLAG_SHIFTKEY, CV_EVENT_FLAG_ALTKEY,<BR> // CV_EVENT_FLAG_LBUTTON, CV_EVENT_FLAG_RBUTTON, CV_EVENT_FLAG_MBUTTON<BR></PRE>
<P></P>
<LI>注册handler: <PRE> mouseParam=5;<BR> cvSetMouseCallback("win1",mouseHandler,&mouseParam);<BR></PRE>
<P></P></LI></UL>
<P></P>
<P></P>
<LI>响应键盘事件:
<UL>
<LI>键盘没有事件handler.
<P></P>
<LI>直接获取键盘操作: <PRE> int key;<BR> key=cvWaitKey(10); // 输入等待10ms<BR></PRE>
<P></P>
<LI>等待按键并获取键盘操作: <PRE> int key;<BR> key=cvWaitKey(0); // 无限等待键盘输入<BR></PRE>
<P></P>
<LI>键盘输入循环: <PRE> while(1){<BR> key=cvWaitKey(10);<BR> if(key==27) break;<BR><BR> switch(key){<BR> case 'h':<BR> ...<BR> break;<BR> case 'i':<BR> ...<BR> break;<BR> }<BR> }<BR></PRE>
<P></P></LI></UL>
<P></P>
<LI>处理滚动条事件:
<UL>
<LI>定义滚动条handler: <PRE> void trackbarHandler(int pos)<BR> {<BR> printf("Trackbar position: %d\n",pos);<BR> }<BR></PRE>
<P></P>
<LI>注册handler: <PRE> int trackbarVal=25;<BR> int maxVal=100;<BR> cvCreateTrackbar("bar1", "win1", &trackbarVal ,maxVal , trackbarHandler);<BR></PRE>
<P></P>
<LI>获取滚动条当前位置: <PRE> int pos = cvGetTrackbarPos("bar1","win1");<BR></PRE>
<P></P>
<LI>设定滚动条位置: <PRE> cvSetTrackbarPos("bar1", "win1", 25);<BR></PRE>
<P></P></LI></UL>
<P></P></LI></UL>
<P></P>
<H1><A>OpenCV基础数据结构</A> </H1>
<P></P>
<H2><A>图像数据结构</A> </H2>
<P></P>
<UL>
<LI>IPL 图像: <PRE>IplImage<BR> |-- int nChannels; // 色彩通道数(1,2,3,4)<BR> |-- int depth; // 象素色深: <BR> | // IPL_DEPTH_8U, IPL_DEPTH_8S, <BR> | // IPL_DEPTH_16U,IPL_DEPTH_16S, <BR> | // IPL_DEPTH_32S,IPL_DEPTH_32F, <BR> | // IPL_DEPTH_64F<BR> |-- int width; // 图像宽度(象素点数)<BR> |-- int height; // 图像高度(象素点数)<BR><BR> |-- char* imageData; // 指针指向成一列排列的图像数据<BR> | // 注意色彩顺序为BGR<BR> |-- int dataOrder; // 0 - 彩色通道交叉存取 BGRBGRBGR, <BR> | // 1 - 彩色通道分隔存取 BBBGGGRRR<BR> | // 函数cvCreateImage只能创建交叉存取的图像<BR> |-- int origin; // 0 - 起点为左上角,<BR> | // 1 - 起点为右下角(Windows位图bitmap格式)<BR> |-- int widthStep; // 每行图像数据所占字节大小<BR> |-- int imageSize; // 图像数据所占字节大小 = 高度*每行图像数据字节大小<BR> |-- struct _IplROI *roi;// 图像ROI. 若不为NULL则表示需要处理的图像<BR> | // 区域.<BR> |-- char *imageDataOrigin; // 指针指向图像数据原点<BR> | // (用来校准图像存储单元的重新分配)<BR> |<BR> |-- int align; // 图像行校准: 4或8字节校准<BR> | // OpenCV不采用它而使用widthStep<BR> |-- char colorModel[4]; // 图像色彩模型 - 被OpenCV忽略<BR></PRE>
<P></P></LI></UL>
<P></P>
<P></P>
<H2><A>矩阵与向量</A> </H2>
<P></P>
<UL>
<LI>矩阵: <PRE>CvMat // 2维数组<BR> |-- int type; // 元素类型(uchar,short,int,float,double)<BR> |-- int step; // 一行所占字节长度<BR> |-- int rows, cols; // 尺寸大小<BR> |-- int height, width; // 备用尺寸参照<BR> |-- union data;<BR> |-- uchar* ptr; // 针对unsigned char矩阵的数据指针<BR> |-- short* s; // 针对short矩阵的数据指针<BR> |-- int* i; // 针对integer矩阵的数据指针<BR> |-- float* fl; // 针对float矩阵的数据指针<BR> |-- double* db; // 针对double矩阵的数据指针<BR><BR><BR>CvMatND // N-维数组<BR> |-- int type; // 元素类型(uchar,short,int,float,double)<BR> |-- int dims; // 数组维数<BR> |-- union data;<BR> | |-- uchar* ptr; // 针对unsigned char矩阵的数据指针<BR> | |-- short* s; // 针对short矩阵的数据指针<BR> | |-- int* i; // 针对integer矩阵的数据指针<BR> | |-- float* fl; // 针对float矩阵的数据指针<BR> | |-- double* db; // 针对double矩阵的数据指针<BR> |<BR> |-- struct dim[]; // 每个维的信息<BR> |-- size; // 该维内元素个数<BR> |-- step; // 该维内元素之间偏移量<BR><BR><BR>CvSparseMat // 稀疏N维数组<BR></PRE>
<P></P>
<LI>通用数组: <PRE>CvArr* // 仅作为函数参数,说明函数接受多种类型的数组,例如:<BR> // IplImage*, CvMat* 或者 CvSeq*. <BR> // 只需通过分析数组头部的前4字节便可确定数组类型</PRE>
<P></P>
<P></P>
<LI>标量: <PRE>CvScalar<BR> |-- double val[4]; //4D向量<BR></PRE>
<P>初始化函数: </P><PRE>CvScalar s = cvScalar(double val0, double val1=0, double val2=0, double val3=0);<BR></PRE>
<P>举例: </P><PRE>CvScalar s = cvScalar(20.0);<BR>s.val[0]=10.0;<BR></PRE>
<P>注意:初始化函数与数据结构同名,只是首字母小写. 它不是C++的构造函数. </P>
<P></P></LI></UL>
<P></P>
<H2><A>其他数据结构</A> </H2>
<P></P>
<UL>
<LI>点: <PRE>CvPoint p = cvPoint(int x, int y);<BR>CvPoint2D32f p = cvPoint2D32f(float x, float y);<BR>CvPoint3D32f p = cvPoint3D32f(float x, float y, float z);<BR>例如:<BR>p.x=5.0;<BR>p.y=5.0;<BR></PRE>
<P></P>
<LI>长方形尺寸: <PRE>CvSize r = cvSize(int width, int height);<BR>CvSize2D32f r = cvSize2D32f(float width, float height);<BR></PRE>
<P></P>
<LI>带偏移量的长方形尺寸: <PRE>CvRect r = cvRect(int x, int y, int width, int height);<BR></PRE>
<P></P></LI></UL>
<P></P>
<P></P>
<H1><A>图像处理</A> </H1>
<P></P>
<H2><A>分配与释放图像空间</A> </H2>
<P></P>
<UL>
<LI>分配图像空间: <PRE>IplImage* cvCreateImage(CvSize size, int depth, int channels);<BR><BR> size: cvSize(width,height);<BR><BR> depth: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,<BR> IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F<BR><BR> channels: 1, 2, 3 or 4. <BR> 注意数据为交叉存取.彩色图像的数据编排为b0 g0 r0 b1 g1 r1 ...<BR></PRE>
<P>举例: </P><PRE>// 分配一个单通道字节图像<BR>IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); <BR><BR>// 分配一个三通道浮点图像<BR>IplImage* img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);<BR></PRE>
<P></P>
<LI>释放图像空间: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); <BR>cvReleaseImage(&img);<BR></PRE>
<P></P>
<LI>复制图像: <PRE>IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); <BR>IplImage* img2;<BR>img2=cvCloneImage(img1);<BR></PRE>
<P></P>
<LI>设定/获取兴趣区域: <PRE>void cvSetImageROI(IplImage* image, CvRect rect);<BR>void cvResetImageROI(IplImage* image);<BR>vRect cvGetImageROI(const IplImage* image);<BR><BR>大部分OpenCV函数都支持ROI.<BR></PRE>
<P></P>
<LI>设定/获取兴趣通道: <PRE>void cvSetImageCOI(IplImage* image, int coi); // 0=all<BR>int cvGetImageCOI(const IplImage* image);<BR><BR>大部分OpenCV函数暂不支持COI.<BR></PRE>
<P></P></LI></UL>
<P></P>
<H2><A>读取存储图像</A> </H2>
<P></P>
<UL>
<LI>从文件中载入图像: <PRE> IplImage* img=0; <BR> img=cvLoadImage(fileName);<BR> if(!img) printf("Could not load image file: %s\n",fileName);<BR><BR> Supported image formats: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,<BR> SR, RAS, TIFF, TIF<BR></PRE>
<P>载入图像默认转为3通道彩色图像. 如果不是,则需加flag: </P><PRE> img=cvLoadImage(fileName,flag);<BR><BR> flag: >0 载入图像转为三通道彩色图像<BR> =0 载入图像转为单通道灰度图像<BR> <0 不转换载入图像(通道数与图像文件相同).<BR></PRE>
<P></P>
<LI>图像存储为图像文件: <PRE> if(!cvSaveImage(outFileName,img)) printf("Could not save: %s\n",outFileName);<BR></PRE>
<P>输入文件格式由文件扩展名决定. </P>
<P></P></LI></UL>
<P></P>
<H2><A>存取图像元素</A> </H2>
<P></P>
<UL>
<LI>假设需要读取在i行j列像点的第k通道. 其中, 行数i的范围为[0, height-1], 列数j的范围为[0, width-1],
通道k的范围为[0, nchannels-1].
<P></P>
<LI><EM>间接存取:</EM> (比较通用, 但效率低, 可读取任一类型图像数据)
<P></P>
<UL>
<LI>对单通道字节图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);<BR>CvScalar s;<BR>s=cvGet2D(img,i,j); // get the (i,j) pixel value<BR>printf("intensity=%f\n",s.val[0]);<BR>s.val[0]=111;<BR>cvSet2D(img,i,j,s); // set the (i,j) pixel value<BR></PRE>
<P></P>
<LI>对多通道浮点或字节图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);<BR>CvScalar s;<BR>s=cvGet2D(img,i,j); // get the (i,j) pixel value<BR>printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]);<BR>s.val[0]=111;<BR>s.val[1]=111;<BR>s.val[2]=111;<BR>cvSet2D(img,i,j,s); // set the (i,j) pixel value<BR></PRE>
<P></P></LI></UL>
<P></P>
<LI><EM>直接存取:</EM> (效率高, 但容易出错)
<P></P>
<UL>
<LI>对单通道字节图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);<BR>((uchar *)(img->imageData + i*img->widthStep))[j]=111;<BR></PRE>
<P></P>
<LI>对多通道字节图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);<BR>((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B<BR>((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G<BR>((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R<BR></PRE>
<P></P>
<LI>对多通道浮点图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);<BR>((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B<BR>((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G<BR>((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R<BR></PRE>
<P></P></LI></UL>
<P></P>
<LI><EM>用指针直接存取 :</EM> (在某些情况下简单高效)
<P></P>
<UL>
<LI>对单通道字节图像: <PRE>IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);<BR>int height = img->height;<BR>int width = img->width;<BR>int step = img->widthStep/sizeof(uchar);<BR>uchar* data = (uchar *)img->imageData;<BR>data[i*step+j] = 111;<BR></PRE>
<P></P>
<LI>对多通道字节图像: <PRE>IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);<BR>int height = img->height;<BR>int width = img->width;<BR>int step = img->widthStep/sizeof(uchar);<BR>int channels = img->nChannels;<BR>uchar* data = (uchar *)img->imageData;<BR>data[i*step+j*channels+k] = 111;<BR></PRE>
<P></P>
<LI>对单通道浮点图像(假设用4字节调整): <PRE>IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);<BR>int height = img->height;<BR>int width = img->width;<BR>int step = img->widthStep/sizeof(float);<BR>int channels = img->nChannels;<BR>float * data = (float *)img->imageData;<BR>data[i*step+j*channels+k] = 111;<BR></PRE>
<P></P></LI></UL>
<P></P>
<P></P>
<LI><EM>使用 c++ wrapper 进行直接存取:</EM> (简单高效)
<P></P>
<UL>
<LI>对单/多通道字节图像,多通道浮点图像定义一个 c++ wrapper: <PRE>template<class T> class Image<BR>{<BR> private:<BR> IplImage* imgp;<BR> public:<BR> Image(IplImage* img=0) {imgp=img;}<BR> ~Image(){imgp=0;}<BR> void operator=(IplImage* img) {imgp=img;}<BR> inline T* operator[](const int rowIndx) {<BR> return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}<BR>};<BR><BR>typedef struct{<BR> unsigned char b,g,r;<BR>} RgbPixel;<BR><BR>typedef struct{<BR> float b,g,r;<BR>} RgbPixelFloat;<BR><BR>typedef Image<RgbPixel> RgbImage;<BR>typedef Image<RgbPixelFloat> RgbImageFloat;<BR>typedef Image<unsigned char> BwImage;<BR>typedef Image<float> BwImageFloat;<BR></PRE>
<P></P>
<LI>单通道字节图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);<BR>BwImage imgA(img);<BR>imgA[i][j] = 111;<BR></PRE>
<P></P>
<LI>多通道字节图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);<BR>RgbImage imgA(img);<BR>imgA[i][j].b = 111;<BR>imgA[i][j].g = 111;<BR>imgA[i][j].r = 111;<BR></PRE>
<P></P>
<LI>多通道浮点图像: <PRE>IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);<BR>RgbImageFloat imgA(img);<BR>imgA[i][j].b = 111;<BR>imgA[i][j].g = 111;<BR>imgA[i][j].r = 111;<BR></PRE>
<P></P></LI></UL>
<P></P></LI></UL>
<P></P>
<H2><A>图像转换</A> </H2>
<P></P>
<UL>
<LI>转为灰度或彩色字节图像: <PRE>cvConvertImage(src, dst, flags=0);<BR><BR> src = float/byte grayscale/color image<BR> dst = byte grayscale/color image<BR> flags = CV_CVTIMG_FLIP (flip vertically)<BR> CV_CVTIMG_SWAP_RB (swap the R and B channels)<BR></PRE>
<P></P>
<LI>转换彩色图像为灰度图像:
<P></P>
<P><BR>使用OpenCV转换函数: </P><PRE>cvCvtColor(cimg,gimg,CV_BGR2GRAY); // cimg -> gimg<BR></PRE>
<P></P>
<P><BR>直接转换: </P><PRE>for(i=0;i<cimg->height;i++) for(j=0;j<cimg->width;j++) <BR> gimgA[i][j]= (uchar)(cimgA[i][j].b*0.114 + <BR> cimgA[i][j].g*0.587 + <BR> cimgA[i][j].r*0.299);<BR></PRE>
<P></P>
<LI>颜色空间转换:
<P></P><PRE>cvCvtColor(src,dst,code); // src -> dst<BR><BR> code = CV_<X>2<Y><BR> <X>/<Y> = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS<BR><BR>e.g.: CV_BGR2GRAY, CV_BGR2HSV, CV_BGR2Lab<BR></PRE>
<P></P></LI></UL>
<P></P>
<H2><A>绘图命令</A> </H2>
<P></P>
<UL>
<LI>画长方体: <PRE>// 用宽度为1的红线在(100,100)与(200,200)之间画一长方体<BR>cvRectangle(img, cvPoint(100,100), cvPoint(200,200), cvScalar(255,0,0), 1);<BR></PRE>
<P></P>
<LI>画圆: <PRE>// 在(100,100)处画一半径为20的圆,使用宽度为1的绿线<BR>cvCircle(img, cvPoint(100,100), 20, cvScalar(0,255,0), 1);<BR></PRE>
<P></P>
<LI>画线段: <PRE>// 在(100,100)与(200,200)之间画绿色线段,宽度为1<BR>cvLine(img, cvPoint(100,100), cvPoint(200,200), cvScalar(0,255,0), 1);<BR></PRE>
<P></P>
<LI>画一组线段: <PRE>CvPoint curve1[]={10,10, 10,100, 100,100, 100,10};<BR>CvPoint curve2[]={30,30, 30,130, 130,130, 130,30, 150,10};<BR>CvPoint* curveArr[2]={curve1, curve2};<BR>int nCurvePts[2]={4,5};<BR>int nCurves=2;<BR>int isCurveClosed=1;<BR>int lineWidth=1;<BR><BR>cvPolyLine(img,curveArr,nCurvePts,nCurves,isCurveClosed,cvScalar(0,255,255),lineWidth);<BR></PRE>
<P></P>
<LI>画内填充色的多边形: <PRE>cvFillPoly(img,curveArr,nCurvePts,nCurves,cvScalar(0,255,255));<BR></PRE>
<P></P>
<LI>添加文本: <PRE>CvFont font;<BR>double hScale=1.0;<BR>double vScale=1.0;<BR>int lineWidth=1;<BR>cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);<BR><BR>cvPutText (img,"My comment",cvPoint(200,400), &font, cvScalar(255,255,0));<BR></PRE>
<P>Other possible fonts: </P><PRE>CV_FONT_HERSHEY_SIMPLEX, CV_FONT_HERSHEY_PLAIN,<BR>CV_FONT_HERSHEY_DUPLEX, CV_FONT_HERSHEY_COMPLEX,<BR>CV_FONT_HERSHEY_TRIPLEX, CV_FONT_HERSHEY_COMPLEX_SMALL,<BR>CV_FONT_HERSHEY_SCRIPT_SIMPLEX, CV_FONT_HERSHEY_SCRIPT_COMPLEX,<BR></PRE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -