OpenCV(三) 之 基本數據結構 CvMat和 IplImage


OpenCV(三) 之 基本數據結構 CvMat和 IplImage

OpenCv中基本的數據類型

類型 參數 表示
CvPoint int x,y 像素點
CvPoint2D32f float x,y 平面點
CvPoint3D32f float x,y,z 空間點
CvSize int width,height 圖像大小
CvSize2D32f float x, y 區域大小
CvSize3D32f float x,y,z 立方體大小
CvRect int x,y,width,height 矩形區域
CvScalar double val[4] RGBA 值

類型的構造函數僅是類型名首字母小寫,比如cvPoint(int x,int y),除了CvScalar

CvScalar類型是可以用來存放4個double類型的數組,最多四個不一定要四個

  1. typedef struct CvScalar 

  2. double val[4]; 
  3. }; 

其賦值函數有四種

  1. 1. CvScalar cvScalar(double v0,double v1,double v2, double v3)
  2. 2. CvScalar cvRealScalar(double v0)
  3. //第一個數值賦值,剩余三個為0 
  4. 3. CvScalar cvScalarAll(double v)
  5. //所有的四個值都相同 
  6. 4. CV_RGB 
  7. #define CV_RGB(r,g,b) cvScalar(b,r,g,0); 

CvMat類型

  1. typedef struct CvMat { 
  2. int type; 
  3. int step; 
  4. int* refcount; // for internal use only 
  5. union
  6. uchar* ptr; 
  7. short* s; 
  8. int* i; 
  9. float* fl; 
  10. double* db; 
  11. } data; 
  12. union
  13. int rows; 
  14. int height; 
  15. }; 
  16. union
  17. int cols; 
  18. int width; 
  19. }; 
  20. } CvMat; 

其構造函數

  1. CvMat* cvCreateMat(int rows,int cols,int type); 
  2. CvMat* cvCreateMatHeader(int rows,int cols,int type); 
  3. CvMat* cvInitMatHeader(CvMat *mat,int rows,int cols,int type, void* data=NULL, int step = CV_AUTOSTEP) 
  4. CvMat* cvCloneMat(CvMat*) 
  5.  
  6. //內存釋放 
  7. void cvReleaseMat(CvMat** mat) 

使用數組創建CvMat

  1. float vals[4]=[1,2,3,4]; 
  2. CvMat* mat; 
  3. cvInitMatHeader(mat,2,2,CV_32FC1,vals); 

CvMat屬性值的獲取

  1. cvGetElemType(const CvArr* arr);//返回數據類型 
  2. cvGetDims(const CvArr* arr,int* sizes=NULL);//返回CvMat的維數,相當於張量的階數, int* 可以用來存儲每一維對應的長度 
  3. cvGetDimSize(const CvArr* arr,int index);//返回第index維度上的長度 

CvMat數據值的讀取

  1. float sum( const CvMat* mat )  

  2. float s = 0.0f
  3. for(int row=0; row<mat->rows; row++ )  

  4. const float* ptr = (const float*)(mat->data.ptr + row * mat->step); 
  5. for( col=0; col<mat->cols; col++ ) 

  6. s += *ptr++; 


  7. return( s ); 

這里要注意的是

  1. 要強制指定數據類型,因為CvMat定義中數據類型是union。

  2. 使用step參數是每一行所占的字節數,並不等於cols*sizeof(bytes),因為含有優化的地址對齊問題。

CvMat矩陣數據存儲順序是先行再列,3D數據存儲順序是每個位置的channels,然后按行、列排列。

下圖時一組空間點存到不同的CvMat的存儲結果

enter description here

1477837579893.jpg

