OpenCV入門學習筆記
一.簡介
- OpenCV(Open Source Computer Vision),開源計算機視覺庫
- 提供了不少函數,實現了不少計算機視覺算法,算法從最基本的濾波到高級的物體檢測皆有涵蓋
- 學習OpenCV所須要的基本知識
- C/C++編程基礎(編程能力)
- 瞭解算法原理(理論基礎知識)
- 提高理論基礎知識,所要了解的課程
- OpenCV知識一個算法庫,咱們並不須要徹底精通算法原理以後纔去使用,只須要了解它的功能,就能夠動手操做了
二.預備知識
1.編程的流程
- 編輯(edit)
- 編輯即編寫代碼,是編程的第一步
- 可使用任意編輯器編寫代碼,可是爲了方便,推薦使用功能豐富的編輯器
- 編譯(compile)
- 編譯是將某種編程語言寫成的源代碼,轉換成目標文件
- 目標文件包含
- 機器代碼(能夠直接被計算機CPU執行)
- 代碼在運行時使用的數據
- 編譯器(compiler)是實現這一目的的軟件
- Windows下的有cl.exe
- Linux下有gcc或g++
- 鏈接(link)
- 鏈接是將多個目標文件,以及庫文件生成可執行文件(或靜態庫/動態庫)的過程
- 鏈接器(linker)是實現這一目的的軟件
- 經常使用的鏈接器有
- Windows下的link.exe
- Linux下的ld等
- 運行(run)
- Visual C++(IDE)
- 集成開發環境(Integrated Development Environment)能夠幫助開發者對項目進行管理
- 頭文件
- 在存在多個源文件的狀況下,一個源文件中的函數要想調用另一個源文件中的函數
- 在編譯階段,因爲編譯器是對單個文件進行編譯,編譯器也不知道是否存在那個函數能夠調用,以及調用的方式是否正確,所以就須要藉助頭文件中的函數聲明來判斷
- 庫文件
- 庫文件中包含一系列的子程序,庫文件是二進制的,在庫文件中是看不到原始的源代碼的
- 庫文件和可執行文件的區別是,庫不是獨立程序,是向其餘程序提供服務的代碼
- 使用庫文件的好處
- 對源代碼進行保密
- 減小重複編譯的時間,加強程序的模塊化
- 將庫文件鏈接到程序中的兩種方式
2.OpenCV是什麼
- OpenCV其實就是一堆C和C++語言的源代碼文件,這些源代碼文件中實現了許多經常使用的計算機視覺算法
3.其餘知識
- 命令行參數
- int main(int argc, char** argv)
- int main(int argc, char* argv[])
- argc表示命令行輸入參數的個數(以空白符分隔)
- argv存儲了全部的命令行參數
- 例如:hello.exe Jiaqi Wang
- argc的值是3
- argv[0]是"hello.exe"
- argv[1]是"Jiaqi"
- argv[2]是"Wang"
- 常見編譯錯誤
- 出現編譯錯誤後,須要作的第一件事就是閱讀出錯信息
- 出錯信息雖然看似凌亂,可是可以提供不少有價值的信息,幫助開發者解決問題
- 常見編譯錯誤1:找不到頭文件
- 找不到頭文件通常有兩個緣由
- 頭文件的文件名拼寫錯誤
- 未將頭文件所在的路徑添加到開發環境中
- 若是文件名拼寫正確,編譯器仍是找不到頭文件,則須要將頭文件所在路徑添加到相應的變量中
- 常見編譯錯誤2:拼寫錯誤
- 在編程中,拼寫錯誤也是一類常見錯誤
- 若是檢查後發現不是拼寫錯誤,可能的緣由是聲明函數的頭文件未使用include語句包含到源文件中
- 若是源代碼不符合語法規則,也會形成編譯錯誤
- 常見連接錯誤
- 若是代碼符合語法規則,則會經過編譯過程
- 編譯完全部源代碼以後,下一步是鏈接目標文件,以造成可執行文件
- 編譯經過之後,在鏈接時出錯,多是沒有導入依賴的庫文件,故找不到對應的方法實現
- 須要將依賴的庫文件添加到項目設置中
- 運行時錯誤
- 通過編譯和鏈接的過程,生成了可執行文件,在運行這個可執行文件所產生的錯誤是運行時錯誤
- 比較常見的運行時錯誤是內存錯誤
- 在程序編寫中,對於數組和指針等,要特別的當心
- 由於對於空指針以及數組越界等問題,編譯器沒法在編譯時給出錯誤提示
- 這類錯誤一旦在運行時發生,排除起來很是困難
三.OpenCV介紹
- OpenCV的全稱是Open Source Computer Vision Library,是一個開放源代碼的計算機視覺庫
- OpenCV最初由英特爾公司發起並開發,以BSD許可證受權發行,能夠在商業和研究領域中無償使用,如今美國Willow Garage爲OpenCV提供主要的支持
- OpenCV可用於開發實時的圖像處理,計算機視覺以及模式識別程序,目前在工業界以及科研領域普遍採用
1.OpenCV的來源
- 誕生於Intel
- 初衷:提供一個計算機視覺庫,使之充分發掘CPU的計算能力,促進Intel產品的銷售
- 最初開發是由Intel在俄羅斯的團隊實現
- 2008年Willow Garage開始大力支持OpenCV
- Willow Garage是一家機器人公司
- 致力於爲我的機器人開發開放的硬件平臺和軟件
- 現已開發PR2機器人,並支持ROS/OpenCV/PCL等軟件
- ROS(Robot Operating System)是用於機器人的操做系統,是一個開發源代碼的軟件,OpenCV做爲ROS的視覺模塊嵌入
2.OpenCV的協議
- OpenCV採用BSD協議,這是一個很是寬鬆的協議
- 用戶能夠修改OpenCV的源代碼
- 能夠將OpenCV嵌入到本身的軟件中
- 能夠將包含OpenCV的軟件銷售,能夠用於商業產品
- 也能夠用於科研領域
- BSD協議並不具備"傳染性"
- 若是在軟件中使用OpenCV,你不須要公開代碼
- 你能夠對OpenCV作任何操做
- 協議對用戶的惟一約束就是
- 要在軟件的文檔或者說明中註明使用OpenCV,並附上OpenCV的協議
- OpenCV的協議保證了計算機視覺技術快速的傳播,讓更多的人從OpenCV受益
四.圖像的基本操做
1.圖像的表示
- 基本知識
- 人眼看到的圖像,在計算機看來,只是一堆亮度各異的點
- 一副尺寸爲M × N的圖像,能夠用一個M × N的矩陣來表示
- 矩陣元素的值表示這個位置上的像素的亮度
- 通常來講,像素值越大表示該點越亮
- 灰度圖和彩色圖像
- 通常來講,灰度圖用2維矩陣表示(M × N)
- 彩色(多通道)圖像用3維矩陣表示(M × N × 3)
- 對於圖像顯示來講,目前大部分設備都是用無符號8位整數(CV_8U)表示像素亮度
- 圖像數據在計算機內存中的存儲順序爲以圖像最左上點(也可能最左下點)開始
- 若是是多通道圖像,好比RGB圖像,則每一個像素用三個字節表示
- 在OpenCV中,RGB圖像的通道順序爲BGR
2.Mat類
- 早期的OpenCV
- 使用IpLImage和CvMat數據結構來表示圖像
- IpLImage和CvMat都是C語言的結構
- 使用這兩個結構的問題是內訓須要手動管理
- 開發者必須清楚什麼時候須要申請內存,什麼時候須要釋放內存
- 爲開發者帶來了必定的負擔,開發者應該將更多精力用於算法設計
- 所以,新版本的OpenCV中引入了Mat類
- 新版的OpenCV
- 新加入的Mat類可以自動管理內存
- 優勢:
- 不須要花費大量精力在內存管理上
- 代碼會變得很簡潔,代碼行數會變少
- 缺點:
- 使用C++接口在一些嵌入式開發系統中可能只支持C語言
- 若是開發平臺支持C++,徹底不必再用IpLImage和CvMat
- 在新版本的OpenCV中,開發者依然可使用IpLImage和CvMat
- 可是一些新增的函數只提供了Mat接口
class CV_EXPORTS Mat
{
public:
//一系列函數 ...
/* flag參數中包含許多關於矩陣的信息,如:
-Mat 的標識
-數據是否連續
-深度
-通道數目
*/
int flags;
//矩陣的維數,取值應該大於或等於 2
int dims;
//矩陣的行數和列數,若是矩陣超過 2 維,這兩個變量的值都爲-1
int rows, cols;
//指向數據的指針
uchar* data;
//指向引用計數的指針
//若是數據是由用戶分配的,則爲 NULL
int* refcount;
//其餘成員變量和成員函數
...
};
3.建立Mat對象
- Mat是一個很是優秀的圖像類,它同時也是一個通用的矩陣類
- 能夠用來建立和操做多維矩陣,有多種方法建立一個Mat對象
- 構造函數方法
- Mat M(3,2, CV_8UC3, Scalar(0,0,255));
- 建立一個行數(高度)爲3,列數(寬度)爲2的圖像
- 圖像元素是8位無符號整數類型,且有三個通道
- 圖像的全部像素值被初始化爲(0,0,255)
- 因爲OpenCV中默認的顏色順序爲BGR,所以這是一個全紅色的圖像
- Mat從新定義了<<操做符,使用這個操做符,能夠方便地輸出全部像素值,而不須要使用for循環逐個像素輸出
- 經常使用的構造方法有("::"表示做用域和所屬關係)
- Mat::Mat()
- Mat::Mat(int rows, int cols, int type)
- 建立行數爲rows,列數爲cols,類型爲type的圖像
- Mat::Mat(Size size, int type)
- Mat::Mat(int rows, int cols, int type, const Scalar& s)
- 建立行數爲rows,列數爲cols,類型爲type的圖像,並將全部元素初始化爲值s
- Mat::Mat(Size size, int type, const Scalar& s)
- 建立大小爲size,類型爲type的圖像,並將全部元素初始化爲值s
- Mat::Mat(const Mat& m)
- 將m賦值給新建立的對象,此處不會對圖像數據進行復制,m和新對象公用圖像數據
- Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
- 建立行數爲rows,列數爲cols,類型爲type的圖像,此構造函數不建立圖像數據所需內存,而是直接使用data所指內存,圖像的行步長由step指定
- Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
- 建立大小爲size,類型爲type的圖像,此構造函數不建立圖像數據所需內存,而是直接使用data所指內存,圖像的行步長由step指定
- Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
- 建立新圖像爲m的一部分,具體的範圍由rowRange和colRange指定,此構造函數也不進行圖像數據的複製操做,新圖像與m公用圖像數據
- Mat::Mat(const Mat& m, const Rect& roi)
- 建立的新圖像爲m的一部分,具體的範圍由roi指定,此構造函數也不進行圖像數據的複製操做,新圖像與m公用圖像數據
- 這些構造函數中,不少都涉及到類型type,type能夠是
- CV_8UC1
- CV_16SC1
- CV_64FC4
- C後面表示通道數
- 例如C1表示一個通道的圖像,C4表示4個通道的圖像,以此類推
- 若是須要更多的通道數,須要使用宏CV_8UC(n)
4.使用create()函數建立對象
- 除了在構造函數中能夠建立圖像,也可使用Mat類的create()函數建立圖像
- 若是create()函數指定的參數與圖像以前的參數相同,則不進行是指的內存申請操做
- 若是參數不一樣,則減小原始數據內存的索引,並從新申請內存
- 須要注意的是,使用create()函數沒法設置圖像像素的初始值
5.Matlab風格的建立對象方法
- OpenCV2中提供了Matlab風格的函數
- 如zeros(),ones(),eyes()
- 這種方法使得代碼很是簡潔,使用起來也很是方便
- 使用這些函數須要指定圖像的大小和類型
- Mat Z = Mat::zeros(2,3, CV_8UC1);
- Mat O = Mat::ones(2, 3, CV_32F);
- Mat E = Mat::eye(2, 3, CV_64F);
- 該代碼中,有些type參數如CV_32F未註明通道數目,這種狀況下它表示單通道
6.矩陣的基本元素表達
- 單通道圖像
- 對於單通道圖像,其元素類型通常爲8U(即8位無符號整數)
- 固然也能夠是16S/32F等,這些類型能夠直接用uchar/short/float等C/C++語言中的基本數據類型表達
- 多通道圖像
- 對於多通道圖像,如RGB彩色圖像,須要用三個通道來表示
- 在這種狀況下,若是依然將圖像視做一個二維矩陣,那麼矩陣的元素再也不是基本的數據類型
- OpenCV中有模板類Vec,能夠表示一個向量
- OpenCV中使用Vec類預約義了一些小向量,能夠將之用於矩陣元素的表達
- typedef Vec<uchar, 2> Vec2b;
- typedef Vec<short, 2> Vec2s;
- typedef Vec<int, 2> Vec2i;
- typedef Vec<float, 2> Vec2f;
- typedef Vec<double, 2> Vec2d;
- 例如8U類型的RGB彩色圖像可使用Vec3b,三通道float類型的矩陣可使用Vec3f
- 對於Vec對象,可使用[]符號如操做數組般讀寫其元素,如:
- Vec3b color; // color變量描述一種RGB顏色
- color[0] = 255; // B份量
- color[1] = 0; // G份量
- color[2] = 0; //R份量
7.像素值的讀寫
- 不少時候,咱們須要讀取某個像素值,或者設置某個像素值
- 在更多的時候,咱們須要對整個圖像裏的全部像素進行遍歷
- OpenCV提供了多種方法來實現圖像的遍歷
- at()函數
- 函數at()來實現讀取矩陣中的某個像素,或者對某個像素進行賦值操做
- uchar value = grayim.at
(i,j);//讀出第i行第j列像素值
- grayim.at
(i,j)=128; //將第i行第j列像素值設置爲128
- 注意:若是要遍歷圖像,並不推薦使用at()函數
- 使用這個函數的有優勢是代碼的可讀性高,可是效率並非很高
- 使用迭代器
- 若是你熟悉C++的STL庫,那必定了解迭代器(iterator)的使用
- 迭代器能夠方便地遍歷全部元素
- Mat也增長了迭代器的支持,通常與矩陣元素的遍歷
- 可是因爲使用了迭代器,而不是使用行數和列數來遍歷,因此就沒有了i和j變量
- 使用數據指針
- 使用IpLImage結構的時候,咱們會常用數據指針來直接操做像素
- 經過指針操做來訪問像素是很是高效的,可是務必要十分當心
- C/C++中的指針操做是不進行類型以及越界檢查的,若是指針訪問出錯,程序運行時有時候可能看上去一切正常,有時候卻忽然彈出段錯誤(segment fault)
- 對於不熟悉指針的編程者,不推薦使用指針操做
- 若是你很是注重程序的運行速度,那麼遍歷像素時,建議使用指針
8.選取圖像局部區域
- Mat類提供了不少方便的方法來選擇圖像的局部區域
- 使用這些方法時須要注意,這些方法並不進行內存的複製操做
- 若是將局部區域賦值給新的Mat對象,新對象與原始對象共用相同的數據區域,不從新申請內存,所以這些方法的執行速度都比較快
- 單行或單列的選擇
- 提取矩陣的一行或者一列可使用函數row()或col()
- 函數的聲明以下
- Mat Mat::row(int i) const
- Mat Mat::col(int j) const
- 用Range選擇多行或多列
- Range是OpenCV中新增的類,該類有兩個關鍵變量start和end
- Range對象能夠用來表示矩陣的多個連續的行或者多個連續的列
- 其表示範圍從start到end,包含start,但不包含end
- Range類還提供了一個靜態方法all(),這個方法的做用如同Matlab中的":",表示全部的行或者全部的列
- // 建立一個單位陣
- Mat A = Mat::eye(10, 10, CV_32S);
- // 提取第 1 到 3 列(不包括 3)
- Mat B = A(Range::all(), Range(1, 3));
- // 提取 B 的第 5 至 9 行(不包括 9)
- // 其實等價於 C = A(Range(5, 9), Range(1, 3)) Mat
- C = B(Range(5, 9), Range::all());
- 感興趣區域
- 從圖像中提取感興趣區域(Region of interest)有兩種方法
- 使用構造函數
- // 建立寬度爲 320,高度爲 240 的 3 通道圖像
- Mat img(Size(320,240),CV_8UC3);
- // roi 是表示 img 中 Rect(10,10,100,100)區域的對象
- Mat roi(img, Rect(10,10,100,100));
- 使用括號運算符
- Mat roi2 = img(Rect(10,10,100,100));
- 也可使用Range對象來定義感興趣區域
- // 使用括號運算符
- Mat roi3 = img(Range(10,100),Range(10,100));
- // 使用構造函數
- Mat roi4(img, Range(10,100),Range(10,100));
- 取對角線元素
- 矩陣的對角線元素可使用Mat類的diag()函數獲取
- 該函數的定義以下
- Mat Mat::diag(int d) const
- 當參數d=0時,表示取主對角線
- 當參數d>0時,表示取主對角線下方的次對角線
- 當參數d=1時,表示取主對角線下方,且緊貼主對角線的元素
- 當參數d<0時,表示取主對角線上方的次對角線
- 如同row()和col()函數,diag()函數也不進行內存複製操做,其複雜度也是O(1)
9.Mat表達式
- 利用C++中的運算符重載,OpenCV2中引入了Mat運算表達式
- 下面給出Mat表達式所支持的運算(下面列表中使用A和B表示Mat類型的對象,使用s表示Scalar對象,alpha表示double值)
- 加法,減法,取負:A+B,A-B,A+s,A-s,s+A,s-A,-A
- 縮放取值範圍:A*alpha
- 矩陣對應元素的乘法和除法: A.mul(B),A/B,alpha/A
- 矩陣乘法:A*B (注意此處是矩陣乘法,而不是矩陣對應元素相乘)
- 矩陣轉置:A.t()
- 矩陣求逆和求僞逆:A.inv()
- 矩陣比較運算:A cmpop B,A cmpop alpha,alpha cmpop A。此處 cmpop 能夠是>,>=,==,!=,<=,<。若是條件成立,則結果矩陣(8U 類型矩 陣)的對應元素被置爲 255;不然置 0。
- 矩陣位邏輯運算:A logicop B,A logicop s,s logicop A,~A,此處 logicop 能夠是&,|和^。
- 矩陣對應元素的最大值和最小值:min(A, B),min(A, alpha),max(A, B), max(A, alpha)。
- 矩陣中元素的絕對值:abs(A)
- 叉積和點積:A.cross(B),A.dot(B)
10.Mat_類
- Mat_類是對Mat類的一個包裝
- 在包裝中,只定義了幾個方法,沒有定義新的屬性
- 若是使用Mat_類,能夠在變量聲明時肯定元素的類型,訪問元素時再也不須要指定元素類型,既能使代碼簡潔,又能減小出錯的可能性
11.Mat類的內存管理
- 雖然使用Mat類時,內存管理變得簡單,可是若是清楚瞭解Mat類的內存管理,會更清楚一些函數到底操做了哪些數據
- Mat是一個類,由兩個數據部分組成
- 矩陣頭(包含矩陣尺寸/存儲方法/存儲地址等信息)
- 一個指向存儲全部像素值的矩陣的指針
- 矩陣頭的尺寸是常數值,但矩陣自己的尺寸會依圖像的不一樣而不一樣,一般比矩陣頭的尺寸大數個數量級
- 複製矩陣數據每每花費較多時間,所以除非有必要,不要複製大的矩陣
- 爲了解決矩陣數據的傳遞,OpenCV使用了引用計數
- 思路:讓每一個Mat對象有本身的矩陣頭信息,但多個Mat對象能夠共享同一個矩陣數據
- 讓矩陣指針指向同一地址而實現這一目的
- 不少函數以及不少操做(如函數參數傳值)只複製矩陣頭信息,而不復制矩陣數據
- 有不少種方法建立Mat類,若是Mat類本身申請數據空間,那麼該類會多申請4個字節(int類型),多出的4個字節存儲數據被引用的次數
- 引用次數存儲於數據空間的後面,refcount指向這個位置
- 當計數等於0時,則釋放該空間
12.輸出
- Mat類重載了<<操做符,能夠方便的使用流操做來輸出矩陣的內容
- 默認狀況下,輸出的格式是相似Matlab中矩陣的輸出格式
- 除了默認格式,Mat也支持其餘的輸出格式
- Python格式
- csv格式(以逗號分隔)
- numpy格式
- C語言格式
- 除了Mat對象可使用<<符號輸出,其餘的不少類型也支持<<輸出
13.Mat與ImlImage和CvMat的轉換
- 雖然OpenCV2引入了方便的Mat類,出於兼容性考慮,OpenCV依然是支持C語言接口的ImlImage和CvMat結構
- 若是要與之前的代碼兼容,將會涉及到Mat與ImlImage和CvMat的轉換
- Mat轉爲ImlImage和CvMat格式
- IplImage iplimg = img; //轉爲IplImage結構
- CvMat cvimg = img; //轉爲CvMat結構
- 注意:類型轉換後,ImlImage和CvMat與Mat公用同一矩陣數據,而ImlImage和CvMat沒有引用計數功能,若是img中數據被釋放,ImlImage和CvMat也就失去了數據,所以要牢記不可將Mat對象提早釋放
- ImlImage和CvMat格式轉爲Mat
- Mat 類有兩個構造函數,能夠實現 IplImage 和 CvMat 到 Mat 的轉換。
- 這兩 個函數都有一個參數 copyData。
- 若是 copyData 的值是 false,那麼 Mat 將與 IplImage 或 CvMat 共用同一矩陣數據;
- 若是值是 true,Mat 會新申請內存,而後將 IplImage 或 CvMat 的數據複製到 Mat 的數據區。
- 若是共用數據,Mat 也將不會使用引用計數來管理內存,須要開發者本身來管理。
- 建議作此轉換是將參數置爲 true,這樣內存管理變得簡單。
- Mat::Mat(const CvMat* m, bool copyData=false)
- Mat::Mat(const IplImage* img, bool copyData=false)
五.數據獲取與存儲
1.讀寫圖像文件
- 將圖像文件讀入內存,可使用imread()函數
- 將Mat對象以圖像文件格式寫入內存,可使用imwrite()函數
- 讀圖像文件
- imread()函數返回的是Mat對象
- 若是讀取文件失敗,則會返回一個空矩陣,即Mat::data的值是NULL
- 執行imread()以後,須要檢查文件是否成功讀入,可使用Mat::empty()函數進行檢查
- imread()函數的聲明以下
- Mat imread(const string& filename, int flags=1 )
- filename是被讀取或保存的圖像文件名
- 在imread()函數中,flag參數值有三種狀況
- flag>0,該函數返回3通道圖像,若是磁盤上的圖像文件是單通道的灰度圖像,則會被強制轉爲3通道
- flag=0,該函數返回單通道圖像,若是磁盤的圖像文件是多通道圖像,則會被強制轉爲單通道
- flag<0,該函數不會對圖像進行通道轉換
- imread()函數支持多種文件格式,且該函數是根據圖像文件的內容來肯定文件格式,而不是根據文件的擴展名來肯定
- 所支持的格式文件以下:
- Windows 位圖文件 - BMP, DIB;
- JPEG 文件 - JPEG, JPG, JPE;
- 便攜式網絡圖片 - PNG;
- 便攜式圖像格式 - PBM,PGM,PPM;
- Sun rasters - SR,RAS;
- TIFF 文件 - TIFF,TIF;
- TIFF 文件 - TIFF,TIF;
- JPEG 2000 圖片- jp2。
- 所安裝的OpenCV並不必定能支持上述全部格式,文件格式的支持須要特定的庫,只有在編譯OpenCV添加了響應的文件格式庫,纔可支持其格式
- 寫圖像文件
- 將圖像寫入文件,可使用imwrite()函數,該函數的聲明以下:
- bool imwrite(const string& filename, InputArray image, const vector
& params=vector
())
- 文件的格式由filename參數指定的文件擴展名肯定
- 推薦使用PNG文件格式
- BMP格式是無損格式,可是通常不進行壓縮,文件尺寸很是大
- JPEG格式的文件較小,可是JPEG是有損壓縮,會丟失一些信息
- PNG是無損壓縮格式,推薦使用
- imwrite()函數的第三個參數params能夠指定文件格式的一些細節信息,這個參數裏面的數值是跟文件格式相關的:
- JPEG:表示圖像的質量,取值範圍從0到100,數值越大表示圖像質量越高,固然文件也越大,默認值是95
- PNG:表示壓縮級別,取值範圍是從0到9,數值越大表示文件越小,可是壓縮花費的時間也越長,默認值是3
- PPM/PGM/PBM:表示文件是以二進制仍是純文本方式存儲,取值爲0或1,若是取值爲1,則表示以二進制方式存儲,默認值是1
- 並非全部Mat對象均可以村委圖像文件,目前支持的格式只有8U類型的單通道和3通道(顏色順序爲BGR)矩陣
- 若是須要保存16U格式圖像,只能使用PNG/JPEG2000/TIFF格式
- 若是但願將其餘格式的矩陣保存爲圖像文件,能夠現用Mat::convertTo()函數或者cvtColor()函數將矩陣轉爲能夠保存的格式
- 另外須要注意的是,在保存文件時,若是文件已經存在,imwrite()函數不會進行提醒,將直接覆蓋掉之前的文件
2.讀寫視頻
- 在介紹OpenCV讀寫視頻以前,先介紹一下編解碼器(codec)
- 若是是圖像文件,咱們能夠根據文件擴展名得知圖像的格式,可是此經驗不能推廣到視頻文件中
- 視頻的格式主要由壓縮算法決定,壓縮算法稱之爲編碼器(coder),解壓縮算法稱之爲解碼器(decoder),編解碼算法能夠統稱爲編解碼器(codec)
- 視頻文件能讀或寫,關鍵看是否有相應的編解碼器,編解碼器的種類很是多,經常使用的有MJPG/XVID/DIVX等,完整列表請參考FOURCC網站,所以視頻文件的擴展名每每只能表示這是一個視頻文件
- OpenCV2中提供了兩個類來實現視頻的讀寫
- 讀視頻的類是VideoCapture
- 寫視頻的類是VideoWriter
- 讀視頻
- VideoCapture既能夠從視頻文件讀取圖像,也能夠從攝像頭讀取圖像
- 可使用該類的構造函數打開視頻文件或者攝像頭
- 若是VideoCapture對象已經建立,也可使用VideoCapture::open()打開,VideoCapture::open()函數會自動調用VideoCapture::release()函數,先釋放已經打開的視頻,而後再打開新視頻
- 若是要讀一幀,可使用VideoCapture::read()函數
- VideoCapture類重載了>>操做符,實現了讀視頻幀的功能
- 寫視頻
- 使用OpenCV建立視頻也很是簡單,與讀視頻不一樣的是,須要在建立視頻時設置一系列參數,包括:
- 文件名
- 編解碼器:編解碼器使用四個字符表示
- CV_FOURCC('M','J','P','G')
- CV_FOURCC('X','V','I','D')
- CV_FOURCC('D','I','V','X')
- 若是使用某種編解碼器沒法建立視頻文件,請嘗試其餘的編解碼器
- 幀率
- 寬度
- 高度
- 將圖像寫入視頻可使用VideoWriter:write()函數,VideoWrite類中也重載了<<操做符,使用起來很是方便
- 另外須要注意:待寫入的圖像尺寸必須與建立視頻時指定的尺寸一致