日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV Mat类详解和用法(官网原文)

發(fā)布時間:2025/3/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV Mat类详解和用法(官网原文) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

參考文章:OpenCV Mat類詳解和用法

我馬克一下,日后更

官網(wǎng)原文鏈接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_image_container.html

opencv3.2.0全套教程

文章目錄

  • 20211124 上面那篇文章也太長了吧,看完得幾個小時呢!這里就做些簡單筆記吧!
  • 全文 OpenCV Mat類詳解和用法
    • 目標
    • Mat(包含矩陣大小、存儲方法、矩陣存儲地址的矩陣頭和一個指向包含像素值的矩陣的指針)
      • 重點
    • 存儲方法
    • 顯式創(chuàng)建 Mat 對象
      • cv::Mat::Mat構(gòu)造函數(shù)
      • 使用 C/C++ 數(shù)組并通過構(gòu)造函數(shù)初始化
      • cv::Mat::create函數(shù):
      • MATLAB 樣式初始值設定項:cv::Mat::zeros、cv::Mat::ones、cv::Mat::eye。指定要使用的大小和數(shù)據(jù)類型:
      • 對于小矩陣,您可以使用逗號分隔的初始值設定項:
      • 為現(xiàn)有的Mat對象和cv::Mat::clone或cv::Mat::copyTo創(chuàng)建一個新頭部(header)
      • cv::randu()函數(shù)用隨機值填充矩陣
    • 輸出格式
      • 默認
      • Python(python風格會把一個像素點的不同通道像素值組合成組顯示,比默認顯示風格更加清晰)
      • 逗號分隔值(Comma separated values) (CSV)(額,,這種風格連括號都懶得給你打印了)
      • Numpy(Numpy風格挺詳細,連數(shù)據(jù)類型都給你打印出來了)
      • C
    • 其他常用項??目的輸出
      • 二維點
      • 3D點
      • std::vector via cv::Mat
      • std::vector of points

20211124 上面那篇文章也太長了吧,看完得幾個小時呢!這里就做些簡單筆記吧!

Mat本質(zhì)上是由兩個數(shù)據(jù)部分組成的類: (包含信息有矩陣的大小,用于存儲的方法,矩陣存儲的地址等) 的矩陣頭和一個指針,指向包含了像素值的矩陣(可根據(jù)選擇用于存儲的方法采用任何維度存儲數(shù)據(jù))。矩陣頭部的大小是恒定的。然而,矩陣本身的大小因圖像的不同而不同,通常是較大的數(shù)量級。


不行還是全文拷貝過來吧,因為重點內(nèi)容太多了!

全文 OpenCV Mat類詳解和用法

目標

我們有多種方法可以獲得從現(xiàn)實世界的數(shù)字圖像:數(shù)碼相機、掃描儀、計算機體層攝影或磁共振成像就是其中的幾種。在每種情況下我們(人類)看到了什么是圖像。但是,轉(zhuǎn)換圖像到我們的數(shù)字設備時我們的記錄是圖像的每個點的數(shù)值。


例如在上圖中你可以看到車的鏡子只是一個包含所有強度值的像素點矩陣。現(xiàn)在,我們?nèi)绾潍@取和存儲像素值可能根據(jù)最適合我們的需要而變化,最終可能減少計算機世界內(nèi)的所有圖像數(shù)值矩陣和一些其他的信息的描述基質(zhì)本身。OpenCV 是一個計算機視覺庫,其主要的工作是處理和操作,進一步了解這些信息。因此,你需要學習和開始熟悉它的第一件事是理解OpenCV 是如何存儲和處理圖像。

Mat(包含矩陣大小、存儲方法、矩陣存儲地址的矩陣頭和一個指向包含像素值的矩陣的指針)

OpenCV 自 2001 年出現(xiàn)以來。在那些日子里庫是圍繞C接口構(gòu)建的。在那些日子里,他們使用名為IplImage C 的結(jié)構(gòu)在內(nèi)存中存儲圖像。這是您將在大多數(shù)較舊的教程和教材中看到的那個。使用這個結(jié)構(gòu)的問題是將 C 語言的所有負面效果都擺到了桌面上。最大的問題是手動管理。它是建立在用戶來負責處理內(nèi)存分配和解除分配的假設之上的。當程序規(guī)模較小時,這是沒有問題的,一旦代碼基開始變得越來越大它將會越來越掙扎著處理所有這一切而不是著眼于實際解決自己的開發(fā)目標。

幸運的是 c + + 出現(xiàn)了,并引入了類的概念,使得為用戶開辟另一條路成為可能:

自動內(nèi)存管理 (或多或少)。好消息是,c + +,如果完全兼容 C 所以進行更改時沒有兼容性問題產(chǎn)生。因此, OpenCV其2.0 版本引入一個新的c + + 接口,通過利用這些優(yōu)點將為你的工作提供新的方法。某種程度上,在其中您不需要撥弄內(nèi)存管理讓你的代碼簡潔 (寫得更少,實現(xiàn)的更多)。C + + 接口的唯一主要缺點在于,目前許多嵌入式的開發(fā)系統(tǒng)支持僅 C.因此,除非您的目標是這一平臺,否則就沒有理由再使用舊的方法(除非你是個受虐狂程序員和喜歡自討苦吃)。

你需要知道的關于Mat的第一件事是你不再需要手動分配其大小并且當你不需要它的時候你不再需要手動釋放它。雖然這樣做仍然是可能的,大多數(shù) OpenCV 函數(shù)將手動分配其輸出數(shù)據(jù)。還有一個額外的好處是如果傳遞一個已存在Mat對象,它已經(jīng)為矩陣分配所需的空間,這段空間將被重用。也就是說我們在任何時候只使用與我們執(zhí)行任務時所必須多的內(nèi)存一樣多的內(nèi)存。

Mat本質(zhì)上是由兩個數(shù)據(jù)部分組成的類: (包含信息有矩陣的大小,用于存儲的方法,矩陣存儲的地址等)
的矩陣頭和一個指針,指向包含了像素值的矩陣(可根據(jù)選擇用于存儲的方法采用任何維度存儲數(shù)據(jù))。矩陣頭部的大小是恒定的。然而,矩陣本身的大小因圖像的不同而不同,通常是較大的數(shù)量級。因此,當你在您的程序中傳遞圖像并在有些時候創(chuàng)建圖像副本您需要花費很大的代價生成圖像矩陣本身,而不是圖像的頭部。OpenCV
是圖像處理庫,它包含大量的圖像處理函數(shù)。若要解決的計算挑戰(zhàn),最終大部分時間你會使用庫中的多個函數(shù)。由于這一原因圖像傳給庫中的函數(shù)是一種常見的做法。我們不應忘記我們正在談論往往是計算量相當大的圖像處理算法。我們想要做的最后一件事是通過制作不必要的可能很大的圖像的拷貝進一步降低您的程序的速度。

為了解決這一問題 OpenCV 使用引用計數(shù)系統(tǒng)。其思想是Mat的每個對象具有其自己的頭,但可能他們通過讓他們矩陣指針指向同一地址的兩個實例之間共享該矩陣。此外,拷貝運算符將只能復制矩陣頭部,也還將復制指針到大型矩陣,但不是矩陣本身。

Mat A, C; //僅創(chuàng)建了頭部 A = imread(argv[1], CV_LOAD_IMAGE_COLOR); //在此我們知道使用的方法(分配矩陣) Mat B(A); //使用拷貝構(gòu)造函數(shù) C = A; //賦值運算符

上文中的所有對象,以相同的單個數(shù)據(jù)矩陣的結(jié)束點。他們頭不同,但是使用的其中任何一個對矩陣進行任何修改,也將影響所有其他的。在實踐中的不同對象只是提供相同的底層數(shù)據(jù)不同的訪問方法,然而,它們的頭部是不同的。真正有趣的部分是您可以創(chuàng)建僅指向完整數(shù)據(jù)的一小部分的頭。例如,要在圖像中創(chuàng)建興趣區(qū)域 ( ROI) 您只需創(chuàng)建一個新頭設置新邊界:

Mat D (A, Rect(10, 10, 100, 100) ); // 用矩形界定 (x1, y1)(x2, y2)?Mat E = A(Range:all(), Range(1,3)); // 用行和列來界定(這個用不了不知怎么回事?)


現(xiàn)在,你可能會問是否矩陣的本身可以屬于多個Mat對象在不再需要時負責清理數(shù)據(jù)。簡短的回答是:最后一個使用它的對象。這對于使用引用計數(shù)的機制,每當有人復制Mat對象的頭,矩陣的計數(shù)器被增加。每當一個頭被清除,此計數(shù)器被下調(diào)。當該計數(shù)器變?yōu)榱?#xff0c;矩陣也就被釋放了。因為有時會仍然也要復制矩陣的本身,存在著 clone() 或 copyTo() 函數(shù)。

Mat F = A.clone(); Mat G; A.copyTo(G);

現(xiàn)在修改F或G不會影響Mat頭指向的矩陣。你需要記住的是:

重點

? 輸出圖像分配 OpenCV 功能是自動 (除非另行指定,否則)。? 用c + + OpenCV的接口就無需考慮內(nèi)存釋放。? 賦值運算符和復制構(gòu)造函數(shù) (構(gòu)造函數(shù))只復制頭。? 使用clone () 或copyTo () 函數(shù)將復制的圖像的基礎矩陣。

