天天看點

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

點選檢視第一章 點選檢視第三章

第2章 OpenCV基礎知識導論

在第1章介紹了在不同作業系統上安裝OpenCV之後,我們将在本章介紹OpenCV開發的基礎知識。首先介紹如何使用CMake建立項目。我們将介紹基本的圖像資料結構和矩陣,以及在項目中工作所需的其他結構。我們還會介紹如何通過OpenCV的XML/YAML存儲函數将變量和資料儲存到檔案中。

本章介紹以下主題:

  • 使用CMake配置項目
  • 從/向磁盤讀取/寫入圖像
  • 讀取視訊和通路相機裝置
  • 主要圖像結構(例如,矩陣)
  • 其他重要和基本的結構(例如,向量和标量)
  • 基本矩陣運算簡介
  • 使用XML/YAML存儲OpenCV API進行檔案存儲操作

2.1 技術要求

本章需要讀者熟悉基本的C++程式設計語言,所使用的所有代碼都可以從以下GitHub連結下載下傳:

https://github.com/PacktPublishing/Learn-OpenCV-4-By-Building-Projects-Second-Edition/tree/master/Chapter_02

。代碼可以在任何作業系統上執行,盡管隻在Ubuntu上測試過。

2.2 基本CMake配置檔案

為配置和檢查項目的所有必要依賴項,我們會用到CMake,但這不是唯一可以完成此操作的方法。我們可以在任何其他工具或IDE中配置我們的項目,例如Makefiles或Visual Studio,但CMake是一種用于配置多平台C++項目的更便攜的方式。

CMake使用名為CMakeLists.txt的配置檔案,可以在其中定義編譯和依賴關系過程。對于從單個源代碼檔案建構可執行檔案的基本項目,隻需要一個包含三行代碼的CMakeLists.txt檔案。

該檔案的内容類似于:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

第一行定義所需的CMake最低版本,該行在CMakeLists.txt檔案中是必需的,它使我們能夠使用在特定版本中定義的CMake功能。在我們的例子中,要求最低版本為CMake 3.0。第二行定義項目的名稱。這個名稱儲存在名為PROJECT_NAME的變量中。

最後一行從main.cpp檔案建立一個可執行指令(add_executable()),并将其命名為與項目(${PROJECT_NAME})相同的名稱,然後将源代碼編譯成一個名為CMakeTest的可執行檔案,這是我們設定的項目名稱。${}表達式能夠通路環境中定義的任何變量。之後,我們就可以用${PROJECT_NAME}變量作為輸出的可執行檔案的名稱。

2.3 建立一個庫

CMake可用于建立由OpenCV建構系統使用的庫。在多個應用程式之間分解共享代碼是軟體開發中常見且有用的做法。在大型應用程式中,或者在多個應用程式共享的公共代碼中,這種做法非常有用。在這種情況下,我們不建立二進制可執行檔案,而是建立一個包含所有函數、類等的編譯檔案。這樣就可以和其他應用程式分享此庫檔案,而無須共享我們的源代碼。

CMake為此提供了add_library函數:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

以#開頭的行是添加的注釋,會被CMake忽略。add_library(Hello hello.cpp hello.h)指令定義庫的源檔案及其名稱,其中Hello是庫名,hello.cpp和hello.h是源檔案。我們還添加了頭檔案,使得諸如Visual Studio這樣的IDE能夠連結到頭檔案。該行将會生成一個共享(.so适用于Mac OS X和Unix,.dll适用于Windows)或靜态庫(.a适用于Mac OS X和Unix,.lib适用于Windows)檔案,具體取決于我們是否在庫名和源檔案之間添加SHARED或STATIC字。target_link_libraries(executable Hello)是将可執行檔案連結到所需庫的函數,在我們的例子中,需要的庫是Hello庫。

2.4 管理依賴項

CMake具備搜尋依賴項和外部庫的能力,這使我們能夠根據項目中的外部元件建構複雜的項目,并添加一些要求。

在本書中,最重要的依賴項自然是OpenCV,我們将把它添加到我們的所有項目中:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

現在,我們通過以下代碼了解腳本的工作原理:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

第一行定義CMake的最低版本,第二行告訴CMake使用CMake的新行為,以便識别正确的數字和布爾常量,而無須使用這些名稱間接引用變量。該政策是在CMake 2.8.0中引入的,當3.0.2版本中未設定此政策時,CMake會發出警告。最後一行定義項目的标題。定義項目名稱後,我們必須定義需求、庫和依賴項:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

