1. 程式人生 > >基礎學習筆記之opencv(24):imwrite函式的使用

基礎學習筆記之opencv(24):imwrite函式的使用

  前言

  OpenCV中儲存圖片的函式在c++版本中變成了imwrite(),這應該是向matlab中影象處理的的一些函式風格靠近吧。儲存圖片這個功能還是很重要的,比如說在寫科研論文的時候需要把一些中間圖片給貼出來,這樣就可以在程式中間利用該函式儲存圖片了。甚至還可以將這些儲存的圖片供後續的matlab處理。本文就簡單介紹下OpenCV中imwrite()函式的用法。不過個人感覺這個函式功能還是不夠強大,使用時有很多限制。

  開發環境:QtCreato2.5.1+OpenCV2.4.3

  實驗基礎

  本次實驗主要是測試imwrite()函式的2個功能:

  1. 測試其是否能夠儲存Mat影象中擷取的一部分影象,比如說用Rect矩陣擷取大的影象中的一部分,由於此時兩者只是用了自己的檔案頭,資料是共享的(沒有采用copyTo()函式或者clone()函式複製),所以這種測試想法很正常。

  2. 測試imwrite()函式的第3個引數的使用。

  在針對第1個測試時,是給定一張原圖,擷取一部分,然後儲存。針對第2個功能是採用OpenCV官網檔案中的一個例子,建立一個alpha表,然後儲存為png格式的圖片,壓縮引數自設定。

  首先來看看imwrite()函式的具體用法。

  bool imwrite(const string& filename, InputArray img, const vector<int>& params=vector<int>() )

  該函式是把程式中的Mat型別的矩陣儲存為影象到指定位置。

  引數filename為所需儲存影象的檔案目錄和檔名。這裡的檔名需要帶有影象格式字尾的,目前OpenCV該函式只支援JPEG,PNG,PPM,PGM,PBM,TIFF等。並不是所有Mat型別都支援。

  img引數為影象資料來源,其型別為Mat。注意也不是所有格式的Mat型資料都能被使用儲存為圖片,目前OpenCV主要只支援單通道和3通道的影象,並且此時要求其深度為8bit和16bit無符號(即CV_16U)。所以其他一些資料型別是不支援的,比如說float型等。如果Mat型別資料的深度和通道數不滿足上面的要求,則需要使用convertTo()函式和cvtColor()函式來進行轉換。convertTo()函式負責轉換資料型別不同的Mat,即可以將類似float型的Mat轉換到imwrite()函式能夠接受的型別。而cvtColor()函式是負責轉換不同通道的Mat,因為該函式的第4個引數就可以設定目的Mat資料的通道數(只是我們一般沒有用到它,一般情況下這個函式是用來進行色彩空間轉換的)。另外也可以不用imwrite()函式來存圖片資料,可以直接用通用的XML IO介面函式將資料存在XML或者YXML中。

  引數params是用來設定對應圖片格式的引數的,因為一般情況下這些圖片格式都是經過了壓縮的,這裡就是設定這些壓縮引數來控制圖片的質量。該引數是一個vector<int>型別,裡面分別存入paramId_1, paramValue_1, paramId_2, paramValue_2, ... 也就是說存入一對屬性值。如果不設定該引數的話,則程式會自動根據所儲存的影象格式採用一個預設的引數。

  本實驗中還用到了下面這個函式。

  template<...> _Tp saturate_cast(_Tp2 v)

  將引數v轉換成模板中的型別,比如說:

  uchar a = saturate_cast<uchar>(-100); 

  OpenCV知識點總結:

  Rect的建構函式中不能過載3個引數,比如左上角點的座標,寬和高這時候應該改成4個,左上角點的座標直接分開為2個寫,對應著了點的x和y。

  實驗結果

  程式執行後工程資料夾中顯示如下:

   

  說明擷取影象部分並儲存是成功的。

  原影象和擷取原圖中間1/4大小的影象如下:

   

  後臺輸出如下:

  

  說明此時也儲存成功了。

  生成的alpha表影象顯示如下:

   

  實驗程式碼及註釋

  main.cpp:

複製程式碼
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

Mat src;
Mat image;
string str = "./";

/*建立alpha表,整體偏紅色,左上角到右下角呈現從完全透明到完全不透明變化趨勢*/
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;    //r分量一直最大,所以整體偏紅
            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()
{
    /*採用預設引數進行圖片的儲存*/
    src = imread("test.jpg");
    imwrite(str+"原圖.jpg", src); //c版本中的儲存圖片為cvSaveImage()函式,c++版本中直接與matlab的相似,imwrite()函式。
    imshow("src", src);
    Rect rect(src.cols/4, src.rows/4, src.cols/2, src.rows/2);
    image = src(rect);
    imwrite(str+"擷取原圖中的一部分割槽域小圖.jpg", image);
    imshow("image", image);

    /*採用自己設定的引數來儲存圖片*/
    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);    //png格式下,預設的引數為3.
    try {
        imwrite("alpha.png", mat, compression_params);
    }
    catch (runtime_error& ex) {
        fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
        return 1;
    }
    fprintf(stdout, "Saved PNG file with alpha data.\n");

    waitKey(0);
    return 0;
}
複製程式碼

  實驗總結

  Imwrite()函式可以儲存截取出的影象,但是這個函式使用時受限制太多,希望後面的版本對其進行加強。

  參考資料

網址:http://www.cnblogs.com/tornadomeet/archive/2012/12/26/2834336.html