IplImage

  1. typedef struct _IplImage{ 
  2. int nSize; 
  3. int ID; 
  4. int nChannels; //**type 
  5. int alphaChannel; 
  6. int depth; //**type 
  7. int dataOrder; //數組存儲結構,是按照像素存IPL_DATA_ORDER_PIXEL,還是先按照通道存IPL_DATA_ORDER_PLANE 
  8. int origin; //圖像坐標原點位於左上角 IPL_ORIGIN_TL,還是左下角IPL_ORIGIN_BL 
  9. int align; 
  10. int width; //**columns 
  11. int height; //**rows 
  12. char colorModel[4]; 
  13. char channelSeq[4]; 
  14. struct _IplROI* roi; //region of interest 
  15. struct _IplImage* maskROI; 
  16. void* imageId; 
  17. struct _IplTileInfo* tileInfo; 
  18. int imageSize; 
  19. char* imageData; //** data 
  20. int widthStep; //** step 
  21. int BorderMode[4]; 
  22. int BorderConst[4]; 
  23. char* imageDataOrigin; 

其中注釋**部分對應着CvMat的成員變量,CvMat的type成員被拆分成了兩個屬性:depth, nChannels表示像素值深度和圖像的通道數
depth的取值有

  1. IPL_DEPTH_8U; IPL_DEPTH_8S; IPL_DEPTH_16S; IPL_DEPTH_32S; IPL_DEPTH_32F; IPL_DEPTH_64F; 

看字面就知道什么意思了。

IplROI包含的屬性:

  1. int xOffset, yOffset; //x,y 方向的偏置 
  2. int height, width; //感興趣區域的大小 
  3. int COI; //Channel of Interest,感興趣的通道 

一旦ROI設置了,那么對圖像的操作將盡在ROI內操作。

IplImage數據的訪問示例

對於HSV圖像,希望將S,V通道值設置為255:

  1. void saturate_sv(IplImage* img) 

  2. for(int y=0;y<img->height;y++) 

  3. uchar* ptr=(uchar*)(img->imageData+y*img->widthStep); 
  4. for(int x=0;x<img->width;i++) 

  5. ptr[3*x+1]=255
  6. ptr[3*x+2]=255



這里奇怪為什么默認img->dataOrder=IPL_DATA_ORDER_PIXEL。這是因為

We say that dataOrder may be either IPL_DATA_ORDER_PIXEL of IPL_DATA_ORDER_PLANE, but in fact only IPL_DATA_ORDER_PIXEL is supported by OpenCV. Both values are generally supported by IPL/IPP, but OpenCV always uses interleaved images.

Note: 比較CvMat和IplImage數據區的操作,發現IplImage->imageData並沒有進行類型轉換,全部都是byte字節,而CvMat則需要轉換成所存儲數據的類型,在指針運算時需要特別注意,尤其是IplImage和CvMat進行計算時。

ROI的使用:

  1. void cvSetImageROI(IplImage* image, CvRect rect); //設置rect區域為感興趣區域 
  2. void cvResetImageROI(IplImage* image); //取消圖像的感興趣區域 
  1. #include "highgui.h" 
  2. #include "cv.h" 
  3. int main(int argc, char** argv) 

  4. // 圖像路徑、ROI的x,y偏移量, 長和寬、像素值增加量 
  5. IplImage* src; 
  6. if (argc == 7 && ((src = cvLoadImage(argv[1])) != 0)) 

  7. int xOffset = atoi(argv[2]); //x偏移 
  8. int yOffset = atoi(argv[3]); //y偏移 
  9. int width = atoi(argv[4]); //ROI寬 
  10. int height = atoi(argv[5]); //ROI高 
  11. int add = atoi(argv[6]); //每個像素值增加量 
  12.  
  13. cvSetImageROI(src, cvRect(xOffset, yOffset, width, height)); 
  14. cvAddS(src, cvScalarAll(add), src); 
  15. cvResetImageROI(src); 
  16. cvNamedWindow("src"); 
  17. cvShowImage("src", src); 
  18. cvWaitKey(0); 
  19. cvReleaseImage(&src); 
  20. cvDestroyWindow("src"); 
  21.  

  22.  

enter description here

1478005187960.jpg

上述過程還存在另一種直接地址操作的方法

  1. #include "highgui.h" 
  2. #include "cv.h" 
  3. int main(int argc, char** argv) 

  4. // 圖像路徑、ROI的x,y偏移量, 長和寬、像素值增加量 
  5. IplImage* src; 
  6. if (argc == 7 && ((src = cvLoadImage(argv[1])) != 0)) 

  7. int xOffset = atoi(argv[2]); //x偏移 
  8. int yOffset = atoi(argv[3]); //y偏移 
  9. int width = atoi(argv[4]); //ROI寬 
  10. int height = atoi(argv[5]); //ROI高 
  11. int add = atoi(argv[6]); //每個像素值增加量 
  12.  
  13. IplImage * sub_img = cvCreateImageHeader(cvSize(width, height), src->depth, src->nChannels); 
  14. sub_img->widthStep = src->widthStep; 
  15. sub_img->imageData = src->imageData + yOffset*src->widthStep + xOffset*src->nChannels; 
  16.  
  17. cvAddS(sub_img, cvScalarAll(add), sub_img); 
  18. cvReleaseImageHeader(&sub_img); 
  19.  
  20. cvResetImageROI(src); 
  21. cvNamedWindow("src"); 
  22. cvShowImage("src", src); 
  23. cvWaitKey(0); 
  24. cvReleaseImage(&src); 
  25. cvDestroyWindow("src"); 
  26.  

  27.  

這里很容易理解,就是將ROI截取出來作為一個新的圖像,需要注意的時sub_img並沒有新分配地址,數據區指向的仍然是src的數據區,此時圖像sub_img的數據區並不是連續的,所以將src->widthStep賦值給sub_img-》widthStep保證讀取正確的地址數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM