天天看點

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

本節書摘來自華章計算機《opencv圖像處理》一書中的第1章,第1.5節,作者:[西]葛羅瑞亞·布埃諾·加西亞(gloria bueno garcía)著,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視

圖像處理依賴于得到一幅圖像(例如,一張照片和一個視訊幀)并通過應用信号處理技術的“播放”(playing)來得到預期的結果。本節展示如何使用由opencv提供的函數從檔案中讀取圖像。

1.5.1 基本api概念

mat類是存儲和操作opencv中圖像的主要資料結構。這個類是在core子產品中定義的。opencv已經實作了對于這些資料結構自動配置設定和釋放記憶體的機制。但是,當資料結構共享相同的緩沖存儲器時,程式員仍然應該特别注意。例如,指派運算符并沒有從一個對象(mat a)到另一個對象(mat b)複制記憶體内容;而隻是對其引用(相應内容的存儲位址)的複制。之後,一個對象(a或b)的改變對兩個對象都有影響。為了複制一個mat對象的記憶體内容,應該使用成員函數mat::clone()。

opencv中的許多函數在處理密集的單通道或多通道數組時,常使用mat類。但是在某些場合,使用一個不同的資料類型可能很友善,例如,std::vector< >、matx< >、vec< >或scalar。為此,opencv提供了代理類inputarray和outputarray,允許前面的任意類型作為函數的參數使用。

mat類用于密集的n維單通道或多通道數組。實際上它可以存儲實數或複數值向量和矩陣、彩色圖像或灰階圖像、直方圖、點雲(point cloud)等。

有許多種不同的方式可用來建立一個mat對象,最流行的方法是構造函數,其數組的大小和類型被指定為:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

數組元素的初始值可以由scalar類設定為一個典型的四元素向量(對于存儲在數組中的圖像的每個rgb和透明度分量)。下面展示mat的一個使用示例:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

datatype類定義opencv的基本資料類型。基本資料類型可以是bool、unsigned char、signed char、unsigned short、signed short、int、f?loat、double或者是以這些基本類型之一的值構成的一個元組(或稱數組)。任何基本類型都可以用一個辨別符以下面的形式定義:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

在上面的代碼中,u、s和f分别代表unsigned、signed和f?loat資料類型。對于單通道數組,可應用下面的枚舉類型,其資料類型的描述為:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

此處,需要注意的是,這三個聲明是等價的:cv_8u、cv_8uc1和cv_8uc(1)。該單通道聲明最适合于灰階圖像的整型數組,然而一個數組的三通道聲明更适合于具有三個分量(例如,rgb、brg、hsv等)的圖像。對于線性代數運算,可以使用f?loat(f)類型的數組。

我們可以為多通道數組(高達512個通道)定義上面所有的資料類型。圖1-4說明一幅具有單個通道(cv_8u,灰階)圖像的内部表示和具有三個通道(cv_8uc3,rgb)的同一幅圖像。圖1-4是通過在一個opencv可執行檔案(showimage示例)的視窗中所顯示的一幅圖像的放大來獲得的:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

使用opencv函數正确地儲存一幅rgb圖像是很重要的,該圖像必須按照bgr通道順序在記憶體中存儲。按照同樣的方式,當從一個檔案中讀取一幅rgb圖像時,應按照bgr通道順序将其存儲在記憶體中。而且,需要補充第四個通道(alpha)來處理具有三個通道(rgb)的圖像,加上了一個透明度。對于rgb圖像,整數值越大,意味着像素更亮或alpha通道更透明。

所有的opencv類和函數都在cv命名空間(namespace)中,是以,在源代碼中還有如下兩個選項:

在包含頭檔案後還應添加使用命名空間cv的聲明(using namespace cv)(這是本書所有代碼示例所使用的選項)。

附加cv::字首到用到的所有opencv類、函數和資料結構上。如果由opencv提供的外部名字與常用的标準子產品庫(standard template library,stl)或其他庫沖突,那麼就推薦使用這個選項。

1.5.2 支援圖像檔案的格式

opencv支援最常見的圖像格式。但是,某些圖像格式需要(免費提供的)第三方類庫。由opencv支援的主要格式有:

windows bitmaps (.bmp、dib)

portable image formats (.pbm、.pgm、*.ppm)

sun rasters (.sr、.ras)

需要輔助庫的格式有:

jpeg (.jpeg、.jpg、*.jpe)

jpeg 2000 (*.jp2)

portable network graphics (*.png)

tiff (.tiff、.tif)

webp (*.webp).

