1. 程式人生 > >OPENCV學習筆記3_Mat 保存

OPENCV學習筆記3_Mat 保存

crc 靜態 時間 簡單 enc 通道 有符號 eat 最小

1.1 Storing methods(Mat存儲方法)

1. color space

儲像素值需要指定顏色空間和數據類型。顏色空間是指對一個給定的顏色,如何組合顏色元素以對其編碼。最簡單的顏色空間要屬灰度級空間,只處理黑色和白色,對它們進行組合可以產生不同程度的灰色。對於 彩色 方式則有更多種類的顏色空間,但不論哪種方式都是把顏色分成三個或者四個基元素,通過組合基元素可以產生所有的顏色。RGB顏色空間是最常用的一種顏色空間,這歸功於它也是人眼內部構成顏色的方式。它的基色是紅色、綠色和藍色,有時為了表示透明顏色也會加入第四個元素 alpha (A)。有很多的顏色系統,各有自身優勢:

  • RGB是最常見的,這是因為人眼采用相似的工作機制,它也被顯示設備所采用。
  • HSV(hue、saturation、value)和HSL(、lightness)把顏色分解成色調、飽和度和亮度/明度。這是描述顏色更自然的方式,比如可以通過拋棄最後一個元素,使算法對輸入圖像的光照條件不敏感。
  • YCrCb在JPEG圖像格式中廣泛使用。
  • CIE L*a*b*是一種在感知上均勻的顏色空間,它適合用來度量兩個顏色之間的距離 。
2. data type

每個組成元素都有其自己的定義域,取決於其數據類型。最小的數據類型是 char ,占一個字節或者8位,可以是有符號型(0到255之間)或無符號型(-127到+127之間)。盡管使用三個 char 型元素已經可以表示1600萬種可能的顏色(使用RGB顏色空間),但若使用float(4字節,32位)或double(8字節,64位)則能給出更加精細的顏色分辨能力。但同時也要切記增加元素的尺寸也會增加了圖像所占的內存空間。

1.2 Mat accessing pixels(at)

1. vector(向量)

vector是STL中最常見的容器,它是一種順序容器,支持隨機訪問。vector是一塊連續分配的內存,從數據安排的角度來講,和數組極其相似,不同的地方就是:數組是靜態分配空間,一旦分配了空間的大小,就不可再改變了;而vector是動態分配空間,隨著元素的不斷插入,它會按照自身的一套機制不斷擴充自身的容量, 當程序員無法知道自己需要的數組的規模多大時,用其來解決問題可以達到最大節約空間的目的。

#include<vector>
#include <iostream>
using
namespace std; int main() { int i =0; vector<int> g; //Vector to store integers for( i = 0; i < 5; i++ ) { g.push_back( i ); } for( i = 0; i < g.size(); i++ ) { cout << g[ i ] << " "; } cout << endl; return 0; }

技術分享

例如 8U 類型的 RGB 彩色圖像可以使用 <Vec3b>,3 通道 float 類型的矩陣可以使用 <Vec3f>

2. .at(int x, int y)

可以用來存取圖像中對應坐標為(x,y)的元素坐標。

假設提前已知一幅圖像img的數據類型為 unsigned char型灰度圖(單通道),要對坐標為(14,25)的像素重新賦值為25,則對應操作如下:

Mat grayim(600, 800, CV_8UC1);

uchar value = grayim.at<uchar>(i, j);    // 讀出第 i行第 j列像素值

grayim.at<uchar>(i, j) = 128;           // 將第 i行第 j列像素值設置為 128 128

如果要操作的圖片img是一幅數據類型同樣為unsigned char的彩色圖片,再次要求將坐標(14,25)的像素賦值為25,需要對這個像素三個通道的每個對應元素賦值,Opencv中圖像三原色在內存中的排列順序為B-G-R,操作過程如下:

img.at< Vec3b >(14, 25)[0] = 25;//B   

img.at< Vec3b >(14, 25)[1] = 25;//G   

img.at< Vec3b >(14, 25)[2] = 25;//R

需要註意的是,如果要遍歷圖像,並不推薦使用at()函數。使用這個函數的優點是代碼的可讀性高,但是效率並不是很高。

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat    image(600, 800, CV_8UC1);
    Mat    image2(600, 800, CV_8UC3);
    for (int i = 0; i < image.rows; ++i)
    {
        for (int j = 0; j < image.cols; ++j)
        {
            image.at<uchar>(i, j) = 0;
        }
    }
    for (int i = 0; i < image2.rows; ++i)
    {
        for (int j = 0; j < image2.cols; ++j)
        {
            image2.at<Vec3b>(i, j)[0] = 50;
            image2.at<Vec3b>(i, j)[1] = 150;
            image2.at<Vec3b>(i, j)[2] = 250;
        }
    }
    imshow("image", image);
    imshow("image2", image2);
    waitKey(0);

}

技術分享

3. imwrite函數

  bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());

  • filename,擴展名來指定圖像的保存格式(.jpg .png .bmp)
  • params,用來指定圖像的保存編碼方式,對於不同的圖像保存類型,params是不同的值:

    JPEG,參數為CV_IMWRITE_JPEG_QUALITY(圖片質量),值是從0到100,值越小壓縮的越多,默認值是95;

    PNG, 參數為CV_IMWRITE_PNG_COMPRESSION(壓縮級別),值是從0到9,值越大表示圖片尺寸越小,壓縮時間越長。默認值是3;

    PPM,PGM或者PBM,參數為CV_IMWRITE_PXM_BINARY(二進制格式標誌),值是0或者1。默認值是1。

  imwrite只能保存8位(或者是16位無符號(CV_16UC)的PNG,JPEG200或者TIFF圖像)單通道或者三通道的圖像,如果要保存的不是這樣的圖片,可以使用convertTo或者cvtColor來進行轉變。

  下面代碼展示了如果使用imwrite向文件中寫入一個4通道的png圖像

#include<iostream>  
#include<opencv2/opencv.hpp>  
using namespace std;  
using namespace cv;
/*
阿爾法通道(Alpha Channel)是指一張圖片的透明和半透明度。一個使用32位存儲的圖片,每8位表示紅綠藍,和阿爾法通道。
在這種情況下,就不光可以表示透明還是不透明,阿爾法通道還可以表示256級的半透明度。
*/
void createAlphaMat(Mat &mat) // 創建帶Alpha通道的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);
            //UCHAR_MAX的宏定義為0xff,對應的是R通道
            rgba[0] = UCHAR_MAX ; 
            //對於G通道,表示越往右占的百分比就越少,顏色也就越深
            //saturate_cast,限制數據範圍為0~255,超過255的值取255,小於0的值取03
            rgba[1] = saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
            //對於B通道,表示越往下占的百分比就越少,顏色也就越深
            rgba[2] = saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);
            //最後的透明度,是取G和B通道的平均值
            rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
        }
    }
}

int main()
{
    Mat mat(480,640,CV_8UC4);
    
    createAlphaMat(mat);
    //定義一個容器compression_params,容器內的值為int類型
    vector<int> compression_params ;
    //向compression_params裏面添加值
    compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); 
    compression_params.push_back(9);
    imwrite("alpha.png",mat,compression_params);
    // CV_IMWRITE_PNG_COMPRESSION = 9

    return 0;
}

技術分享

OPENCV學習筆記3_Mat 保存