轉自http://blog.csdn.net/poem_qianmo/article/details/20537737
菜鳥再次向淺墨大神學習!
本系列文章由@淺墨_毛星雲 出品,轉載請註明出處。
文章鏈接: http://blog.csdn.net/poem_qianmo/article/details/20537737
作者:毛星雲(淺墨) 郵箱: [email protected]
寫作當前博文時配套使用的OpenCV版本: 2.4.8
這篇文章中,我們將詳細而深入地弄懂入門OpenCV2最基本的問題,那就是圖像的載入,顯示和輸出。
PS:文章末尾提供了博文配套程序源代碼的下載。
依然是先看一張運行截圖:
瞭解過之前老版本OpenCV的童鞋們都應該清楚,對於OpenCV1.0時代的基於 C 語言接口而建的圖像存儲格式IplImage*,如果在退出前忘記release掉的話,就會照成內存泄露。而且用起來超級麻煩,我們往往在debug的時候,很大一部分時間在糾結手動釋放內存的問題。雖然對於小型的程序來說手動管理內存不是問題,但一旦我們寫的代碼變得越來越龐大,我們便會開始越來越多地糾纏於內存管理的問題,而不是着力解決你的開發目標。
這,就有些捨本逐末的感覺了。
而淺墨在這篇文章開頭想說,自從OpenCV踏入2.0時代,用Mat類數據結構作爲主打之後,OpenCV變得越發像需要很少編程涵養的Matlab那樣,上手超級快。甚至有些函數名稱都和matlab一樣,比如大家所熟知的imread,imwrite,imshow等函數。
這對於我們廣大圖像處理領域的孩子們來說,這的確是一個可喜可賀的事情。
這篇文章中,我們主要來詳細看一看入門OpenCV2最基本的問題,那就圖像的載入,顯示和輸出。
一、開胃菜之一 • 關於OpenCV的命名空間
OpenCV中的C++類和函數都是定義在命名空間cv之內的,有兩種方法可以訪問。第一種是,在代碼開頭的適當位置,加上usingnamespace cv;這句。
另外一種是在使用OpenCV類和函數時,都加入cv::命名空間。不過這種情況難免會不爽,每用一個OpenCV的類或者函數,都要多敲四下鍵盤寫出cv::,很麻煩。
所以,淺墨推崇大家在代碼開頭的適當位置,加上using namespace cv;這句。於是和opencv命名空間一了百了了。
比如淺墨,在寫簡單的OpenCV程序的時候,如下這三句是標配:
- #include <opencv2/core/core.hpp>
- #include<opencv2/highgui/highgui.hpp>
- using namespace cv;
二、開胃菜之二 • 關於Mat類型
cv::Mat類是用於保存圖像以及其他矩陣數據的數據結構。默認情況下,其尺寸爲0,我們也可以指定初始尺寸,比如,比如定義一個Mat類對象,就要寫cv::Mat pic(320,640,cv::Scalar(100));
Mat類型作爲OpenCV2新紀元的重要代表“人物”,淺墨準備在稍後的文章中,花長篇幅詳細講解它,現在我們只要理解,它是對應於OpenCV1.0時代的IplImage的主要用來存放圖像的數據結構就行了。對於這篇文章,我們需要用到關於Mat其實就簡單的這樣一句代碼:
- Mat myMat= imread("dota.jpg");
表示從工程目錄下把一幅名爲dota.jpg的jpg類型的圖像載入到Mat類型的myMat中。這裏的imread函數這篇文章的下文就會詳細剖析到。
好吧,開胃菜就是這麼多了,下面來看看今天的主要內容,圖像的載入和顯示,處理圖像混合,設置感興趣區域以及如何輸出圖像,一項一項來擊破吧。
三、圖像的載入和顯示
在新版本的OpenCV2中,最簡單的圖像載入和顯示只需要3句代碼,非常便捷。這三句代碼分別對應了三個函數,他們分別是:
imread( ), namedWindow( )以及imshow( )。我們依次來解析一下這三個函數。
1.imread函數
首先,我們看imread函數,可以在OpenCV官方文檔中查到其原型如下:
- Mat imread(const string& filename, intflags=1 );
■ 第一個參數,const string&類型的filename,填我們需要載入的圖片路徑名。
在Windows操作系統下,OpenCV的imread函數支持如下類型的圖像載入:
- Windows位圖 - *.bmp, *.dib
- JPEG文件 - *.jpeg, *.jpg, *.jpe
- JPEG 2000文件- *.jp2
- PNG圖片 - *.png
- 便攜文件格式- *.pbm, *.pgm, *.ppm
- Sun rasters光柵文件 - *.sr, *.ras
- TIFF 文件 - *.tiff, *.tif
■ 第二個參數,int類型的flags,爲載入標識,它指定一個加載圖像的顏色類型。可以看到它自帶缺省值1.所以有時候這個參數在調用時我們可以忽略,在看了下面的講解之後,我們就會發現,如果在調用時忽略這個參數,就表示載入三通道的彩色圖像。
可以在OpenCV中標識圖像格式的枚舉體中取值。通過轉到定義,我們可以在higui_c.h中發現這個枚舉的定義是這樣的:
- enum
- {
- /* 8bit, color or not */
- CV_LOAD_IMAGE_UNCHANGED =-1,
- /* 8bit, gray */
- CV_LOAD_IMAGE_GRAYSCALE =0,
- /* ?, color */
- CV_LOAD_IMAGE_COLOR =1,
- /* any depth, ? */
- CV_LOAD_IMAGE_ANYDEPTH =2,
- /* ?, any color */
- CV_LOAD_IMAGE_ANYCOLOR =4
- };
相應的解釋:
- CV_LOAD_IMAGE_UNCHANGED,這個標識在新版本中被廢置了,忽略。
- CV_LOAD_IMAGE_ANYDEPTH- 如果取這個標識的話,若載入的圖像的深度爲16位或者32位,就返回對應深度的圖像,否則,就轉換爲8位圖像再返回。
- CV_LOAD_IMAGE_COLOR- 如果取這個標識的話,總是轉換圖像到彩色一體
- 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通道的話呢,這裏就需要取負值。
如果你搞怪,flags取1999,也是可以的,這時就表示返回一個3通道的彩色圖像。
好了,講了這麼多,來幾個載入示例,一看就懂:
- Mat image0=imread("dota.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);//載入最真實的圖像
- ge1=imread("dota.jpg",0);//載入灰度圖
- Mat image2=imread("dota.jpg",199);//載入3通道的彩色圖像
- Mat logo=imread("dota_logo.jpg");//載入3通道的彩色圖像
2.namedWindow函數
顧名思義,namedWindow函數,用於創建一個窗口。
函數原型是這樣的:
- void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE );
■ 第一個參數,const string&型的name,即填被用作窗口的標識符的窗口名稱。
■ 第二個參數,int 類型的flags ,窗口的標識,可以填如下的值:
- WINDOW_NORMAL設置了這個值,用戶便可以改變窗口的大小(沒有限制)
- WINDOW_AUTOSIZE如果設置了這個值,窗口大小會自動調整以適應所顯示的圖像,並且不能手動改變窗口大小。
- 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的原型:
- CV_EXPORTS_W void imshow(const string&winname, InputArray mat);
進一步對InputArray轉到定義,在core.hpp中查到一個typedef聲明:
- typedef const _InputArray& InputArray;
這其實一個類型聲明引用,就是說_InputArray和InputArray是一個意思,既然他們是一個意思,我們就來做最後一步,對_InputArray進行轉到定義,終於,我們在core.hpp發現了InputArray的真身:
- class CV_EXPORTS _InputArray
- {
- public:
- enum {
- KIND_SHIFT = 16,
- FIXED_TYPE = 0x8000 << KIND_SHIFT,
- FIXED_SIZE = 0x4000 << KIND_SHIFT,
- KIND_MASK = ~(FIXED_TYPE|FIXED_SIZE) - (1 << KIND_SHIFT) + 1,
- NONE = 0 <<KIND_SHIFT,
- MAT = 1 <<KIND_SHIFT,
- MATX = 2 <<KIND_SHIFT,
- STD_VECTOR = 3 <<KIND_SHIFT,
- STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
- STD_VECTOR_MAT = 5 <<KIND_SHIFT,
- EXPR = 6 <<KIND_SHIFT,
- OPENGL_BUFFER = 7 <<KIND_SHIFT,
- OPENGL_TEXTURE = 8 <<KIND_SHIFT,
- GPU_MAT = 9 <<KIND_SHIFT,
- OCL_MAT =10 <<KIND_SHIFT
- };
- _InputArray();
- _InputArray(const Mat& m);
- _InputArray(const MatExpr& expr);
- template<typename _Tp> _InputArray(const _Tp* vec, int n);
- template<typename _Tp> _InputArray(const vector<_Tp>&vec);
- template<typename _Tp> _InputArray(constvector<vector<_Tp> >& vec);
- _InputArray(const vector<Mat>& vec);
- template<typename _Tp> _InputArray(const vector<Mat_<_Tp>>& vec);
- template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
- template<typename _Tp, int m, int n> _InputArray(constMatx<_Tp, m, n>& matx);
- _InputArray(const Scalar& s);
- _InputArray(const double& val);
- // < Deprecated
- _InputArray(const GlBuffer& buf);
- _InputArray(const GlTexture& tex);
- // >
- _InputArray(const gpu::GpuMat& d_mat);
- _InputArray(const ogl::Buffer& buf);
- _InputArray(const ogl::Texture2D& tex);
- virtual Mat getMat(int i=-1) const;
- virtual void getMatVector(vector<Mat>& mv) const;
- // < Deprecated
- virtual GlBuffer getGlBuffer() const;
- virtual GlTexture getGlTexture() const;
- // >
- virtual gpu::GpuMat getGpuMat() const;
- /*virtual*/ ogl::Buffer getOGlBuffer() const;
- /*virtual*/ ogl::Texture2D getOGlTexture2D() const;
- virtual int kind() const;
- virtual Size size(int i=-1) const;
- virtual size_t total(int i=-1) const;
- virtual int type(int i=-1) const;
- virtual int depth(int i=-1) const;
- virtual int channels(int i=-1) const;
- virtual bool empty() const;
- #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY
- virtual ~_InputArray();
- #endif
- int flags;
- void* obj;
- Size sz;
- };
可以看到,_InputArray類的裏面首先定義了一個枚舉,然後是各類的模板類型和一些方法。更復雜的我們暫且不挖深講了,很多時候,遇到函數原型中的InputArray類型,我們把它簡單地當做Mat類型就行了。
imshow 函數詳解:
imshow 函數用於在指定的窗口中顯示圖像。如果窗口是用CV_WINDOW_AUTOSIZE(默認值)標誌創建的,那麼顯示圖像原始大小。否則,將圖像進行縮放以適合窗口。而imshow 函數縮放圖像,取決於圖像的深度:
- 如果載入的圖像是8位無符號類型(8-bit unsigned),就顯示圖像本來的樣子。
- 如果圖像是16位無符號類型(16-bit unsigned)或32位整型(32-bit integer),便用像素值除以256。也就是說,值的範圍是[0,255 x 256]映射到[0,255]。
- 如果圖像是32位浮點型(32-bit floating-point),像素值便要乘以255。也就是說,該值的範圍是[0,1]映射到[0,255]。
還有一點,若窗口創建(namedWindow函數)的時候,如果設定了支持OpenGL(WINDOW_OPENGL ),那麼imshow還支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作爲輸入。
四、輸出圖像到文件——imwrite函數
在OpenCV中,輸出圖像到文件,我們一般都用imwrite函數,它的聲明如下:
- 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>(),所以一般情況下不需要填寫。而如果要填寫的話,有下面這些需要了解的地方:
- 對於JPEG格式的圖片,這個參數表示從0到100的圖片質量(CV_IMWRITE_JPEG_QUALITY),默認值是95.
- 對於PNG格式的圖片,這個參數表示壓縮級別(CV_IMWRITE_PNG_COMPRESSION)從0到9。較高的值意味着更小的尺寸和更長的壓縮時間,而默認值是3。
- 對於PPM,PGM,或PBM格式的圖片,這個參數表示一個二進制格式標誌(CV_IMWRITE_PXM_BINARY),取值爲0或1,而默認值是1。
函數解析:
imwrite函數用於將圖像保存到指定的文件。圖像格式是基於文件擴展名的,可保存的擴展名和imread中可以讀取的圖像擴展名一樣,爲了方便查看,我們在這裏再列一遍:
- Windows位圖 - *.bmp, *.dib
- JPEG文件 - *.jpeg, *.jpg, *.jpe
- JPEG 2000文件- *.jp2
- PNG圖片 - *.png
- 便攜文件格式- *.pbm, *.pgm, *.ppm
- Sun rasters光柵格式 - *.sr, *.ras
- TIFF 文件 - *.tiff, *.tif
- #include <vector>
- #include <stdio.h>
- #include<opencv2/opencv.hpp>
- using namespace cv;
- using namespace std;
- 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( )
- {
- //創建帶alpha通道的Mat
- 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);
- try{
- imwrite("透明Alpha值圖.png", mat, compression_params);
- }
- catch(runtime_error& ex) {
- fprintf(stderr,"圖像轉換成PNG格式發生錯誤:%s\n", ex.what());
- return1;
- }
- fprintf(stdout,"PNG圖片文件的alpha數據保存完畢~\n");
- return 0;
- }
五、一個綜合示例
最後是一個綜合示例,載入圖像,進行簡單圖像混合,顯示圖像,並且輸出混合後的圖像到jpg。
由於篇幅原因,這裏的圖像混合具體細節我們放到稍後的文章中再講,現在先給大家看看混合的效果和源碼。囧,因爲opencv圖像處理真的很少涉及到設計模式的問題,所以很多時候往往就是main函數中塞滿一串串代碼打天下,即便是OpenCV官方的示例都是如此。
好了,如下就是這篇文章配套綜合示例的配套源碼,非常的簡單明瞭:
- //-----------------------------------【程序說明】----------------------------------------------
- // 程序名稱::【OpenCV入門教程之三】圖像的載入,顯示與輸出 一站式完全解析 博文配套源碼
- // VS2010版 OpenCV版本:2.4.8
- // 2014年3月5日 Create by 淺墨
- // 描述: 圖像的載入,顯示與輸出 一站式剖析 配套源碼
- // 圖片素材出處:dota2原畫聖堂刺客 dota2 logo 動漫人物
- //------------------------------------------------------------------------------------------------
- #include<opencv2/core/core.hpp>
- #include<opencv2/highgui/highgui.hpp>
- using namespace cv;
- int main( )
- {
- //-----------------------------------【一、圖像的載入和顯示】--------------------------------------
- // 描述:以下三行代碼用於完成圖像的載入和顯示
- //--------------------------------------------------------------------------------------------------
- Mat girl=imread("girl.jpg"); //載入圖像到Mat
- namedWindow("【1】動漫圖"); //創建一個名爲 "【1】動漫圖"的窗口
- imshow("【1】動漫圖",girl);//顯示名爲 "【1】動漫圖"的窗口
- //-----------------------------------【二、初級圖像混合】--------------------------------------
- // 描述:二、初級圖像混合
- //-----------------------------------------------------------------------------------------------
- //載入圖片
- Mat image= imread("dota.jpg",199);
- Mat logo= imread("dota_logo.jpg");
- //載入後先顯示
- namedWindow("【2】原畫圖");
- imshow("【2】原畫圖",image);
- namedWindow("【3】logo圖");
- imshow("【3】logo圖",logo);
- //定義一個Mat類型,用於存放,圖像的ROI
- Mat imageROI;
- //方法一
- imageROI=image(Rect(800,350,logo.cols,logo.rows));
- //方法二
- //imageROI=image(Range(350,350+logo.rows),Range(800,800+logo.cols));
- //將logo加到原圖上
- addWeighted(imageROI,0.5,logo,0.3,0.,imageROI);
- //顯示結果
- namedWindow("【4】原畫+logo圖");
- imshow("【4】原畫+logo圖",image);
- //-----------------------------------【三、圖像的輸出】--------------------------------------
- // 描述:將一個Mat圖像輸出到圖像文件
- //-----------------------------------------------------------------------------------------------
- //輸出一張jpg圖片到工程目錄下
- imwrite("我喜歡打dota2 by淺墨.jpg",image);
- waitKey();
- return 0;
- }
運行這個程序,會彈出四個我們在OpenCV中創建的窗口。
下面是運行截圖。首先是圖像載入和顯示的演示,我們載入了一張動漫人物圖:
接着是載入一張dota2原畫和dota2logo圖,爲圖像融合做準備:
logo圖:
最終,經過處理,得到dota2原畫+logo的融合,並輸出一張名爲我喜歡打dota2 by淺墨.jpg的圖片到工程目錄下。
嗯,本篇文章到這裏就基本結束了,最後放出本篇文章配套示例程序的下載地址。
本篇文章的配套源代碼請點擊這裏下載:
【淺墨OpenCV入門教程之三】圖像的載入,顯示和輸出配套源代碼下載
OK,本節的內容大概就是這些,我們下篇文章見:)
本系列文章由@淺墨_毛星雲 出品,轉載請註明出處。
文章鏈接: http://blog.csdn.net/poem_qianmo/article/details/20537737
作者:毛星雲(淺墨) 郵箱: [email protected]
寫作當前博文時配套使用的OpenCV版本: 2.4.8
這篇文章中,我們將詳細而深入地弄懂入門OpenCV2最基本的問題,那就是圖像的載入,顯示和輸出。
PS:文章末尾提供了博文配套程序源代碼的下載。
依然是先看一張運行截圖:
瞭解過之前老版本OpenCV的童鞋們都應該清楚,對於OpenCV1.0時代的基於 C 語言接口而建的圖像存儲格式IplImage*,如果在退出前忘記release掉的話,就會照成內存泄露。而且用起來超級麻煩,我們往往在debug的時候,很大一部分時間在糾結手動釋放內存的問題。雖然對於小型的程序來說手動管理內存不是問題,但一旦我們寫的代碼變得越來越龐大,我們便會開始越來越多地糾纏於內存管理的問題,而不是着力解決你的開發目標。
這,就有些捨本逐末的感覺了。
而淺墨在這篇文章開頭想說,自從OpenCV踏入2.0時代,用Mat類數據結構作爲主打之後,OpenCV變得越發像需要很少編程涵養的Matlab那樣,上手超級快。甚至有些函數名稱都和matlab一樣,比如大家所熟知的imread,imwrite,imshow等函數。
這對於我們廣大圖像處理領域的孩子們來說,這的確是一個可喜可賀的事情。
這篇文章中,我們主要來詳細看一看入門OpenCV2最基本的問題,那就圖像的載入,顯示和輸出。
一、開胃菜之一 • 關於OpenCV的命名空間
OpenCV中的C++類和函數都是定義在命名空間cv之內的,有兩種方法可以訪問。第一種是,在代碼開頭的適當位置,加上usingnamespace cv;這句。
另外一種是在使用OpenCV類和函數時,都加入cv::命名空間。不過這種情況難免會不爽,每用一個OpenCV的類或者函數,都要多敲四下鍵盤寫出cv::,很麻煩。
所以,淺墨推崇大家在代碼開頭的適當位置,加上using namespace cv;這句。於是和opencv命名空間一了百了了。
比如淺墨,在寫簡單的OpenCV程序的時候,如下這三句是標配:
- #include <opencv2/core/core.hpp>
- #include<opencv2/highgui/highgui.hpp>
- using namespace cv;
二、開胃菜之二 • 關於Mat類型
cv::Mat類是用於保存圖像以及其他矩陣數據的數據結構。默認情況下,其尺寸爲0,我們也可以指定初始尺寸,比如,比如定義一個Mat類對象,就要寫cv::Mat pic(320,640,cv::Scalar(100));
Mat類型作爲OpenCV2新紀元的重要代表“人物”,淺墨準備在稍後的文章中,花長篇幅詳細講解它,現在我們只要理解,它是對應於OpenCV1.0時代的IplImage的主要用來存放圖像的數據結構就行了。對於這篇文章,我們需要用到關於Mat其實就簡單的這樣一句代碼:
- Mat myMat= imread("dota.jpg");
表示從工程目錄下把一幅名爲dota.jpg的jpg類型的圖像載入到Mat類型的myMat中。這裏的imread函數這篇文章的下文就會詳細剖析到。
好吧,開胃菜就是這麼多了,下面來看看今天的主要內容,圖像的載入和顯示,處理圖像混合,設置感興趣區域以及如何輸出圖像,一項一項來擊破吧。
三、圖像的載入和顯示
在新版本的OpenCV2中,最簡單的圖像載入和顯示只需要3句代碼,非常便捷。這三句代碼分別對應了三個函數,他們分別是:
imread( ), namedWindow( )以及imshow( )。我們依次來解析一下這三個函數。
1.imread函數
首先,我們看imread函數,可以在OpenCV官方文檔中查到其原型如下:
- Mat imread(const string& filename, intflags=1 );
■ 第一個參數,const string&類型的filename,填我們需要載入的圖片路徑名。
在Windows操作系統下,OpenCV的imread函數支持如下類型的圖像載入:
- Windows位圖 - *.bmp, *.dib
- JPEG文件 - *.jpeg, *.jpg, *.jpe
- JPEG 2000文件- *.jp2
- PNG圖片 - *.png
- 便攜文件格式- *.pbm, *.pgm, *.ppm
- Sun rasters光柵文件 - *.sr, *.ras
- TIFF 文件 - *.tiff, *.tif
■ 第二個參數,int類型的flags,爲載入標識,它指定一個加載圖像的顏色類型。可以看到它自帶缺省值1.所以有時候這個參數在調用時我們可以忽略,在看了下面的講解之後,我們就會發現,如果在調用時忽略這個參數,就表示載入三通道的彩色圖像。
可以在OpenCV中標識圖像格式的枚舉體中取值。通過轉到定義,我們可以在higui_c.h中發現這個枚舉的定義是這樣的:
- enum
- {
- /* 8bit, color or not */
- CV_LOAD_IMAGE_UNCHANGED =-1,
- /* 8bit, gray */
- CV_LOAD_IMAGE_GRAYSCALE =0,
- /* ?, color */
- CV_LOAD_IMAGE_COLOR =1,
- /* any depth, ? */
- CV_LOAD_IMAGE_ANYDEPTH =2,
- /* ?, any color */
- CV_LOAD_IMAGE_ANYCOLOR =4
- };
相應的解釋:
- CV_LOAD_IMAGE_UNCHANGED,這個標識在新版本中被廢置了,忽略。
- CV_LOAD_IMAGE_ANYDEPTH- 如果取這個標識的話,若載入的圖像的深度爲16位或者32位,就返回對應深度的圖像,否則,就轉換爲8位圖像再返回。
- CV_LOAD_IMAGE_COLOR- 如果取這個標識的話,總是轉換圖像到彩色一體
- 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通道的話呢,這裏就需要取負值。
如果你搞怪,flags取1999,也是可以的,這時就表示返回一個3通道的彩色圖像。
好了,講了這麼多,來幾個載入示例,一看就懂:
- Mat image0=imread("dota.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);//載入最真實的圖像
- ge1=imread("dota.jpg",0);//載入灰度圖
- Mat image2=imread("dota.jpg",199);//載入3通道的彩色圖像
- Mat logo=imread("dota_logo.jpg");//載入3通道的彩色圖像
2.namedWindow函數
顧名思義,namedWindow函數,用於創建一個窗口。
函數原型是這樣的:
- void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE );
■ 第一個參數,const string&型的name,即填被用作窗口的標識符的窗口名稱。
■ 第二個參數,int 類型的flags ,窗口的標識,可以填如下的值:
- WINDOW_NORMAL設置了這個值,用戶便可以改變窗口的大小(沒有限制)
- WINDOW_AUTOSIZE如果設置了這個值,窗口大小會自動調整以適應所顯示的圖像,並且不能手動改變窗口大小。
- 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的原型:
- CV_EXPORTS_W void imshow(const string&winname, InputArray mat);
進一步對InputArray轉到定義,在core.hpp中查到一個typedef聲明:
- typedef const _InputArray& InputArray;
這其實一個類型聲明引用,就是說_InputArray和InputArray是一個意思,既然他們是一個意思,我們就來做最後一步,對_InputArray進行轉到定義,終於,我們在core.hpp發現了InputArray的真身:
- class CV_EXPORTS _InputArray
- {
- public:
- enum {
- KIND_SHIFT = 16,
- FIXED_TYPE = 0x8000 << KIND_SHIFT,
- FIXED_SIZE = 0x4000 << KIND_SHIFT,
- KIND_MASK = ~(FIXED_TYPE|FIXED_SIZE) - (1 << KIND_SHIFT) + 1,
- NONE = 0 <<KIND_SHIFT,
- MAT = 1 <<KIND_SHIFT,
- MATX = 2 <<KIND_SHIFT,
- STD_VECTOR = 3 <<KIND_SHIFT,
- STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
- STD_VECTOR_MAT = 5 <<KIND_SHIFT,
- EXPR = 6 <<KIND_SHIFT,
- OPENGL_BUFFER = 7 <<KIND_SHIFT,
- OPENGL_TEXTURE = 8 <<KIND_SHIFT,
- GPU_MAT = 9 <<KIND_SHIFT,
- OCL_MAT =10 <<KIND_SHIFT
- };
- _InputArray();
- _InputArray(const Mat& m);
- _InputArray(const MatExpr& expr);
- template<typename _Tp> _InputArray(const _Tp* vec, int n);
- template<typename _Tp> _InputArray(const vector<_Tp>&vec);
- template<typename _Tp> _InputArray(constvector<vector<_Tp> >& vec);
- _InputArray(const vector<Mat>& vec);
- template<typename _Tp> _InputArray(const vector<Mat_<_Tp>>& vec);
- template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
- template<typename _Tp, int m, int n> _InputArray(constMatx<_Tp, m, n>& matx);
- _InputArray(const Scalar& s);
- _InputArray(const double& val);
- // < Deprecated
- _InputArray(const GlBuffer& buf);
- _InputArray(const GlTexture& tex);
- // >
- _InputArray(const gpu::GpuMat& d_mat);
- _InputArray(const ogl::Buffer& buf);
- _InputArray(const ogl::Texture2D& tex);
- virtual Mat getMat(int i=-1) const;
- virtual void getMatVector(vector<Mat>& mv) const;
- // < Deprecated
- virtual GlBuffer getGlBuffer() const;
- virtual GlTexture getGlTexture() const;
- // >
- virtual gpu::GpuMat getGpuMat() const;
- /*virtual*/ ogl::Buffer getOGlBuffer() const;
- /*virtual*/ ogl::Texture2D getOGlTexture2D() const;
- virtual int kind() const;
- virtual Size size(int i=-1) const;
- virtual size_t total(int i=-1) const;
- virtual int type(int i=-1) const;
- virtual int depth(int i=-1) const;
- virtual int channels(int i=-1) const;
- virtual bool empty() const;
- #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY
- virtual ~_InputArray();
- #endif
- int flags;
- void* obj;
- Size sz;
- };
可以看到,_InputArray類的裏面首先定義了一個枚舉,然後是各類的模板類型和一些方法。更復雜的我們暫且不挖深講了,很多時候,遇到函數原型中的InputArray類型,我們把它簡單地當做Mat類型就行了。
imshow 函數詳解:
imshow 函數用於在指定的窗口中顯示圖像。如果窗口是用CV_WINDOW_AUTOSIZE(默認值)標誌創建的,那麼顯示圖像原始大小。否則,將圖像進行縮放以適合窗口。而imshow 函數縮放圖像,取決於圖像的深度:
- 如果載入的圖像是8位無符號類型(8-bit unsigned),就顯示圖像本來的樣子。
- 如果圖像是16位無符號類型(16-bit unsigned)或32位整型(32-bit integer),便用像素值除以256。也就是說,值的範圍是[0,255 x 256]映射到[0,255]。
- 如果圖像是32位浮點型(32-bit floating-point),像素值便要乘以255。也就是說,該值的範圍是[0,1]映射到[0,255]。
還有一點,若窗口創建(namedWindow函數)的時候,如果設定了支持OpenGL(WINDOW_OPENGL ),那麼imshow還支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作爲輸入。
四、輸出圖像到文件——imwrite函數
在OpenCV中,輸出圖像到文件,我們一般都用imwrite函數,它的聲明如下:
- 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>(),所以一般情況下不需要填寫。而如果要填寫的話,有下面這些需要了解的地方:
- 對於JPEG格式的圖片,這個參數表示從0到100的圖片質量(CV_IMWRITE_JPEG_QUALITY),默認值是95.
- 對於PNG格式的圖片,這個參數表示壓縮級別(CV_IMWRITE_PNG_COMPRESSION)從0到9。較高的值意味着更小的尺寸和更長的壓縮時間,而默認值是3。
- 對於PPM,PGM,或PBM格式的圖片,這個參數表示一個二進制格式標誌(CV_IMWRITE_PXM_BINARY),取值爲0或1,而默認值是1。
函數解析:
imwrite函數用於將圖像保存到指定的文件。圖像格式是基於文件擴展名的,可保存的擴展名和imread中可以讀取的圖像擴展名一樣,爲了方便查看,我們在這裏再列一遍:
- Windows位圖 - *.bmp, *.dib
- JPEG文件 - *.jpeg, *.jpg, *.jpe
- JPEG 2000文件- *.jp2
- PNG圖片 - *.png
- 便攜文件格式- *.pbm, *.pgm, *.ppm
- Sun rasters光柵格式 - *.sr, *.ras
- TIFF 文件 - *.tiff, *.tif
- #include <vector>
- #include <stdio.h>
- #include<opencv2/opencv.hpp>
- using namespace cv;
- using namespace std;
- 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( )
- {
- //創建帶alpha通道的Mat
- 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);
- try{
- imwrite("透明Alpha值圖.png", mat, compression_params);
- }
- catch(runtime_error& ex) {
- fprintf(stderr,"圖像轉換成PNG格式發生錯誤:%s\n", ex.what());
- return1;
- }
- fprintf(stdout,"PNG圖片文件的alpha數據保存完畢~\n");
- return 0;
- }
五、一個綜合示例
最後是一個綜合示例,載入圖像,進行簡單圖像混合,顯示圖像,並且輸出混合後的圖像到jpg。
由於篇幅原因,這裏的圖像混合具體細節我們放到稍後的文章中再講,現在先給大家看看混合的效果和源碼。囧,因爲opencv圖像處理真的很少涉及到設計模式的問題,所以很多時候往往就是main函數中塞滿一串串代碼打天下,即便是OpenCV官方的示例都是如此。
好了,如下就是這篇文章配套綜合示例的配套源碼,非常的簡單明瞭:
- //-----------------------------------【程序說明】----------------------------------------------
- // 程序名稱::【OpenCV入門教程之三】圖像的載入,顯示與輸出 一站式完全解析 博文配套源碼
- // VS2010版 OpenCV版本:2.4.8
- // 2014年3月5日 Create by 淺墨
- // 描述: 圖像的載入,顯示與輸出 一站式剖析 配套源碼
- // 圖片素材出處:dota2原畫聖堂刺客 dota2 logo 動漫人物
- //------------------------------------------------------------------------------------------------
- #include<opencv2/core/core.hpp>
- #include<opencv2/highgui/highgui.hpp>
- using namespace cv;
- int main( )
- {
- //-----------------------------------【一、圖像的載入和顯示】--------------------------------------
- // 描述:以下三行代碼用於完成圖像的載入和顯示
- //--------------------------------------------------------------------------------------------------
- Mat girl=imread("girl.jpg"); //載入圖像到Mat
- namedWindow("【1】動漫圖"); //創建一個名爲 "【1】動漫圖"的窗口
- imshow("【1】動漫圖",girl);//顯示名爲 "【1】動漫圖"的窗口
- //-----------------------------------【二、初級圖像混合】--------------------------------------
- // 描述:二、初級圖像混合
- //-----------------------------------------------------------------------------------------------
- //載入圖片
- Mat image= imread("dota.jpg",199);
- Mat logo= imread("dota_logo.jpg");
- //載入後先顯示
- namedWindow("【2】原畫圖");
- imshow("【2】原畫圖",image);
- namedWindow("【3】logo圖");
- imshow("【3】logo圖",logo);
- //定義一個Mat類型,用於存放,圖像的ROI
- Mat imageROI;
- //方法一
- imageROI=image(Rect(800,350,logo.cols,logo.rows));
- //方法二
- //imageROI=image(Range(350,350+logo.rows),Range(800,800+logo.cols));
- //將logo加到原圖上
- addWeighted(imageROI,0.5,logo,0.3,0.,imageROI);
- //顯示結果
- namedWindow("【4】原畫+logo圖");
- imshow("【4】原畫+logo圖",image);
- //-----------------------------------【三、圖像的輸出】--------------------------------------
- // 描述:將一個Mat圖像輸出到圖像文件
- //-----------------------------------------------------------------------------------------------
- //輸出一張jpg圖片到工程目錄下
- imwrite("我喜歡打dota2 by淺墨.jpg",image);
- waitKey();
- return 0;
- }
運行這個程序,會彈出四個我們在OpenCV中創建的窗口。
下面是運行截圖。首先是圖像載入和顯示的演示,我們載入了一張動漫人物圖:
接着是載入一張dota2原畫和dota2logo圖,爲圖像融合做準備:
logo圖:
最終,經過處理,得到dota2原畫+logo的融合,並輸出一張名爲我喜歡打dota2 by淺墨.jpg的圖片到工程目錄下。
嗯,本篇文章到這裏就基本結束了,最後放出本篇文章配套示例程序的下載地址。
本篇文章的配套源代碼請點擊這裏下載:
【淺墨OpenCV入門教程之三】圖像的載入,顯示和輸出配套源代碼下載
OK,本節的內容大概就是這些,我們下篇文章見:)