存儲方法

這是關于您如何存儲像素值。您可以選擇顏色空間和使用的數(shù)據(jù)類型。顏色空間是指我們?nèi)绾谓M合顏色分量以對給定顏色進行編碼。最簡單的一種是灰度,我們可以使用的顏色是黑色和白色。這些的組合使我們能夠創(chuàng)建許多灰色陰影。

對于豐富多彩的方式,我們有更多的方法可供選擇。他們每個人都將其分解為三個或四個基本組件,我們可以使用這些組件的組合來創(chuàng)建其他組件。最受歡迎的是RGB,主要是因為這也是我們的眼睛構(gòu)建顏色的方式。它的基色是紅色、綠色和藍色。為了編碼顏色的透明度,有時會添加第四個元素:alpha (A)。

然而,還有許多其他顏色系統(tǒng),每一個都有自己的優(yōu)勢:

  • RGB 是最常見的,因為我們的眼睛使用類似的東西,但請記住,OpenCV 標準顯示系統(tǒng)使用 BGR 色彩空間(紅色和藍色通道的切換)組合顏色。
  • HSV 和 HLS 將顏色分解為它們的色調(diào)、飽和度和值/亮度分量,這是我們描述顏色的更自然的方式。例如,您可能會忽略最后一個組件,使您的算法對輸入圖像的光照條件不太敏感。
  • 流行的 JPEG 圖像格式使用 YCrCb(YUV)。
  • CIE Lab* 是感知上均勻的顏色空間,如果您需要測量給定顏色到另一種顏色的距離,它會派上用場。

每個建筑組件都有自己的有效域。這導致使用的數(shù)據(jù)類型。我們?nèi)绾未鎯M件定義了我們對其域的控制。可能的最小數(shù)據(jù)類型是char,這意味著 1 個字節(jié)或 8 位。這可能是無符號的(因此可以存儲從 0 到 255 的值)或有符號的(從 -127 到 +127 的值)。雖然在三個組件的情況下,這已經(jīng)提供了 1600 萬種可能的顏色來表示(如在 RGB 的情況下)我們可以通過使用浮點數(shù)(4 字節(jié) = 32 位)或雙精度浮點型(8 字節(jié) = 64 位)數(shù)據(jù)獲得更精細的控制每個組件的類型。盡管如此,請記住,增加組件的大小也會增加內(nèi)存中整個圖片的大小。

顯式創(chuàng)建 Mat 對象

在加載、修改和保存圖像教程中,您已經(jīng)學習了如何使用cv::imwrite()函數(shù)將矩陣寫入圖像文件。但是,出于調(diào)試目的,查看實際值要方便得多。您可以使用Mat的 << 運算符執(zhí)行此操作。請注意,這僅適用于二維矩陣。

盡管Mat作為圖像容器非常有效,但它也是一個通用的矩陣類。因此,可以創(chuàng)建和操作多維矩陣。您可以通過多種方式創(chuàng)建 Mat 對象:

cv::Mat::Mat構(gòu)造函數(shù)

Mat M(2,2, CV_8UC3, Scalar(0,0,255));cout << "M = " << endl << " " << M << endl << endl;


我640×360的圖片打印了好久才打印完。。。

對于二維和多通道圖像,我們首先定義它們的大小:行和列計數(shù)。

然后我們需要指定用于存儲元素的數(shù)據(jù)類型和每個矩陣點的通道數(shù)。為此,我們根據(jù)以下約定構(gòu)造了多個定義:

CV_[每項的位數(shù)][有符號或無符號][類型前綴]C[通道編號]

例如,CV_8UC3意味著我們使用 8 位長的 unsigned char 類型,并且每個像素具有其中的三個以形成三個通道。這是為最多四個通道編號預定義的。該cv::Scalar是四個元件短矢量。指定此項,您可以使用自定義值初始化所有矩陣點。如果您需要更多,您可以使用上面的宏創(chuàng)建類型,在括號中設置通道號,如下所示。

使用 C/C++ 數(shù)組并通過構(gòu)造函數(shù)初始化

int sz[3] = {2,2,2};Mat L(3,sz, CV_8UC(1), Scalar::all(0));

上面的例子展示了如何創(chuàng)建一個多于二維的矩陣。指定其維度,然后傳遞一個包含每個維度大小的指針,其余保持不變。

(這L存的是什么數(shù)據(jù),我用std::cout打印不出來怎么回事,還報錯)

cv::Mat::create函數(shù):

M.create(4,4, CV_8UC(2));cout << "M = "<< endl << " " << M << endl << endl;


