openCv學習筆記(一)——數字圖形的基礎和結構

一圖像基礎

 1 數字圖像 又稱數碼圖像或數位圖像,是二維圖像用有限數字數值像素的表示。數字圖像是由模擬圖像數字化得到的、以像素爲基本元素的、可以用數字計算機或數字電路存儲和處理的圖像。    

 2. 像素  像素(或像元,Pixel)是數字圖像的基本元素,像素是在模擬圖像數字化時對連續空間進行離散化得到的。每個像素具有整數行(高)和列(寬)位置座標,同時每個像素都具有整數灰度值或顏色值。 通常,像素在計算機中保存爲二維整數數阻的光柵圖像,這些值經常用壓縮格式進行傳輸和儲存。   

 3.通道   基本上,描述一個像素點,如果是灰度,那麼只需要一個數值來描述它,就是單通道。如果一個像素點,有RGB三種顏色來描述它,就是三通道.。windows的bmp有時候是一個四通道圖像,R、G、B加上一個A通道,表示透明度。  

  4.分辨率  影象清晰度或濃度的度量標準。舉例來說,分辨率代表垂直及水平顯示的每英寸點(dpi)的數量。BitWare 可以用普通或標準(100 乘 200 dpi)及精細分辨率(200 乘 200 dpi)發送及接收傳真文檔。分辨率是一個表示平面圖像精細程度的概念,通常它是以橫向和縱向點的數量來衡量的,表示成水平點數×垂直點數的形式。在一個固定的平面內,分辨率越高,意味着可使用的點數越多,圖像越細緻。

二  圖像的分類   

灰度圖像: 單色數字圖像,其中每個像素只有一個強度值   

 多普圖像:二維圖像,在每個空間點或像素位置存在一個強度值向量。如果是一幅彩色圖像,則該向量有三個元素   

二值圖像:所有像素值要麼爲0要麼爲1的數字圖像。   

標記圖像:數字圖像,其中的像素值是有限的字符標記。像素的字符值表示該像素做某個判定的結果。

三 圖像的數據結構  

  1.矩陣       

    1.1基本概念:底層圖像表示的最普通的數據結構,矩陣元素是整型的數值,對應於採樣柵格中的相應像素的亮度或其他屬性。這類圖像數據通常是圖像設備的直接輸出。矩陣中的圖像信息可以通過像素的座標得到,座標對應於行和列的標號,矩陣圖像是一個完整的表示,與圖像數據的內容無關。      

   1.2矩陣表示的圖像:二值圖像:用僅含0和1的矩陣表示;多光譜圖像:可以用幾個矩陣來表示,每個矩陣含有一個頻帶的圖像;分層圖像數據結構:用不同分辨率的矩陣來獲得。圖像的這種分層表示對於處理機陣列結構的並行計算機會是非常的方便。   

   2.鏈      

     2.1鏈碼:常用來描述物體的邊界,或者圖像中一個像素寬度的線條。邊界由其參考像素的座標和一序號序列來定義,符號對應於幾個事先定義好了方向的單位長度的線段。注意,鏈碼本身是相對的,數據是相對於某個參考點來表示的。用鏈碼錶示圖像適合基於形式語言理論的句法模式識別。     

    2.2行程編碼:通常用於圖像矩陣中符號串的表示。   

   3拓撲數據結構     

     3.1賦值圖:是指弧、節點或兩者都帶有數值的圖。      

      3.2區域鄰接圖:其中節點賭贏與區域,相鄰的區域用弧連接起來。    

    4分層數據結構       

        分層數據結構可以使特殊的算法在相對較小的數據量基礎上決定處理策略,只對圖像中實質部分進行最精細的分辨率工作。       

        4.1金字塔:屬於最簡單的分層數據結構。有M型金字塔和T型金字塔。主要是描述多個圖像分辨率的數據結構。       

         4.2四叉樹:是對T型金字塔的改進。圖像中的選擇區域比其他區域在跟高的分辨率上存儲,允許選擇性的提取細節。

四 openCV中的基本結構      

   對於openCv中的數據結構,這裏這討論三個cvArr,cvMat和IplImage     

     4.1CvArr:一個抽象基類,CvArr* 僅僅是被用於作函數的參數,用於指示函數接收的數組類型可以不止一個,如 IplImage*, CvMat* 甚至 CvSeq*. 最終的數組類型是在運行時通過分析數組頭的前4 個字節判斷。     

    4.2CvMat:多通道矩陣,以下是其結構體

typedef struct CvMat
  {
  int type; /* CvMat 標識 (CV_MAT_MAGIC_VAL), 元素類型和標記 */
  int step; /* 以字節爲單位的行數據長度*/
  int* refcount; /* 數據引用計數 */
  union
   {
    uchar* ptr;
    short* s;
    int* i;
    float* fl;
    double* db;
   } data; /* data 指針 */
  #ifdef __cplusplus
  union
   {
     int rows;
     int height;
   };
  union
   {
     int cols;
     int width;
   };
  #else
   int rows; /* 行數 */
   int cols; /* 列數*/
  #endif
 } CvMat;
     CvMat這個類有兩部分數據。一個是matrix header,這部分的大小是固定的,包含矩陣的大小,存儲的方式,矩陣存儲的地址等等,如以上結構。另一個部分是一個指向矩陣包含像素值的指針。   

  4.2.1CvMat的創建和訪問         

 CvMat* cvCreateMat(int rows,int cols,int type)//創建二維矩陣,其中type可以爲以下幾種類型(摘自http://blog.csdn.net/yang_xian521/article/details/7107786#)        

