3、圖片的載入、顯示和輸出
一、關於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
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、圖片的載入、顯示和輸出