最近在系統地學習OpenCV,將學習的過程在此做一個記錄,主要以代碼+注釋的方式
記錄學習過程。
cv::Mat有兩個必不可少的組成部分:一個頭部和一個數據塊。頭部包含了矩陣的所有相關信息(大小、通道數量、數據類型等);數據塊包含了圖像中所有像素的值。頭部有一個指向數據塊的指針,即data屬性。cv::Mat有一個很重要的屬性,即只有在明確要求時,內存塊才會被復制。實際上,大多數操作僅僅復制了cv::Mat的頭部,因此多個對象會同時指向同一個數據塊。
下面的程序可用來測試cv::Mat數據結構的不同屬性(代碼+注釋):
#include <iostream>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>// 測試函數, 它創建一個圖像cv::Mat function() { // 創建圖像 cv::Mat ima(500, 500, CV_8U, 50); // 返回圖像 return ima;} int main() { // 定義圖像窗口 cv::namedWindow("Image 1"); cv::namedWindow("Image 2"); cv::namedWindow("Image 3"); cv::namedWindow("Image 4"); cv::namedWindow("Image 5"); cv::namedWindow("Image"); /*我們需要指定每個矩陣元素的類型,這里我們用CV_8U表示每個像素 對應1字節,用字母U表示無符號,你也可用字母S表示有符號。對于 彩色圖像,你應該用三通道類型(CV_8UC3),也可以定義16位和 32位的整數(有符號或無符號),例如CV_16SC3。我們甚至可以使 用32位和64位的浮點數(例如CV_32F)。*/ // 創建一個240行 × 320列的新圖像 cv::Mat image1(240, 320, CV_8U, 100); cv::imshow("Image", image1); // 顯示圖像 cv::waitKey(0); // 等待按鍵 /*我們可以隨時用create方法分配或重新分配圖像的數據塊,如果圖 像已經分配,首先其原來的內容會被釋放。*/ // 重新分配一個新的圖像 image1.create(200, 200, CV_8U); image1 = 200; cv::imshow("Image", image1); // 顯示圖像 cv::waitKey(0); // 等待按鍵 /*圖像(或矩陣)的每個元素都可以包含多個值(例如彩色圖像中的三 個通道),因此OpenCV引入了一個簡單的數據結構cv::Scalar, 用于在調用函數時傳遞像素值。該結構通常包含一個或三個值。*/ // 創建一個紅色的圖像 // 通道次序為BGR cv::Mat image2(240, 320, CV_8UC3, cv::Scalar(0, 0, 255)); // 或者: // cv::Mat image2(cv::Size(320,240),CV_8UC3); // image2= cv::Scalar(0,0,255); cv::imshow("Image", image2); // 顯示圖像 cv::waitKey(0); // 等待按鍵 // 讀入一個圖像 cv::Mat image3 = cv::imread("puppy.bmp"); /*一旦沒有了指向cv::Mat對象的引用, 分配的內存就會被自動釋 放。 這一點非常方便, 因為它避免了C++動態內存分配中經常發生的 內存泄漏問題。 這是OpenCV 2中一個關鍵的機制, 它的實現方法是 通過cv::Mat實現計數引用和淺復制。 因此, 當在兩個圖像之間賦 值時, 圖像數據( 即像素) 并不會被復制, 此時兩個圖像都指向同一 個內存塊。 這同樣適用于圖像間的值傳遞或值返回。 由于維護了一個 引用計數器, 因此只有當圖像的所有引用都將釋放或賦值給另一個圖 像時, 內存才會被釋放;*/ // 所有這些圖像都指向同一個數據塊。 //下面的兩個圖像,對其中的任何一個做轉換都會影響到其他圖像。 cv::Mat image4(image3); image1 = image3; /*如果要對圖像內容做一個深復制, 你可以使用copyTo方法, 在此情況下 目標圖像會調用create方法。 另一個生成圖像副本的方法是clone, 即創建 一個完全相同的新圖像*/ // 這些圖像是源圖像的副本圖像 image3.copyTo(image2); cv::Mat image5 = image3.clone(); // 轉換圖像用來測試 cv::flip(image3, image3, 1); // 檢查哪些圖像在處理過程中受到了影響 cv::imshow("Image 3", image3); cv::imshow("Image 1", image1); cv::imshow("Image 2", image2); cv::imshow("Image 4", image4); cv::imshow("Image 5", image5); cv::waitKey(0); // 等待按鍵 // 從函數中獲取一個灰度圖像 cv::Mat gray = function(); cv::imshow("Image", gray); // 顯示圖像 cv::waitKey(0); // 等待按鍵 // 作為灰度圖像讀入 image1 = cv::imread("puppy.bmp", CV_LOAD_IMAGE_GRAYSCALE); /*如果你需要把一個圖像復制到另一個圖像中, 而兩者的數據類型不一 定相同, 那就要使用convertTo方法.需要注意的是, 這兩個圖像的通道數量 必須相同。*/ image1.convertTo(image2, CV_32F, 1 / 255.0, 0.0); cv::imshow("Image", image2); // 顯示圖像 cv::waitKey(0); // 等待按鍵 return 0;}程序運行結果:從左往下,image1至image5。
新聞熱點
疑難解答