說到數據的存儲,這一直就是一個值得關注的問題,Mat_<uchar>對應的是CV_8U,Mat_<uchar>對應的是CV_8U,Mat_<char>對應的是CV_8S,Mat_<int>對應的是CV_32S,Mat_<float>對應的是CV_32F,Mat_<double>對應的是CV_64F,對應的數據深度如下:

 CV_8U - 8-bit unsigned integers ( 0..255 )

CV_8S - 8-bit signed integers ( -128..127 )• CV_16U - 16-bit unsigned integers ( 0..65535 )

CV_16S - 16-bit signed integers ( -32768..32767 )

 CV_32S - 32-bit signed integers ( -2147483648..2147483647 )

CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )

 CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )       

  實例代碼

#include<cv.h>
#include<highgui.h>
#include<iostream>
//using namespace cv;
using namespace std;
int main()
{
    //矩陣的創建
	CvMat* mat1=cvCreateMat(2,2,CV_32FC1);//創建矩陣 
	/*
    CV32FC1-有n行三列;CV32FC3 n行一列
	*/

	*((float *)CV_MAT_ELEM_PTR(*mat1,0,0))=0.1;
	*((float *)CV_MAT_ELEM_PTR(*mat1,0,1))=0.2;
	*((float *)CV_MAT_ELEM_PTR(*mat1,1,0))=0.3;
	*((float *)CV_MAT_ELEM_PTR(*mat1,1,1))=0.4;
    CvMat* mat2 = cvCreateMatHeader(5,5,CV_32FC1);//創建矩陣頭信息
	CvMat mat3;
	float valus[] = {0.1,0.2,0.3,0.4};
	cvInitMatHeader(&mat3,2,2,CV_32FC1,valus);
	//矩陣中簡單得到元素——1
	float mat1_elem = CV_MAT_ELEM(*mat1,float,0,0);
	float mat3_elem = CV_MAT_ELEM(mat3,float,1,1);
	cout<<mat1_elem<<endl;
	cout<<mat3_elem<<endl;
    //矩陣中恰當得到元素——2
	//累加通道中的所有元素
    float s=0.0f;
	for(int row =0;row<mat1->rows;row++)
	{
		const float* ptr = (const float *)(mat1->data.ptr+row*mat1->step);//切換行
		for(int col=0;col<mat1->cols;col++)//每行的累加和
		{
			cout<<*ptr<<" ";
			s+=*ptr++;
		}
		cout<<endl;
	}
   // float elem = CV_MAT_ELEM(*mat,float,3,2);
	//cout<<elem<<endl;
	return 0;
}

    對於以上的CvMat現在已經推出Mat類,功能強大。。。,在下一篇中介紹

   4.3 IplImge


 

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 只支持其中的一個子集: 

alphaChannel 在OpenCV中被忽略。 
colorModel 和channelSeq 被OpenCV忽略。OpenCV顏色轉換的唯一函數 cvCvtColor把原圖像的顏色空間的目標圖像的顏色空間作爲一個參數。
dataOrder 必須是IPL_DATA_ORDER_PIXEL (顏色通道是交叉存取),然而平面圖像的被選擇通道可以被處理,就像COI(感興趣的通道)被設置過一樣。
align 是被OpenCV忽略的,而用 widthStep 去訪問後繼的圖像行。 
不支持maskROI 。處理MASK的函數把他當作一個分離的參數。MASK在 OpenCV 裏是 8-bit,然而在 IPL他是 1-bit。 
tileInfo 不支持。 
BorderMode和BorderConst是不支持的。每個 OpenCV 函數處理像素的鄰近的像素,通常使用單一的固定代碼邊際模式。 
除了上述限制,OpenCV處理ROI有不同的要求。要求原圖像和目標圖像的尺寸或 ROI的尺寸必須(根據不同的操作,例如cvPyrDown 目標圖像的寬(高)必須等於原圖像的寬(高)除以2 ±1)精確匹配,而IPL處理交叉區域,如圖像的大小或ROI大小可能是完全獨立的。

            以上摘自文檔。

#include<cv.h>
#include<highgui.h>
#include<iostream>
//using namespace cv;
using namespace std;
int main()
{
	//遍歷圖像,將三通道的HSV圖像,在色度保持不變的情況下,設置每個點的飽和度和高度爲255.
	IplImage* imge = cvLoadImage("test.jpg");
	if(!imge)
	{
	}
	IplImage* imge_result=cvCreateImage(cvGetSize(imge),imge->depth,imge->nChannels) ;
	cvCopyImage(imge,imge_result);
	for(int y=0;y<imge_result->height;y++)
	{
		uchar* ptr = (uchar *)(imge_result->imageData + y*imge_result->widthStep);
		for(int x=0;x<imge_result->width;x++)
		{
			ptr[3*x+1] = 255;
			ptr[3*x+2] = 255;
		}
	}
	cvNamedWindow("原圖");
    cvNamedWindow("result");
	cvShowImage("原圖",imge);
	cvShowImage("result",imge_result);
	cvWaitKey(0);
    cvReleaseImage(&imge);
	cvReleaseImage(&imge_result);
	cvDestroyWindow("原圖");
	cvDestroyWindow("result");
	return 0;
}


可以說,這種方式是遍歷最快的,但是要單獨的找去哪一個元素效率就不行了。

其實,些這些東西,基本上全是參考的。對於結構的瞭解還是不行,還要繼續努力呀

發佈了13 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章