您無法使用此構(gòu)造初始化矩陣值。如果新大小不適合舊大小,它只會重新分配其矩陣數(shù)據(jù)內(nèi)存。

MATLAB 樣式初始值設定項:cv::Mat::zeros、cv::Mat::ones、cv::Mat::eye。指定要使用的大小和數(shù)據(jù)類型:

Mat E = Mat::eye(4, 4, CV_64F);cout << "E = " << endl << " " << E << endl << endl;Mat O = Mat::ones(2, 2, CV_32F);cout << "O = " << endl << " " << O << endl << endl;Mat Z = Mat::zeros(3,3, CV_8UC1);cout << "Z = " << endl << " " << Z << endl << endl;

E =[1, 0, 0, 0;0, 1, 0, 0;0, 0, 1, 0;0, 0, 0, 1]O =[1, 1;1, 1]Z =[ 0, 0, 0;0, 0, 0;0, 0, 0]

對于小矩陣,您可以使用逗號分隔的初始值設定項:

Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);cout << "C = " << endl << " " << C << endl << endl;

為現(xiàn)有的Mat對象和cv::Mat::clone或cv::Mat::copyTo創(chuàng)建一個新頭部(header)

Mat RowClone = C.row(1).clone();cout << "RowClone = " << endl << " " << RowClone << endl << endl;

cv::randu()函數(shù)用隨機值填充矩陣

筆記
您可以使用cv::randu()函數(shù)用隨機值填充矩陣。您需要為隨機值提供下限值和上限值:

Mat R = Mat(3, 2, CV_8UC3);randu(R, Scalar::all(0), Scalar::all(255));cout << "R = " << endl << " " << R << endl << endl;

輸出結(jié)果:

R =[ 91, 2, 79, 179, 52, 205;236, 8, 181, 239, 26, 248;207, 218, 45, 183, 158, 101]

輸出格式

在上面的示例中,您可以看到默認格式選項。但是,OpenCV 允許您格式化矩陣輸出:

默認

cout << "R (default) = " << endl << R << endl << endl;

結(jié)果同上

Python(python風格會把一個像素點的不同通道像素值組合成組顯示,比默認顯示風格更加清晰)

cout << "R (python) = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl; R (python) = [[[ 91, 2, 79], [179, 52, 205]],[[236, 8, 181], [239, 26, 248]],[[207, 218, 45], [183, 158, 101]]]

逗號分隔值(Comma separated values) (CSV)(額,,這種風格連括號都懶得給你打印了)

cout << "R (csv) = " << endl << format(R, Formatter::FMT_CSV) << endl << endl; R (csv) =91, 2, 79, 179, 52, 205 236, 8, 181, 239, 26, 248 207, 218, 45, 183, 158, 101

Numpy(Numpy風格挺詳細,連數(shù)據(jù)類型都給你打印出來了)

cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY ) << endl << endl; R (numpy) = array([[[ 91, 2, 79], [179, 52, 205]],[[236, 8, 181], [239, 26, 248]],[[207, 218, 45], [183, 158, 101]]], dtype='uint8')

C

cout << "R (c) = " << endl << format(R, Formatter::FMT_C ) << endl << endl; R (c) = { 91, 2, 79, 179, 52, 205,236, 8, 181, 239, 26, 248,207, 218, 45, 183, 158, 101}

其他常用項??目的輸出

OpenCV 也通過 << 運算符提供對其他常見 OpenCV 數(shù)據(jù)結(jié)構(gòu)的輸出的支持:

二維點

Point2f P(5, 1);cout << "Point (2D) = " << P << endl << endl; Point (2D) = [5, 1]

3D點

Point3f P3f(2, 6, 7);cout << "Point (3D) = " << P3f << endl << endl; Point (3D) = [2, 6, 7]

std::vector via cv::Mat

vector<float> v; v.push_back((float)CV_PI); v.push_back(2); v.push_back(3.01f); cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;

std::vector of points

vector<Point2f> vPoints(20); for (size_t i = 0; i < vPoints.size(); ++i)vPoints[i] = Point2f((float)(i * 5), (float)(i % 7)); cout << "A vector of 2D Points = " << vPoints << endl << endl; A vector of 2D Points = [0, 0;5, 1;10, 2;15, 3;20, 4;25, 5;30, 6;35, 0;40, 1;45, 2;50, 3;55, 4;60, 5;65, 6;70, 0;75, 1;80, 2;85, 3;90, 4;95, 5]

這里的大多數(shù)示例都包含在一個小型控制臺應用程序中。您可以從這里或在 cpp 示例的核心部分下載它。

您還可以在YouTube 上找到有關此的快速視頻演示。

總結(jié)

以上是生活随笔為你收集整理的OpenCV Mat类详解和用法(官网原文)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。