OpenCV入門學習筆記

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)
        • 建立大小爲size,類型爲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
        • 8U表示8位無符號整數
      • CV_16SC1
        • 16S表示16位有符號整數
      • CV_64FC4
        • 64F表示64位浮點數(即double類型)
      • 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類中也重載了<<操做符,使用起來很是方便
    • 另外須要注意:待寫入的圖像尺寸必須與建立視頻時指定的尺寸一致
相關文章
相關標籤/搜索