OpenCV2:Mat


1.Mat基礎

在計算機內存中,數字圖像是已矩陣的形式保存的。OpenCV2中,數據結構Mat是保存圖像像素信息的矩陣,它主要包含兩部分:矩陣頭和一個指向像素數據的矩陣指針。
矩陣頭主要包含,矩陣尺寸、存儲方法、存儲地址和引用次數等。
矩陣頭的大小是一個常數,不會隨着圖像的大小而改變,但是保存圖像像素數據的矩陣則會隨着圖像的大小而改變,通常數據量會很大,比矩陣頭大幾個數量級。這樣,在圖像復制和傳遞過程中,主要的開銷是由存放圖像像素的矩陣而引起的。因此,OpenCV使用了引用次數,當進行圖像復制和傳遞時,不再復制整個Mat數據,而只是復制矩陣頭和指向像素矩陣的指針。例如:
cv::Mat a ;//創建矩陣頭
a = cv::imread("f:\\psb.jpg");//讀入圖像
cv::Mat b = a ;//復制 
上面的a,b有各自的矩陣頭,但是其矩陣指針指向同一個矩陣,也就是其中任何一個改變了矩陣數據都會影響另外一個。
那么,多個Mat共用一個矩陣數據,最后誰來釋放矩陣數據呢?
這就是引用計數的作用,當Mat對象每被復制一次時,就會將引用計數加1,而每銷毀一個Mat對象(共用同一個矩陣數據)時引用計數會被減1,當引用計數為0時,矩陣數據會被清理。
 
上圖是Mat對象a,b共用一個矩陣,故其引用計數refcount為2.
但是有些時候仍然會需要復制矩陣數據本身(不只是矩陣頭和矩陣指針),這時候可以使用clone 和copyTo方法。
cv::Mat c = a.clone();
cv::Mat d ;
a.copyTo(d);
上面代碼中的c,d各自擁有自己的矩陣,改變自己的矩陣數據不會相互影響。
在使用Mat中,需要記住:
  1. OpenCV中的內存分配是自動完成的(不是特別指定的話)
  2. 使用OpenCV的C++ 接口時不需要考慮內存釋放問題
  3. Mat的賦值運算和拷貝構造函數只會拷貝矩陣頭,仍然共同同一個矩陣
  4. 如果要復制矩陣數據,可以使用clone和copyTo函數

2.Mat存儲方法

Mat中矩陣的每個元素可以使用不同的數據類型,最小的數據類型是char,占用一個字節或者8位,可以是有符號的(0到255)或者是無符號的(-127到127)。在RGB顏色空間中,使用三個char類型可以表示1600萬中顏色,但在圖像處理的過程中有可能會使用到float或者double來表示圖像的像素。

Mat的創建

構造函數
cv::Mat img(2,2,CV_8UC3,cv::Scalar(0,0,255));
上述代碼創建了一個2行2列的矩陣,矩陣元素使用8位無符號char類型保存,具有3通道,每個像素的初始值是(0,0,255)
構造函數的前兩個參數指定了矩陣的行和列
第三個參數指定矩陣元素的數據類型以及通道數,其指定規則如下:
CV_[The number of bits per item][Signed or Unsigned][TypePrefix]C[The channel number]
四部分分別指定:元素的大小,是有符號還是無符號,數據類型以及通道數
最后一個參數,Scalar是short型的vector,提供矩陣的初始化。
Create方法
該方法不能為矩陣設置初始值,只是在改變尺寸時為矩陣數據重新分配內存。使用方法:
img.create(4,4,CV_8UC(2));
創建了一個4行4列有2個通道的矩陣
MATLAB形式的初始化
cv::Mat e = cv::Mat::eye(4,4,CV_64F);
cv::Mat z = cv::Mat::ones(2,2,CV_32F);
cv::Mat o = cv::Mat::zeros(3,3,CV_8UC1);
Mat e是4行4列的對角矩陣
Mat z是2行2列的單位矩陣
Mat o是3行3列的零矩陣
小矩陣的初始化
對於小矩陣可以使用逗號分割的初始化函數
Mat c =(Mat_<double>(3,3)<<1,2,3,0,-1,0,4,5,6);
在對圖像進行模板運算時,定義模板使用這種方法是很方便的。

3.Mat的輸入輸出

使用imread函數,向Mat對象中寫入一個圖像。
a = cv::imread("f:\\psb.jpg");//讀入圖像
imread的原型如下
cv::Mat imread(const string& filename,int flags=1)
filename指定要讀取圖像的位置
flags指定圖像的顏色空間  
    flags > 0 3通道的彩色圖像
     flags = 0 灰度圖像
    flags < 0 不作改變
也可以有以下的枚舉值
CV_LOAD_IMAGE_ANYDEPTH、 CV_LOAD_IMAGE_COLOR、 CV_LOAD_IMAGE_GRAYSCALE
 
使用imwrite函數,將Mat對象保存到指定的文件中。
imwrite的函數原型如下:
bool imwrite(const string& filename,InputArray img,constvector<int>& params=vector<int>())
filename,指定的文件
img  要保存的Mat對象
params 用來指定圖像的保存編碼方式。
使用filename的擴展名來指定圖像的保存格式(.jpg  .png  .bmp),對於不同的圖像保存類型,params是不同的值
  • JPEG,params用來指定圖像的質量(0到100),默認的是95.  CV_IMWRITE_JPEG_QUALITY
  • PNG,params用來指定圖像的壓縮級別(0到9),壓縮級別越高圖像占用的空間越小,保存圖像所用的時間越久。默認值是3. CV_IMWRITE_PNG_COMPRESSION
  • PPM,PGM,PBM,params是一個標記(0或者1),默認的是1.CV_IMWRITE_PXM_BINARY
imwrite只能保存8位( 或者是16位無符號(CV_16UC)的PNG,JPEG200或者TIFF圖像) 單通道或者三通道的圖像, 如果要保存的不是這樣的圖片,可以使用convertTo或者cvtColor來進行轉變。
下面代碼展示了如果使用imwrite向文件中寫入一個4通道的png圖像
void createAlphaMat(Mat &mat) 
{
    for(int i = 0 ; i < mat.rows ; i ++) {
        for(int j = 0 ; j < mat.cols ; j ++) {
            Vec4b &rgba = mat.at<Vec4b>(i,j);
            rgba[0] = UCHAR_MAX ;
            rgba[1] = saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
            rgba[2] = saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);
            rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
        }
    }
}
int main()
{
    Mat mat(480,640,CV_8UC4);
    createAlphaMat(mat);

    vector<int> compression_params ;
    compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
    compression_params.push_back(9);

    imwrite("alpha.png",mat,compression_params);

    return 0;
}

 

4.Mat的顯示

OpenCV提供了用以窗口的形式顯示圖片的方法,代碼如下:
Mat img = imread("f:\psb.jpg");
const string name ="Hu";
namedWindow(name);
imshow(name,img);
waitKey();
 
 


免責聲明!

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



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