1. 程式人生 > >3、圖片的載入、顯示和輸出

3、圖片的載入、顯示和輸出

手動 默認 像素 pla 意思 opengl ports normal imread

一、關於opencv的命名空間

OpenCV中的C++類和函數都是定義在命名空間cv之內的,有兩種方法可以訪問。

  (1)在代碼開頭的適當位置,加上usingnamespace cv;這句。

  (2)在使用OpenCV類和函數時,都加入cv::命名空間。

一般都采用第二種。

【示例】

1     #include <opencv2/core/core.hpp>
2     #include<opencv2/highgui/highgui.hpp>
3      
4     using namespace cv;

二、關於Mat類型

  cv::Mat類是用於保存圖像以及其他矩陣數據的數據結構。默認情況下,其尺寸為0,我們也可以指定初始尺寸,比如,比如定義一個Mat類對象,就要寫 cv::Mat pic(320

,640,cv::Scalar(100));

  Mat類型作為OpenCV2新紀元的重要代表“人物”,它是對應於OpenCV1.0時代的IplImage的主要用來存放圖像的數據結構。

1  Mat myMat= imread("dota.jpg");

  表示從工程目錄下把一幅名為dota.jpg的jpg類型的圖像載入到Mat類型的myMat中。這裏的imread函數這篇文章的下文就會詳細剖析到。

三、圖像的載入和顯示

  在新版本的OpenCV2中,最簡單的圖像載入和顯示只需要3句代碼,非常便捷。這三句代碼分別對應了三個函數,他們分別是:

imread( ), namedWindow( )以及imshow( )。

1.imread函數

函數原型如下:

1 Mat imread(const string& filename, intflags=1 );

第一個參數,const string&類型的filename,填我們需要載入的圖片路徑名,支持的圖片類型有:

1     位圖 - *.bmp, 
2     JPEG文件 - *.jpeg, *.jpg, *.jpe
3     JPEG 2000文件- *.jp2
4     PNG圖片 - *.png
5     便攜文件格式- *.pbm, *.pgm, *.ppm
6     TIFF 文件 - *.tiff, *.tif

  第二個參數,int類型的flags,為載入標識,它指定一個加載圖像的顏色類型。可以看到它自帶缺省值1.所以有時候這個參數在調用時我們可以忽略,在看了下面的講解之後,我們就會發現,如果在調用時忽略這個參數,就表示載入三通道的彩色圖像。

  可以在OpenCV中標識圖像格式的枚舉體中取值。通過轉到定義,我們可以在higui_c.h中發現這個枚舉的定義是這樣的:

 1 enum
 2 {
 3 /* 8bit, color or not */
 4    CV_LOAD_IMAGE_UNCHANGED  =-1,
 5 /* 8bit, gray */
 6    CV_LOAD_IMAGE_GRAYSCALE  =0,
 7 /* ?, color */
 8    CV_LOAD_IMAGE_COLOR      =1,
 9 /* any depth, ? */
10    CV_LOAD_IMAGE_ANYDEPTH   =2,
11 /* ?, any color */
12    CV_LOAD_IMAGE_ANYCOLOR   =4
13 };

相應的解釋:

1     CV_LOAD_IMAGE_UNCHANGED,這個標識在新版本中被廢置了,忽略。
2     CV_LOAD_IMAGE_ANYDEPTH- 如果取這個標識的話,若載入的圖像的深度為16位或者32位,就返回對應深度的圖像,否則,就轉換為8位圖像再返回。
3     CV_LOAD_IMAGE_COLOR- 如果取這個標識的話,總是轉換圖像到彩色一體
4     CV_LOAD_IMAGE_GRAYSCALE- 如果取這個標識的話,始終將圖像轉換成灰度1

  如果輸入有沖突的標誌,將采用較小的數字值。比如CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 將載入3通道圖。

  如果想要載入最真實的圖像,選擇CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR。

因為flags是int型的變量,如果我們不在這個枚舉體中取值的話,還可以這樣來:

  • flags >0返回一個3通道的彩色圖像。
  • flags =0返回灰度圖像。
  • flags <0返回包含Alpha通道的加載的圖像。

需要註意的點:輸出的圖像默認情況下是不載入Alpha通道進來的。如果我們需要載入Alpha通道的話呢,這裏就需要取負值。

