生活随笔
收集整理的這篇文章主要介紹了
访问图像中每个像素的值
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載請注明出處:http://blog.csdn.net/xiaowei_cqu/article/details/7557063
!!此篇是基于IplImage* (C接口或者說2.1之前版本的接口,新的Mat的訪問方式請參考博文:
《訪問Mat圖像中每個像素的值》)
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)
[cpp]?view plaincopy
typedef?struct?_IplImage?? ????{?? ????????int??nSize;??????????? ????????int??ID;?????????????? ????????int??nChannels;??????? ????????int??alphaChannel;???? ????????int??depth;?????????? ?? ????????char?colorModel[4];??? ????????char?channelSeq[4];??? ????????int??dataOrder;?????? ?? ????????int??origin;????????? ?? ????????int??align;??????????? ????????int??width;??????????? ????????int??height;?????????? ????????struct?_IplROI?*roi;?? ????????struct?_IplImage?*maskROI;??? ????????void??*imageId;??????? ????????struct?_IplTileInfo?*tileInfo;??? ????????int??imageSize;??????? ????????char?*imageData;???? ????????int??widthStep;????? ????????int??BorderMode[4];??? ????????int??BorderConst[4];??? ????????char?*imageDataOrigin;??? ????}?? ????IplImage;??
直接訪問:
對我們來說比較重要的兩個元素是:char *imageData以及widthStep。imageData存放圖像像素數據,而widStep類似CvMat中的step,表示以字節為單位的行數據長度。
一個m*n的單通道字節型圖像,其imageData排列如下:
如果我們要遍歷圖像中的元素,只需:
[cpp]?view plaincopy
IplImage*?img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);?? uchar*?tmp;?? for(int?i=0;i<img->height;i++)?? ????for(int?j=0;j<img->width;j++)?? ????????*tmp=((uchar?*)(img->imageData?+?i*img->widthStep))[j];??
這種直接訪問的方法速度快,但容易出錯,我們可以通過定義指針來訪問。即:
[cpp]?view plaincopy
IplImage*?img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);?? ucha*?data=(uchar?*)img->imageData;?? int?step?=?img->widthStep/sizeof(uchar);?? uchar*?tmp;?? for(int?i=0;i<img->height;i++)?? ????for(int?j=0;j<img->width;j++)?? ????????*tmp=data[i*step+j];??
而多通道(三通道)字節圖像中,imageData排列如下:
其中(Bi,Bj)(Gi,Gj)(Ri,Rj)表示圖像(i,j)處BGR分量的值。使用指針的遍歷方法如下:
[cpp]?view plaincopy
IplImage*?img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);?? IplImage*?img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);?? uchar*?data=(uchar?*)img->imageData;?? int?step?=?img->widthStep/sizeof(uchar);?? int?channels?=?img->nChannels;?? uchar?*b,*g,*r;?? for(int?i=0;i<img->height;i++)?? ?????for(int?j=0;j<img->width;j++){?? ???????????*b=data[i*step+j*chanels+0];?? ???????????*g=data[i*step+j*chanels+1];?? ???????????*r=data[i*step+j*chanels+2];?? ??????}??
*如果要修改某像素值,則直接賦值。
使用cvGet2D()函數訪問:
cvGet*D系列函數可以用來返回特定位置的數組元素(一般使用cvGet2D),原型如下:
[cpp]?view plaincopy
CvScalar?cvGet1D(?const?CvArr*?arr,?int?idx0?);?? CvScalar?cvGet2D(?const?CvArr*?arr,?int?idx0,?int?idx1?);?? CvScalar?cvGet3D(?const?CvArr*?arr,?int?idx0,?int?idx1,?int?idx2?);?? CvScalar?cvGetND(?const?CvArr*?arr,?int*?idx?);?? idx0,idx1,idx2分別用來指示元素數組下標,即cvGet2D返回(idx0,idx1)處元素的值。
因此,單通道圖像像素訪問方式如下:
[cpp]?view plaincopy
IplImage*?img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);?? double?tmp;?? for(int?i=0;i<img->height;i++)?? ????for(int?j=0;j<img->width;j++)?? ????????tmp=cvGet2D(img,i,j).val[0];?? 多通道字節型/浮點型圖像:
[cpp]?view plaincopy
IplImage*?img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);?? double?tmpb,tmpg,bmpr;?? for(int?i=0;i<img->height;i++)?? ????for(int?j=0;j<img->width;j++){?? ????????tmpb=cvGet2D(img,i,j).val[0];?? ????????tmpg=cvGet2D(img,i,j).val[1];?? ????????tmpr=cvGet2D(img,i,j).val[2];?? ????}??
如果是修改元素的值,可用cvSet*D(一般是cvSet2D)函數:
[cpp]?view plaincopy
void?cvSet1D(?CvArr*?arr,?int?idx0,?CvScalar?value?);?? void?cvSet2D(?CvArr*?arr,?int?idx0,?int?idx1,?CvScalar?value?);?? void?cvSet3D(?CvArr*?arr,?int?idx0,?int?idx1,?int?idx2,?CvScalar?value?);?? void?cvSetND(?CvArr*?arr,?int*?idx,?CvScalar?value?);?? 這種方法對于任何圖像的訪問方式是一樣的,比較簡單,但效率較低,不推薦使用。
總結
以上是生活随笔為你收集整理的访问图像中每个像素的值的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。