這段代碼搜尋OpenCV依賴項。FIND_PACKAGE能夠查找依賴項、所需的最低版本以及該依賴是必需的還是可選的。在這個示例腳本中,我們查找4.0.0或更高版本的OpenCV,并聲明它是必需包。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

如果CMake沒有找到它,就會傳回錯誤,并且不會阻止我們編譯應用程式。MESSAGE函數在終端或CMake GUI中顯示一條消息。在這個例子中,我們将這樣顯示OpenCV版本:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

${OpenCV_VERSION}是CMake用來存儲OpenCV包版本的變量。include_directories()和link_directories()向環境中添加指定庫的頭檔案和路徑。OpenCV CMake的子產品将這些資料儲存在${OpenCV_INCLUDE_DIRS}和${OpenCV_LIB_DIR}變量中。并非所有平台(例如Linux)都需要這些指令行,因為這些路徑通常位于環境中,但是建議使用多個OpenCV版本來選擇正确的連結并包含路徑。現在包含我們開發的源檔案:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

最後一行建立可執行檔案,并将可執行檔案與OpenCV庫連結,如上一節中所述。這段代碼中有一個新的函數SET,該函數建立一個新變量,并向其添加我們需要的任何值。在這個例子中,我們将main.cpp值合并到SRC變量中。我們還可以在同一個變量中添加更多的值,如下面的腳本所示:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.5 讓腳本更複雜

在本節中,我們将要展示一個更複雜的腳本,它包括子檔案夾、庫和可執行檔案。但實際上,該腳本隻有兩個檔案和幾行代碼,如下例所示。沒有必要建立多個CMakeLists.txt檔案,因為我們可以在主CMakeLists.txt檔案中指定所有内容。但是,為每個項目子檔案夾使用不同的CMakeLists.txt檔案更為常見,可以使其更加靈活和便攜。

這個例子有一個代碼結構檔案夾,其中包含一個utils庫檔案夾和一個根檔案夾,後者包含主可執行檔案:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

然後,我們必須定義兩個CMakeLists.txt檔案,一個在根檔案夾中,另一個在utils檔案夾中。CMakeLists.txt根檔案夾檔案具有以下内容:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

除了我們将要解釋的一些函數之外,幾乎所有的代碼行都在前面中有過描述。add_subdirectory()告訴CMake分析所需子檔案夾的CMakeLists.txt。在繼續說明主CMakeLists.txt檔案之前,我們先解釋utils中的CMakeLists.txt檔案。

在utils檔案夾的CMakeLists.txt檔案中,我們将編寫一個将包含在主項目檔案夾中的新庫:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

此CMake腳本檔案定義一個變量UTILS_LIB_SRC,我們在其中添加庫中包含的所有源檔案,并使用add_library函數生成庫,并且使用target_include_directories函數以便允許主項目檢測所有頭檔案。離開utils子檔案夾,繼續準備根CMake腳本,其中,Option函數建立一個新的變量,在這個例子中為WITH_LOG,并附帶一小段描述。可以通過ccmake指令行或顯示描述内容的CMake GUI界面更改這個變量,使用者還可以通過一個複選框啟用或禁用此選項。這個函數非常有用,它使使用者能夠決定編譯時功能,例如,我們是否要啟用或禁用日志,是否像OpenCV一樣使用Java或Python進行編譯,等等。

在這個例子中,我們使用此選項在應用程式中啟用記錄器。為啟用記錄器,我們在代碼中使用了一個預編譯器定義,如下所示:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

可以通過調用add_definitions函數(-DLOG)在CMakeLists.txt中定義這個LOG宏,該函數本身可以使用簡單條件根據CMake變量WITH_LOG運作或隐藏:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

至此,我們就完成了建立CMake腳本檔案的準備工作,可以在任何作業系統中編譯我們的計算機視覺項目。然後,在開始示例工程之前,我們會繼續介紹OpenCV的基礎知識。

2.6 圖像和矩陣