【示例】

1 Mat image0=imread("dota.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);//載入最真實的圖像
2 Mat image1=imread("dota.jpg",0);//載入灰度圖
3 Mat image2=imread("dota.jpg",199);//載入3通道的彩色圖像
4 Mat logo=imread("dota_logo.jpg");//載入3通道的彩色圖像

2.namedWindow函數

顧名思義,namedWindow函數,用於創建一個窗口。函數原型是這樣的:

void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE ); 

第一個參數,const string&型的name,即填被用作窗口的標識符的窗口名稱。

第二個參數,int 類型的flags ,窗口的標識,可以填如下的值:

1 WINDOW_NORMAL設置了這個值,用戶便可以改變窗口的大小(沒有限制)
2 WINDOW_AUTOSIZE如果設置了這個值,窗口大小會自動調整以適應所顯示的圖像,並且不能手動改變窗口大小。
3 WINDOW_OPENGL 如果設置了這個值的話,窗口創建的時候便會支持OpenGL。

函數剖析:

  首先需要註意的是,它有默認值WINDOW_AUTOSIZE,所以,一般情況下,這個函數我們填一個變量就行了。

  namedWindow函數的作用是,通過指定的名字,創建一個可以作為圖像和進度條的容器窗口。如果具有相同名稱的窗口已經存在,則函數不做任何事情。

  我們可以調用destroyWindow()或者destroyAllWindows()函數來關閉窗口,並取消之前分配的與窗口相關的所有內存空間。但話是這樣說,其實對於代碼量不大的簡單小程序來說,我們完全沒有必要手動調用上述的destroyWindow()或者destroyAllWindows()函數,因為在退出時,所有的資源和應用程序的窗口會被操作系統會自動關閉。

3.imshow函數

在指定的窗口中顯示一幅圖像。

void imshow(const string& winname, InputArray mat);

第一個參數,const string&類型的winname,填需要顯示的窗口標識名稱。

第二個參數,InputArray 類型的mat,填需要顯示的圖像。

這裏的InputArray 我們講一下吧,不然一直是個梗在這邊。

我們可以在Highgui.hpp中查到imshow的原型:

1 CV_EXPORTS_W void imshow(const string&winname, InputArray mat);

在core.hpp中查到一個typedef聲明:

1 typedef const _InputArray& InputArray;

這其實一個類型聲明引用,就是說_InputArray和InputArray是一個意思,在core.hpp可以發現了InputArray的真身:

 1 class CV_EXPORTS _InputArray
 2 {
 3 public:
 4    enum {
 5        KIND_SHIFT = 16,
 6        FIXED_TYPE = 0x8000 << KIND_SHIFT,
 7        FIXED_SIZE = 0x4000 << KIND_SHIFT,
 8        KIND_MASK = ~(FIXED_TYPE|FIXED_SIZE) - (1 << KIND_SHIFT) + 1,
 9  
10        NONE              = 0 <<KIND_SHIFT,
11        MAT               = 1 <<KIND_SHIFT,
12        MATX              = 2 <<KIND_SHIFT,
13        STD_VECTOR        = 3 <<KIND_SHIFT,
14        STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
15        STD_VECTOR_MAT    = 5 <<KIND_SHIFT,
16        EXPR              = 6 <<KIND_SHIFT,
17        OPENGL_BUFFER     = 7 <<KIND_SHIFT,
18        OPENGL_TEXTURE    = 8 <<KIND_SHIFT,
19        GPU_MAT           = 9 <<KIND_SHIFT,
20        OCL_MAT           =10 <<KIND_SHIFT
21    };
22    _InputArray();
23  
24    _InputArray(const Mat& m);
25    _InputArray(const MatExpr& expr);
26    template<typename _Tp> _InputArray(const _Tp* vec, int n);
27    template<typename _Tp> _InputArray(const vector<_Tp>&vec);
28    template<typename _Tp> _InputArray(constvector<vector<_Tp> >& vec);
29    _InputArray(const vector<Mat>& vec);
30    template<typename _Tp> _InputArray(const vector<Mat_<_Tp>>& vec);
31    template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
32    template<typename _Tp, int m, int n> _InputArray(constMatx<_Tp, m, n>& matx);
33    _InputArray(const Scalar& s);
34    _InputArray(const double& val);
35    // < Deprecated
36    _InputArray(const GlBuffer& buf);
37    _InputArray(const GlTexture& tex);
38    // >
39    _InputArray(const gpu::GpuMat& d_mat);
40    _InputArray(const ogl::Buffer& buf);
41    _InputArray(const ogl::Texture2D& tex);
42  
43    virtual Mat getMat(int i=-1) const;
44    virtual void getMatVector(vector<Mat>& mv) const;
45    // < Deprecated
46    virtual GlBuffer getGlBuffer() const;
47    virtual GlTexture getGlTexture() const;
48    // >
49    virtual gpu::GpuMat getGpuMat() const;
50    /*virtual*/ ogl::Buffer getOGlBuffer() const;
51    /*virtual*/ ogl::Texture2D getOGlTexture2D() const;
52  
53    virtual int kind() const;
54    virtual Size size(int i=-1) const;
55    virtual size_t total(int i=-1) const;
56    virtual int type(int i=-1) const;
57    virtual int depth(int i=-1) const;
58    virtual int channels(int i=-1) const;
59    virtual bool empty() const;
60  
61 #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY
62    virtual ~_InputArray();
63 #endif
64  
65    int flags;
66    void* obj;
67    Size sz;
68 };

  可以看到,_InputArray類的裏面首先定義了一個枚舉,然後是各類的模板類型和一些方法。更復雜的我們暫且不挖深講了,很多時候,遇到函數原型中的InputArray類型,我們把它簡單地當做Mat類型就行了。