對于opencv 3.0版本,除了上面列出的格式外,它還包含一個由地理資料抽象庫(geographic data abstraction library,gdal)所支援格式(nitf、dted、srtm等)的驅動器,通過cmake的選項with_gdal來設定。注意,在windows os上,對gdal的支援還沒有經過廣泛測試。在windows和os x中,預設對這些格式(libjpeg、libjasper、libpng和libtiff)使用opencv附帶的編解碼器。之後,在這些作業系統中,可以讀取jpeg、png和tiff格式。linux(和其他類unix開源作業系統)會尋找安裝在系統中的編解碼器。在opencv之前,可以安裝編解碼器或從opencv包中通過在cmake中設定正确的選項(例如,build_jasper、build_jpeg、build_png和build_tiff)來建構其他庫。

1.5.3 示例代碼

為了說明如何使用opencv讀、寫圖像檔案,現在,我們将描述showimage示例,如圖1-5所示。從指令行執行該示例,對應的輸出視窗如下:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

在本示例中,兩個檔案名稱作為參數給出。第一個是讀取的輸入圖像檔案。第二個是使用輸入圖像的一個灰階副本寫入的圖像檔案,接下來,展示源代碼及其說明:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案
《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

此處,使用#include指令包含opencv.hpp頭檔案,實際上,它包含所有的opencv頭檔案。通過包含該單個檔案,不再需要包含其他檔案。聲明所使用的cv命名空間之後,在這個命名空間内的所有變量和函數都不再需要cv::字首。在主函數中要做的第一件事情就是檢查指令行中傳遞的參數個數。之後,如果出現錯誤,則顯示一個幫助消息。

1.?讀取圖像檔案

如果參數個數正确,那麼使用函數imread(argv[1], imread_unchanged)将圖像檔案讀入到mat對象in_image中。這裡,第一個參數是在指令行中傳遞的第一個實參(argv[1]),第二個參數是一個标志(imread_unchanged),這就意味着存儲到記憶體圖像中的圖像不會被改變。函數imread決定圖像類型(編解碼器)來自檔案内容而不是來自檔案擴充名。

函數imread的原型如下:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

f?lag指定讀取圖像的顔色,并在imgcodecs.hpp頭檔案中由如下枚舉類型定義和

解釋:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

在opencv 3.0版本中,函數imread是在imgcodecs子產品中,而不是像opencv 2.x在highgui子產品中。

因為一些函數和聲明被移入到opencv 3.0中,是以連接配接器可能會由于找不到一個或多個聲明(符号和/或函數)而得到一些編譯錯誤。為了弄清楚在什麼地方(*.hpp)定義一個符号并且連結到哪個庫,推薦使用qt生成器ide的如下技巧:

向代碼添加聲明#include 。将滑鼠光标放在該符号或函數上并按f2功能鍵;這樣就會打開聲明了該符号或函數的*.hpp檔案。

讀取輸入的圖像檔案之後,應檢查操作是否成功。可使用成員函數in_image.empty()來實作這個檢查。如果讀取圖像檔案時沒有發生錯誤,會建立兩個視窗分别顯示輸入圖像和輸出圖像。使用如下函數進行視窗的建立:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

opencv視窗是通過程式中一個意義明确的名字來識别的。通過下面highgui.hpp頭檔案中的枚舉給出該标志的定義及其說明:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案
《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

一個視窗的建立不會在螢幕上顯示任何内容。在一個視窗中顯示一幅圖像的函數(屬于highgui子產品)是:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

如果使用window_autosize标志建立該視窗(winname),那麼所顯示的是原始大小的圖像(mat)。

在showimage示例中,第二個視窗顯示輸入圖像的一個灰階副本。為了将一幅彩色圖像轉換為灰階圖像,使用imgproc子產品的函數cvtcolor。實際上使用這個函數來改變圖像的顔色空間。

在一個程式中建立的任何視窗都可以從預設設定下調整大小和進行移動。當不再需要任何視窗時,應該銷毀視窗,以便釋放其資源。像示例中那樣,在一個程式結束時,會隐式地完成資源的釋放。

2.?在内部循環中處理事件

如果在一個視窗上顯示一幅圖像之後不再做任何事情,出乎意料地,将不再顯示圖像。在一個視窗顯示一幅圖像之後,我們應該開始一個循環,以擷取和處理與使用者和視窗互動有關的事件。通過如下函數可執行這樣一個任務(從highgui子產品中):

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

這個函數在數毫秒(delay>0)内等待一個按鍵操作,并傳回鍵的編碼,如果延遲結束時沒有按鍵則傳回-1。如果delay是0或負數,那麼函數一直等待直到一個鍵被

按下。

記住,隻有至少建立和激活一個視窗時,函數waitkey才會工作。

3.?寫入圖像檔案

imgcodecs子產品中的另一個重要函數是:

《OpenCV圖像處理》——1.5 讀取和寫入圖像檔案

這個函數将一幅圖像(img)儲存到一個檔案(f?ilename),作為第三個可選參數,一個“屬性-值”對的向量指定編解碼器的參數(為使用預設值将其設定為空)。編解碼器由檔案的擴充名決定。

繼續閱讀