毫無疑問,計算機視覺中最重要的結構是圖像。計算機視覺中的圖像是用數字裝置捕獲的實體世界的表示。這種圖檔隻是以矩陣格式存儲的一系列數字(參見圖2-1)。每個數字是所考慮的波長(例如,彩色圖像中的紅色、綠色或藍色)或波長範圍(對于全色裝置)的光強度的測量結果。圖像中的每個點都稱為像素(對于圖像元素),并且每個像素可以存儲一個或多個值,這取決于它是否是僅存儲一個值的黑白圖像(也稱為二進制圖像,比如隻存儲0或1),還是存儲兩個值的灰階圖像,或者是存儲三個值的彩色圖像。這些值通常在整數0~255,但也可以使用其他範圍,比如在高動态範圍成像(high dynamic range imaging,簡稱HDRI)或熱圖像領域中的浮點數0~1。

圖像是以矩陣格式存儲的,其中的每個像素都有一個位置,并且可以通過列和行的編号來引用。OpenCV用Mat類來達到這個目的。在灰階圖像中,使用單個矩陣,如圖2-2所示。

在如圖2-3所示的彩色圖像中,使用了一個寬度×高度×顔色通道數的矩陣。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論
帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

但Mat類不僅僅用于存儲圖像,它還能存儲任何類型和不同大小的矩陣。你可以将其用作代數矩陣并用它執行運算。在接下來的内容中,我們将描述最重要的矩陣運算,例如加法、乘法、對角化。但是,在此之前,了解矩陣如何存儲在計算機記憶體中是非常重要的,因為直接通路記憶體,總比用OpenCV函數通路每個像素更加高效。

在記憶體中,矩陣被儲存為按列和行排序的數組或值序列。表2-1顯示BGR圖像格式的像素序列。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

按照這個順序,我們可以通過以下公式來通路任何像素:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.7 讀/寫圖像

在介紹矩陣之後,我們将首先讨論OpenCV代碼的基礎知識。我們要學習的第一件事是如何讀/寫圖像:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論
帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

現在我們來了解代碼。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

首先,必須包括例子中需要的函數的聲明。這些函數來自core(基本圖像資料處理)和highgui(OpenCV提供的跨平台I/O函數是core和highgui;第一個包括基本類,比如矩陣,而第二個包括讀函數、寫函數,以及用圖形界面顯示圖像的函數)。現在讀取圖像:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

imread是讀取圖像的主函數。該函數打開圖像,并以矩陣格式存儲它。imread接受兩個參數,第一個參數是圖像路徑字元串,第二個參數是可選的,用于指定要加載的圖像類型,預設情況下為彩色圖像。第二個參數可以使用以下選項:

  • cv::IMREAD_UNCHANGED:如果設定,當輸入具有相應的深度時,傳回16位/ 32位圖像,否則将其轉換為8位
  • cv::IMREAD_COLOR:如果設定,它總是将圖像轉換為彩色圖像(BGR,8位無符号)
  • cv::IMREAD_GRAYSCALE:如果設定,它總是将圖像轉換為灰階圖像(8位無符号)

要儲存圖像,可以使用imwrite函數,它将矩陣圖像存儲在計算機中:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

第一個參數是儲存圖像的路徑,以及想要的擴充名格式,第二個參數是要儲存的矩陣圖像。在這個代碼例子中,我們建立并存儲圖像的灰階版本,然後将其另存為.jpg檔案。加載的灰階圖像将存儲在gray變量中:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

通過使用矩陣的.cols和.rows屬性,可以通路圖像的列數和行數,換句話說,可以通路其寬度和高度:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

要通路圖像的一個像素,可以用Mat OpenCV類中的模闆函數cv::Mat::at (row,col),模闆參數是所需的傳回類型。8位彩色圖像中的類型名稱是Vec3b類,它存儲三個無符号字元資料(Vec =向量,3 =元件數,b = 一個位元組)。在灰階圖像中,可以直接使用無符号字元,或圖像中使用的任何其他數字格式,例如uchar pixel = color.at (myRow,myCol)。最後,為了展示圖像,可以使用imshow函數,它建立一個視窗,其标題作為第一個參數,圖像矩陣作為第二個參數:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

前面代碼的結果如圖2-4所示,左邊的圖像是彩色圖像,右邊的圖像是灰階圖像。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

最後,我們按以下示例建立CMakeLists.txt檔案,并使用該檔案編譯代碼。

以下代碼描述了CMakeLists.txt檔案:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