imshow 函數詳解:

imshow 函數用於在指定的窗口中顯示圖像。如果窗口是用CV_WINDOW_AUTOSIZE(默認值)標誌創建的,那麽顯示圖像原始大小。否則,將圖像進行縮放以適合窗口。而imshow 函數縮放圖像,取決於圖像的深度:

1     如果載入的圖像是8位無符號類型(8-bit unsigned),就顯示圖像本來的樣子。
2     如果圖像是16位無符號類型(16-bit unsigned)或32位整型(32-bit integer),便用像素值除以256。也就是說,值的範圍是[0,255 x 256]映射到[0,255]。
3     如果圖像是32位浮點型(32-bit floating-point),像素值便要乘以255。也就是說,該值的範圍是[0,1]映射到[0,255]。

  還有一點,若窗口創建(namedWindow函數)的時候,如果設定了支持OpenGL(WINDOW_OPENGL ),那麽imshow還支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作為輸入。

4、輸出圖像到文件——imwrite函數

在OpenCV中,輸出圖像到文件,我們一般都用imwrite函數,它的聲明如下:

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

■ 第一個參數,const string&類型的filename,填需要寫入的文件名就行了,帶上後綴,比如,“123.jpg”這樣。

■ 第二個參數,InputArray類型的img,一般填一個Mat類型的圖像數據就行了。

■ 第三個參數,const vector<int>&類型的params,表示為特定格式保存的參數編碼,它有默認值vector<int>(),所以一般情況下不需要填寫。而如果要填寫的話,有下面這些需要了解的地方:

1 對於JPEG格式的圖片,這個參數表示從0到100的圖片質量(CV_IMWRITE_JPEG_QUALITY),默認值是95.
2 對於PNG格式的圖片,這個參數表示壓縮級別(CV_IMWRITE_PNG_COMPRESSION)從0到9。較高的值意味著更小的尺寸和更長的壓縮時間,而默認值是3。
3 對於PPM,PGM,或PBM格式的圖片,這個參數表示一個二進制格式標誌(CV_IMWRITE_PXM_BINARY),取值為0或1,而默認值是1。

函數解析:

  imwrite函數用於將圖像保存到指定的文件。圖像格式是基於文件擴展名的,可保存的擴展名和imread中可以讀取的圖像擴展名一樣。

下面是一個圖片載入、顯示和輸出的示例:

//圖像載入、顯示和輸出
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;//OpenCV中的C++類和函數都是定義在命名空間cv之內的

int main()
{
    Mat srcImage = imread("poster_flower_2.jpg");
    namedWindow("風景");
    imshow("風景", srcImage);
   imwrite("hello.jpg", srcImage); waitKey(
0); //等待任何按鍵觸發 return 0; }

3、圖片的載入、顯示和輸出