OpenCV 处理图像的基础知识

d478 贡献于2014-05-02

作者 蒋辉  创建于2013-06-04 14:00:11   修改者  修改于2013-08-24 14:04:53字数5593

文档摘要:【OpenCV】访问图像中每个像素的值。IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中Ipl是Intel Image Processing Library的简写。
关键词:

【OpenCV】访问图像中每个像素的值 IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中Ipl是Intel Image Processing Library的简写。以下是IplImage的结构分析(来自OpenCV中文网站:http://www.opencv.org.cn/index.php/Cxcore%E5%9F%BA%E7%A1%80%E7%BB% 93%E6%9E%84#IplImage) 假设你要访问第k通道、第i行、第j列的像素。 Ø 直接访问:(效率高,容易出错) 对我们来说比较重要的两个元素是:char *imageData以及widthStep。imageData存放图像像素数据,而widStep类似CvMat中的step,表示以字节为单位的行数据长度。 一个m*n的单通道字节型图像,其imageData排列如下: 如果我们要遍历图像中的元素,只需: 对于单通道字节型图像: for(i=0,iimageData + i*img->widthStep))[j]=111; /指向第i行的起始位置 对于多通道字节型图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R 对于多通道浮点型图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R 现在,一般的情况下,假设有N-通道,类型为T的图像: I(i,j)c ~ ((T*)(img->imageData + img->widthStep*i))[j*N + c] Ø 基于指针的直接访问:(简单高效) 这种直接访问的方法速度快,但容易出错,我们可以通过定义指针来访问。即: IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); int height = img->height; int width = img->width; int step = img->widthStep/sizeof(uchar); uchar* data = (uchar *)img->imageData; data[i*step+j] = 111; 而多通道(三通道)字节图像中,imageData排列如下: 其中(Bi,Bj)(Gi,Gj)(Ri,Rj)表示图像(i,j)处BGR分量的值。使用指针的遍历方法如下: IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); int height = img->height; int width = img->width; int step = img->widthStep/sizeof(uchar); int channels = img->nChannels; uchar* data = (uchar *)img->imageData; data[i*step+j*channels+k] = 111; 对于多通道浮点型图像(假设图像数据采用 4字节(32 位)行对齐方式): IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); int height = img->height; int width = img->width; int step = img->widthStep/sizeof(float); int channels = img->nChannels; float * data = (float *)img->imageData; data[i*step+j*channels+k] = 111; *如果要修改某像素值,则直接赋值。 Ø 使用cvGet2D()函数间接访问:(通用,但效率低,可访问任意格式的图像) cvGet*D系列函数可以用来返回特定位置的数组元素(一般使用cvGet2D),原型如下: idx0,idx1,idx2分别用来指示元素数组下标,即cvGet2D返回(idx0,idx1)处元素的值。 因此,单通道图像像素访问方式如下: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); CvScalar s; s=cvGet2D(img,i,j); // get the (i,j) pixel value, 注意cvGet2D与cvSet2D中坐标参数的顺序与其它opencv函数坐标参数顺序恰好相反.本函数中i代表y轴,即height;j代表x 轴,即witdth.也即先cvGet2D的第二个参数i表示行号,第三个参数j表示列号。而元素的坐标值的(j,i) printf("intensity=%f\n",s.val[0]); s.val[0]=111; cvSet2D(img,i,j,s); // set the (i,j) pixel value 多通道字节型/浮点型图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); CvScalar s; s=cvGet2D(img,i,j); // get the (i,j) pixel value printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]); s.val[0]=111; s.val[1]=111; s.val[2]=111; cvSet2D(img,i,j,s); // set the (i,j) pixel value 如果是修改元素的值,可用cvSet*D(一般是cvSet2D)函数: 这种方法对于任何图像的访问方式是一样的,比较简单,但效率较低,不推荐使用。 Ø 基于c++ wrapper的直接访问:(更简单高效) 首先定义一个c++ wrapper ‘Image’,然后基于Image 定义不同类型的图像: template class Image { private: IplImage* imgp; public: Image(IplImage* img=0) {imgp=img;} ~Image(){imgp=0;} void operator=(IplImage* img) {imgp=img;} inline T* operator[](const int rowIndx) { return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));} }; typedef struct{ unsigned char b,g,r; } RgbPixel; typedef struct{ float b,g,r; } RgbPixelFloat; typedef Image RgbImage; typedef Image RgbImageFloat; typedef Image BwImage; typedef Image BwImageFloat; 对于单通道字节型图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); BwImage imgA(img); imgA[i][j] = 111; 对于多通道字节型图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); RgbImage imgA(img); imgA[i][j].b = 111; imgA[i][j].g = 111; imgA[i][j].r = 111; 对于多通道浮点型图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); RgbImageFloat imgA(img); imgA[i][j].b = 111; imgA[i][j].g = 111; imgA[i][j].r = 111; 如何访问矩阵元素? 方法是类似的(下面的例子都是针对 0 起点的列和行) 设有32-bit浮点数的实数矩阵M (CvMat* mat): ---------------------------------------------------------------------------- M(i,j) ~ ((float*)(mat->data.ptr + mat->step*i))[j] ---------------------------------------------------------------------------- 设有64-bit浮点数的复数矩阵M (CvMat* mat): ---------------------------------------------------------------------------- Re M(i,j) ~ ((double*)(mat->data.ptr + mat->step*i))[j*2] Im M(i,j) ~ ((double*)(mat->data.ptr + mat->step*i))[j*2+1] ---------------------------------------------------------------------------- 对单通道矩阵,有宏 CV_MAT_ELEM( matrix, elemtype, row, col ), 例如对32-bit浮点数的实数矩阵: M(i,j) ~ CV_MAT_ELEM( mat, float, i, j ), 例如,这儿是一个3x3单位矩阵的初始化: CV_MAT_ELEM( mat, float, 0, 0 ) = 1.f; CV_MAT_ELEM( mat, float, 0, 1 ) = 0.f; CV_MAT_ELEM( mat, float, 0, 2 ) = 0.f; CV_MAT_ELEM( mat, float, 1, 0 ) = 0.f; CV_MAT_ELEM( mat, float, 1, 1 ) = 1.f; CV_MAT_ELEM( mat, float, 1, 2 ) = 0.f; CV_MAT_ELEM( mat, float, 2, 0 ) = 0.f; CV_MAT_ELEM( mat, float, 2, 1 ) = 0.f; CV_MAT_ELEM( mat, float, 2, 2 ) = 1.f; 如何在OpenCV中处理我自己的数据 设你有300x200 32-bit浮点数image/array, 也就是对一个有60000个元素的数组。 ---------------------------------------------------------------------------- int cols = 300, rows = 200; float* myarr = new float[rows*cols]; // 第一步,初始化CvMat头 CvMat mat = cvMat( rows, cols, CV_32FC1, // 32 位浮点单通道类型 myarr // 用户数据指针(数据没有被复制) ); // 第二步,使用cv函数,例如计算 l2 (Frobenius)模 double norm = cvNorm( &mat, 0, CV_L2 ); ... delete myarr; 其它情况在参考手册中有描述。见cvCreateMatHeader,cvInitMatHeader,cvCreateImageHeader,cvSetData 等 ---------------------------------------------------------------------------- 如何读入和显示图像 #include "cv.h" #include "highgui.h" int main( int argc, char** argv ) { IplImage* img; if( argc == 2 && (img = cvLoadImage( argv[1], 1)) != 0 ) { cvNamedWindow( "Image view", 1 ); cvShowImage( "Image view", img ); cvWaitKey(0); // 非常重要,内部包含事件处理循环 cvDestroyWindow( "Image view" ); cvReleaseImage( &img ); return 0; } return -1; } ----------------------------------------------------------------------------

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档