要使用此CMakeLists.txt檔案編譯代碼,必須執行以下步驟:

  1. 建立一個build檔案夾。
  2. 在build檔案夾内,(在Windows中)執行CMake或打開CMake GUI應用程式,選擇source檔案夾和build檔案夾,然後按下“Configure”(配置)和“Generate”(生成)按鈕。
  3. 如果正在使用Linux或MacOSX,請照常生成Makefile,然後用make指令編譯項目。如果正在使用Windows,請用在步驟2中選擇的編輯器打開項目,然後進行編譯。

在編譯應用程式之後,将會在build檔案夾中生成一個名為app的可執行檔案。

2.8 讀取視訊和攝像頭

本節将用這個簡單示例向你介紹視訊和攝像頭的讀取。在解釋如何讀取視訊或攝像頭的輸入之前,我們想介紹一個非常有用的新類,它可以幫助我們管理輸入指令行參數。這個新類是在OpenCV 3.0版中引入的,它就是CommandLineParser類:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

我們必須為CommandLineParser做的第一件事是在常量char向量中定義我們需要或允許的參數,每一行都采用以下模式:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

name_param可以以@開頭,這會将此參數定義為預設輸入。我們可以使用多個name_param:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

構造函數将擷取main函數的輸入和先前定義的key常量:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

.has類方法檢查參數是否存在。在示例中,我們檢查使用者是否添加參數help或?,然後使用類函數printMessage顯示所有描述參數:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

使用.get(parameterName)函數可以通路和讀取任何輸入參數:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

擷取所有必需的參數以後,即可檢查這些參數是否被正确解析,并在其中一個參數未被解析時顯示錯誤消息,例如,添加的是一個字元串而不是一個數字:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

用于視訊讀取和攝像頭讀取的類是相同的VideoCapture類,與之前版本的OpenCV中一樣,它屬于videoio子子產品而不是highgui子子產品。建立對象後,我們檢查輸入指令行參數videoFile是否有路徑檔案名。如果它是空的,那麼嘗試打開網絡攝像頭;如果它有檔案名,則打開視訊檔案。為此,可以使用open函數,将視訊檔案名或我們要打開的索引攝像頭作為參數。如果我們有一個攝像頭,可以用0作為參數。

要檢查是否可以讀取視訊檔案名或攝像頭,可以使用isOpened函數:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

最後,建立一個視窗,使用namedWindow函數和無限循環來顯示幀,用>>操作抓取每個幀,如果正确地檢索到幀,則使用imshow函數顯示該幀。在這種情況下,我們不想讓應用程式停止,但是會調用waitKey(30)等待30毫秒,以此檢查使用者是否使用任何鍵停止應用程式的執行。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

當使用者想結束應用程式時,他們所要做的就是按下任意鍵,然後我們必須使用釋放函數釋放所有的視訊資源。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

前面代碼的結果是用一個新視窗顯示BGR格式的視訊或網絡攝像頭。

2.9 其他基本對象類型

我們已經了解了Mat和Vec3b類,但還有很多類需要學習。

在本節中,我們将學習大多數項目中所需的最基本的對象類型:

  • Vec
  • Scalar
  • Point
  • Size
  • Rect
  • RotatedRect

2.9.1 Vec對象類型

Vec是一個主要用于數值向量的模闆類。我們可以定義向量的類型群組件的數量:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

我們還可以使用任何的預定義類型:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論
帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論
帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.9.2 Scalar對象類型

Scalar對象類型是從Vec派生的模闆類,有四個元素。Scalar類型在OpenCV中廣泛用于傳遞和讀取像素值。

要通路Vec和Scalar值,可以使用[]運算符,其初始化可以用傳值的方式通過設定另一個标量、向量或值來完成,如下例所示:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.9.3 Point對象類型

另一個非常常見的類模闆是Point。該類定義一個由其坐标x和y指定的2D點。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

與Vec類一樣,OpenCV為友善起見定義了以下Point别名:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

OpenCV為Point定義了以下運算符:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.9.4 Size對象類型

Size是另一個非常重要并且在OpenCV中廣泛使用的模闆類,用于指定圖像或矩形大小。這個類添加了兩個成員width和height,以及有用的area()函數。在下面的示例中,我們可以看到許多使用Size的方法:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.9.5 Rect對象類型

Rect是另一個重要的模闆類,用于定義由以下參數定義的2D矩形:

  • 左上角的坐标
  • 矩形的寬度和高度

