转载:【opencv入门教程之三】:图片的载入|显示|输出
本系列文章由@淺墨_毛星云 出品,轉(zhuǎn)載請注明出處。??
文章鏈接:?http://blog.csdn.net/poem_qianmo/article/details/20537737
作者:毛星云(淺墨)????郵箱:?happylifemxy@163.com?
寫作當前博文時配套使用的OpenCV版本: 2.4.8
這篇文章中,我們將詳細而深入地弄懂入門OpenCV2最基本的問題,那就是圖像的載入,顯示和輸出。
PS:文章末尾提供了博文配套程序源代碼的下載。
依然是先看一張運行截圖:
了解過之前老版本OpenCV的童鞋們都應(yīng)該清楚,對于OpenCV1.0時代的基于 C 語言接口而建的圖像存儲格式IplImage*,如果在退出前忘記release掉的話,就會照成內(nèi)存泄露。而且用起來超級麻煩,我們往往在debug的時候,很大一部分時間在糾結(jié)手動釋放內(nèi)存的問題。雖然對于小型的程序來說手動管理內(nèi)存不是問題,但一旦我們寫的代碼變得越來越龐大,我們便會開始越來越多地糾纏于內(nèi)存管理的問題,而不是著力解決你的開發(fā)目標。
這,就有些舍本逐末的感覺了。
而淺墨在這篇文章開頭想說,自從OpenCV踏入2.0時代,用Mat類數(shù)據(jù)結(jié)構(gòu)作為主打之后,OpenCV變得越發(fā)像需要很少編程涵養(yǎng)的Matlab那樣,上手超級快。甚至有些函數(shù)名稱都和matlab一樣,比如大家所熟知的imread,imwrite,imshow等函數(shù)。
這對于我們廣大圖像處理領(lǐng)域的孩子們來說,這的確是一個可喜可賀的事情。
?
這篇文章中,我們主要來詳細看一看入門OpenCV2最基本的問題,那就圖像的載入,顯示和輸出。
?
?
一、開胃菜之一???關(guān)于OpenCV的命名空間
?
OpenCV中的C++類和函數(shù)都是定義在命名空間cv之內(nèi)的,有兩種方法可以訪問。第一種是,在代碼開頭的適當位置,加上usingnamespace cv;這句。
另外一種是在使用OpenCV類和函數(shù)時,都加入cv::命名空間。不過這種情況難免會不爽,每用一個OpenCV的類或者函數(shù),都要多敲四下鍵盤寫出cv::,很麻煩。
所以,淺墨推崇大家在代碼開頭的適當位置,加上using namespace cv;這句。于是和opencv命名空間一了百了了。
?
?
比如淺墨,在寫簡單的OpenCV程序的時候,如下這三句是標配:
?
二、開胃菜之二???關(guān)于Mat類型
cv::Mat類是用于保存圖像以及其他矩陣數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。默認情況下,其尺寸為0,我們也可以指定初始尺寸,比如,比如定義一個Mat類對象,就要寫cv::Mat pic(320,640,cv::Scalar(100));
?
Mat類型作為OpenCV2新紀元的重要代表“人物”,淺墨準備在稍后的文章中,花長篇幅詳細講解它,現(xiàn)在我們只要理解,它是對應(yīng)于OpenCV1.0時代的IplImage的主要用來存放圖像的數(shù)據(jù)結(jié)構(gòu)就行了。對于這篇文章,我們需要用到關(guān)于Mat其實就簡單的這樣一句代碼:
Mat myMat= imread("dota.jpg");?
表示從工程目錄下把一幅名為dota.jpg的jpg類型的圖像載入到Mat類型的myMat中。這里的imread函數(shù)這篇文章的下文就會詳細剖析到。
?
好吧,開胃菜就是這么多了,下面來看看今天的主要內(nèi)容,圖像的載入和顯示,處理圖像混合,設(shè)置感興趣區(qū)域以及如何輸出圖像,一項一項來擊破吧。
?
三、圖像的載入和顯示
在新版本的OpenCV2中,最簡單的圖像載入和顯示只需要3句代碼,非常便捷。這三句代碼分別對應(yīng)了三個函數(shù),他們分別是:
imread( ), namedWindow( )以及imshow( )。我們依次來解析一下這三個函數(shù)。
?
?
1.imread函數(shù)
首先,我們看imread函數(shù),可以在OpenCV官方文檔中查到其原型如下:
?
Mat imread(const string& filename, intflags=1 );?
■?第一個參數(shù),const string&類型的filename,填我們需要載入的圖片路徑名。
在Windows操作系統(tǒng)下,OpenCV的imread函數(shù)支持如下類型的圖像載入:
?
- Windows位圖 - *.bmp, *.dib
- JPEG文件 - *.jpeg, *.jpg, *.jpe
- JPEG 2000文件- *.jp2
- PNG圖片 - *.png
- 便攜文件格式- *.pbm, *.pgm, *.ppm
- Sun rasters光柵文件 - *.sr, *.ras
- TIFF 文件 - *.tiff, *.tif
■?第二個參數(shù),int類型的flags,為載入標識,它指定一個加載圖像的顏色類型。可以看到它自帶缺省值1.所以有時候這個參數(shù)在調(diào)用時我們可以忽略,在看了下面的講解之后,我們就會發(fā)現(xiàn),如果在調(diào)用時忽略這個參數(shù),就表示載入三通道的彩色圖像。
可以在OpenCV中標識圖像格式的枚舉體中取值。通過轉(zhuǎn)到定義,我們可以在higui_c.h中發(fā)現(xiàn)這個枚舉的定義是這樣的:
相應(yīng)的解釋:
- CV_LOAD_IMAGE_UNCHANGED,這個標識在新版本中被廢置了,忽略。
- CV_LOAD_IMAGE_ANYDEPTH- 如果取這個標識的話,若載入的圖像的深度為16位或者32位,就返回對應(yīng)深度的圖像,否則,就轉(zhuǎn)換為8位圖像再返回。
- CV_LOAD_IMAGE_COLOR- 如果取這個標識的話,總是轉(zhuǎn)換圖像到彩色一體
- CV_LOAD_IMAGE_GRAYSCALE- 如果取這個標識的話,始終將圖像轉(zhuǎn)換成灰度1
?
如果輸入有沖突的標志,將采用較小的數(shù)字值。比如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通道的彩色圖像。
?
?
好了,講了這么多,來幾個載入示例,一看就懂:
?
2.namedWindow函數(shù)
顧名思義,namedWindow函數(shù),用于創(chuàng)建一個窗口。
函數(shù)原型是這樣的:
void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE );? ? ??■?第一個參數(shù),const string&型的name,即填被用作窗口的標識符的窗口名稱。
? ? ??■?第二個參數(shù),int 類型的flags?,窗口的標識,可以填如下的值:
- WINDOW_NORMAL設(shè)置了這個值,用戶便可以改變窗口的大小(沒有限制)
- WINDOW_AUTOSIZE如果設(shè)置了這個值,窗口大小會自動調(diào)整以適應(yīng)所顯示的圖像,并且不能手動改變窗口大小。
- WINDOW_OPENGL?如果設(shè)置了這個值的話,窗口創(chuàng)建的時候便會支持OpenGL。
函數(shù)剖析:
首先需要注意的是,它有默認值WINDOW_AUTOSIZE,所以,一般情況下,這個函數(shù)我們填一個變量就行了。
namedWindow函數(shù)的作用是,通過指定的名字,創(chuàng)建一個可以作為圖像和進度條的容器窗口。如果具有相同名稱的窗口已經(jīng)存在,則函數(shù)不做任何事情。
我們可以調(diào)用destroyWindow()或者destroyAllWindows()函數(shù)來關(guān)閉窗口,并取消之前分配的與窗口相關(guān)的所有內(nèi)存空間。
但話是這樣說,其實對于代碼量不大的簡單小程序來說,我們完全沒有必要手動調(diào)用上述的destroyWindow()或者destroyAllWindows()函數(shù),因為在退出時,所有的資源和應(yīng)用程序的窗口會被操作系統(tǒng)會自動關(guān)閉。
?
3.imshow函數(shù)
在指定的窗口中顯示一幅圖像。
void imshow(const string& winname, InputArray mat);?■?第一個參數(shù),const string&類型的winname,填需要顯示的窗口標識名稱。
?■?第二個參數(shù),InputArray?類型的mat,填需要顯示的圖像。
?
這里的InputArray?我們講一下吧,不然一直是個梗在這邊。通過轉(zhuǎn)到定義大法,我們可以在
Highgui.hpp中查到imshow的原型:
?
CV_EXPORTS_W void imshow(const string&winname, InputArray mat);?
進一步對InputArray轉(zhuǎn)到定義,在core.hpp中查到一個typedef聲明:
typedef const _InputArray& InputArray;這其實一個類型聲明引用,就是說_InputArray和InputArray是一個意思,既然他們是一個意思,我們就來做最后一步,對_InputArray進行轉(zhuǎn)到定義,終于,我們在core.hpp發(fā)現(xiàn)了InputArray的真身:
可以看到,_InputArray類的里面首先定義了一個枚舉,然后是各類的模板類型和一些方法。更復(fù)雜的我們暫且不挖深講了,很多時候,遇到函數(shù)原型中的InputArray類型,我們把它簡單地當做Mat類型就行了。
?
imshow?函數(shù)詳解:
imshow?函數(shù)用于在指定的窗口中顯示圖像。如果窗口是用CV_WINDOW_AUTOSIZE(默認值)標志創(chuàng)建的,那么顯示圖像原始大小。否則,將圖像進行縮放以適合窗口。而imshow?函數(shù)縮放圖像,取決于圖像的深度:
- 如果載入的圖像是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]。
還有一點,若窗口創(chuàng)建(namedWindow函數(shù))的時候,如果設(shè)定了支持OpenGL(WINDOW_OPENGL?),那么imshow還支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作為輸入。
?
?
四、輸出圖像到文件——imwrite函數(shù)
在OpenCV中,輸出圖像到文件,我們一般都用imwrite函數(shù),它的聲明如下:
bool imwrite(const string& filename,InputArray img, const vector<int>& params=vector<int>() );?
?■?第一個參數(shù),const string&類型的filename,填需要寫入的文件名就行了,帶上后綴,比如,“123.jpg”這樣。
?■?第二個參數(shù),InputArray類型的img,一般填一個Mat類型的圖像數(shù)據(jù)就行了。
?■?第三個參數(shù),const vector<int>&類型的params,表示為特定格式保存的參數(shù)編碼,它有默認值vector<int>(),所以一般情況下不需要填寫。而如果要填寫的話,有下面這些需要了解的地方:
?
- 對于JPEG格式的圖片,這個參數(shù)表示從0到100的圖片質(zhì)量(CV_IMWRITE_JPEG_QUALITY),默認值是95.
- 對于PNG格式的圖片,這個參數(shù)表示壓縮級別(CV_IMWRITE_PNG_COMPRESSION)從0到9。較高的值意味著更小的尺寸和更長的壓縮時間,而默認值是3。
- 對于PPM,PGM,或PBM格式的圖片,這個參數(shù)表示一個二進制格式標志(CV_IMWRITE_PXM_BINARY),取值為0或1,而默認值是1。
?
函數(shù)解析:
imwrite函數(shù)用于將圖像保存到指定的文件。圖像格式是基于文件擴展名的,可保存的擴展名和imread中可以讀取的圖像擴展名一樣,為了方便查看,我們在這里再列一遍:
- Windows位圖 - *.bmp, *.dib
- JPEG文件 - *.jpeg, *.jpg, *.jpe
- JPEG 2000文件- *.jp2
- PNG圖片 - *.png
- 便攜文件格式- *.pbm, *.pgm, *.ppm
- Sun rasters光柵格式 - *.sr, *.ras
- TIFF 文件 - *.tiff, *.tif
五、一個綜合示例
最后是一個綜合示例,載入圖像,進行簡單圖像混合,顯示圖像,并且輸出混合后的圖像到j(luò)pg。
由于篇幅原因,這里的圖像混合具體細節(jié)我們放到稍后的文章中再講,現(xiàn)在先給大家看看混合的效果和源碼。囧,因為opencv圖像處理真的很少涉及到設(shè)計模式的問題,所以很多時候往往就是main函數(shù)中塞滿一串串代碼打天下,即便是OpenCV官方的示例都是如此。
好了,如下就是這篇文章配套綜合示例的配套源碼,非常的簡單明了:
?
運行這個程序,會彈出四個我們在OpenCV中創(chuàng)建的窗口。
下面是運行截圖。首先是圖像載入和顯示的演示,我們載入了一張動漫人物圖:
?
?
接著是載入一張dota2原畫和dota2logo圖,為圖像融合做準備:
?
logo圖:
最終,經(jīng)過處理,得到dota2原畫+logo的融合,并輸出一張名為我喜歡打dota2 by淺墨.jpg的圖片到工程目錄下。
?
?
?嗯,本篇文章到這里就基本結(jié)束了,最后放出本篇文章配套示例程序的下載地址。
本篇文章的配套源代碼請點擊這里下載:
【淺墨OpenCV入門教程之三】圖像的載入,顯示和輸出配套源代碼下載
OK,本節(jié)的內(nèi)容大概就是這些,我們下篇文章見:)
?
淺墨_毛星云 博客專家 原創(chuàng)文章 159獲贊 9891訪問量 755萬+ 已關(guān)注 他的留言板總結(jié)
以上是生活随笔為你收集整理的转载:【opencv入门教程之三】:图片的载入|显示|输出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转载:【opencv入门教程之三】:组件
- 下一篇: 转载:【OpenCV入门教程之四】 RO