Rect模闆類可用于定義圖像的感興趣區域(Region of Interest,簡稱ROI),如下所示:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.9.6 RotatedRect對象類型

最後一個有用的類是名為RotatedRect的特定矩形。該類表示一個旋轉矩形,該矩形由中心點、矩形的寬度和高度以及機關為度的旋轉角度指定:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

這個類的一個有趣的函數是boundingBox,該函數傳回一個包含旋轉矩形的Rect,如圖2-5所示。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.10 基本矩陣運算

在本節中,我們将學習一些基本和重要的矩陣運算,這些運算可以應用于圖像或任何矩陣資料。我們已經知道如何加載圖像并将其存儲在變量Mat中,此外還可以手動建立Mat。最常見的構造函數是為矩陣提供大小和類型,如下所示:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

受支援的類型取決于要存儲的數字類型和通道數,最常見的類型如下:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

初始化不會設定資料的值,是以可能獲得不需要的值。為了避免不需要的值,可以使用0或1值及其各自的函數來初始化矩陣:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

前面矩陣的結果如圖2-6所示。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

一個特殊矩陣初始化是eye函數,它可以建立具有指定類型和大小的機關矩陣:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

其輸出如圖2-7所示。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

OpenCV的Mat類能夠執行所有的矩陣運算。我們可以用+和-運算符來加上或減去兩個相同大小的矩陣,如以下代碼塊所示:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

上述操作的結果如圖2-8所示。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

我們可以用運算符乘以一個标量,或者用mul函數乘以矩陣的每個元素,也可以用運算符執行矩陣乘法:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

上述操作的結果如圖2-9所示。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

其他常見的數學矩陣運算是轉置(transposition)和矩陣求逆(matrix inversion),分别由t()和inv()函數定義。OpenCV提供的其他有趣的函數是矩陣中的數組運算,例如,計算非零元素。這對于計算對象的像素或區域很有用:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

OpenCV提供了一些統計功能,可以使用meanStdDev函數計算通道的平均值和标準差:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

另一個有用的統計函數是minMaxLoc,該函數可以查找矩陣或數組的最小值和最大值,并傳回位置和值:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

這裡的src是輸入矩陣,minVal和maxVal是檢測到的最小值和最大值,minLoc和maxLoc是檢測到的Point值。

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.11 基本資料存儲

在結束本章之前,我們将探讨OpenCV用來存儲和讀取資料的函數。在許多應用程式中(例如校準或機器學習),當我們完成大量計算時,需要儲存這些結果,以便在後續操作中檢索它們。OpenCV為此提供了XML / YAML持久層。

寫入FileStorage

要把一些OpenCV或其他數值資料寫入檔案,可以用FileStorage類,同時要使用流運算符<<操作STL流:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論
帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

要建立儲存資料的檔案,隻需調用構造函數,并提供包含所需擴充名格式的路徑檔案名(XML或YAML),以及第二個要寫入的參數集:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

如果要儲存資料,隻需在第一步給出一個辨別符,然後提供想要儲存的矩陣或值,通過這種方式來使用流操作符。例如,要儲存int變量,隻需要編寫以下代碼行:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

否則,可以按如下所示寫入/儲存mat:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

上述代碼的結果是YAML格式:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

從檔案中讀取先前儲存的檔案與save函數非常相似:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

第一個階段是通過調用FileStorage構造函數并使用适當的參數、路徑和FileStorage::READ來打開一個儲存的檔案:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

要讀取任何存儲的變量,隻需使用公共的流運算符>>并使用FileStorage對象和帶[]運算符的辨別符:

帶你讀《OpenCV 4計算機視覺項目實戰 (原書第2版)》之二:OpenCV基礎知識導論第2章 OpenCV基礎知識導論

2.12 總結

在本章中,我們學習了OpenCV的基礎知識和最重要的類型和操作(通路圖像和視訊),以及它們如何存儲在矩陣中。我們還學習了基本的矩陣運算和用于存儲像素的其他基本OpenCV類、向量等。最後,我們學習了如何将資料儲存在檔案中,以便在其他應用程式或其他操作中讀取它們。

在下一章中,我們将學習如何建立第一個應用程式,進而學習OpenCV提供的圖形使用者界面的基礎知識。我們将建立按鈕和滑塊,并介紹一些圖像處理的基礎知識。

繼續閱讀