OpenCV學習筆記 資料結構Mat詳解

2021-06-20 16:12:07 字數 4373 閱讀 7438

2023年剛剛出現的時候,opencv基於 

c語言介面而建。為了在記憶體(memory)中存放影象,當時採用名為 

iplimage

的c語言結構體,時至今日這仍出現在大多數的舊版教程和教學材料。但這種方法必須接受c語言所有的不足,這其中最大的不足要數手動記憶體管理,其依據是使用者要為開闢和銷毀記憶體負責。雖然對於小型的程式來說手動管理記憶體不是問題,但一旦**開始變得越來越龐大,你需要越來越多地糾纏於這個問題,而不是著力解決你的開發目標。

幸運的是,c++出現了,並且帶來類的概念,這給使用者帶來另外乙個選擇:自動的記憶體管理(不嚴謹地說)。這是乙個好訊息,如果c++完全相容c的話,這個變化不會帶來相容性問題。為此,opencv在2.0版本中引入了乙個新的c++介面,利用自動記憶體管理給出了解決問題的新方法。使用這個方法,你不需要糾結在管理記憶體上,而且你的**會變得簡潔(少寫多得)。但c++介面唯一的不足是當前許多嵌入式開發系統只支援c語言。所以,當目標不是這種開發平台時,沒有必要使用 舊 方法(除非你是自找麻煩的受虐狂碼農)。

關於 mat ,首先要知道的是你不必再手動地(1)為其開闢空間(2)在不需要時立即將空間釋放。但手動地做還是可以的:大多數opencv函式仍會手動地為輸出資料開闢空間。當傳遞乙個已經存在的 mat 物件時,開闢好的矩陣空間會被重用。也就是說,我們每次都使用大小正好的記憶體來完成任務。

基本上講 mat 是乙個類,由兩個資料部分組成:矩陣頭(包含矩陣尺寸,儲存方法,儲存位址等資訊)和乙個指向儲存所有畫素值的矩陣(根據所選儲存方法的不同矩陣可以是不同的維數)的指標。矩陣頭的尺寸是常數值,但矩陣本身的尺寸會依影象的不同而不同,通常比矩陣頭的尺寸大數個數量級。因此,當在程式中傳遞影象並建立拷貝時,大的開銷是由矩陣造成的,而不是資訊頭。opencv是乙個影象處理庫,囊括了大量的影象處理函式,為了解決問題通常要使用庫中的多個函式,因此在函式中傳遞影象是家常便飯。同時不要忘了我們正在討論的是計算量很大的影象處理演算法,因此,除非萬不得已,我們不應該拷貝 大的影象,因為這會降低程式速度。

為了搞定這個問題,opencv使用引用計數機制。其思路是讓每個 mat 物件有自己的資訊頭,但共享同乙個矩陣。這通過讓矩陣指標指向同一位址而實現。而拷貝建構函式則只拷貝資訊頭和矩陣指標,而不拷貝矩陣。

mat a, c;                                 // 只建立資訊頭部分

a = imread(argv[1], cv_load_image_color); // 這裡為矩陣開闢記憶體

mat b(a); // 使用拷貝建構函式

c = a; // 賦值運算子

以上**中的所有mat物件最終都指向同乙個也是唯一乙個資料矩陣。雖然它們的資訊頭不同,但通過任何乙個物件所做的改變也會影響其它物件。實際上,不同的物件只是訪問相同資料的不同途徑而已。

也就是說,

copy這樣的操作只是copy了矩陣的matrix header和那個指標,而不是矩陣的本身,也就意味著兩個矩陣的資料指標指向的是同乙個位址,需要開發者格外注意

。比如上面這段程式,a、b、c指向的是同一塊資料,他們的header不同,但對於a的操作同樣也影響著b、c的結果。這裡還要提及乙個比較棒的功能:你可以建立只引用部分資料的資訊頭。比如想要建立乙個感興趣區域( 

roi),你只需要建立包含邊界資訊的資訊頭:

mat d (a, rect(10, 10, 100, 100) ); // using a rectangle

mat e = a(range:all(), range(1,3)); // using row and column boundaries

現在你也許會問,如果矩陣屬於多個 

mat物件,那麼當不再需要它時誰來負責清理?簡單的回答是:最後乙個使用它的物件。通過引用計數機制來實現。無論什麼時候有人拷貝了乙個 

mat物件的資訊頭,都會增加矩陣的引用次數;反之當乙個頭被釋放之後,這個計數被減一;當計數值為零,矩陣會被清理。但某些時候你仍會想拷貝矩陣本身(不只是資訊頭和矩陣指標),這時可以使用函式 

clone()

或者 copyto()

mat f = a.clone();

mat g;

a.copyto(g);

現在改變 

f或者 

g就不會影響 

mat資訊頭所指向的矩陣。

總結一下,你需要記住的是

這裡講述如何儲存畫素值。需要指定顏色空間和資料型別。顏色空間是指對乙個給定的顏色,如何組合顏色元素以對其編碼。最簡單的顏色空間要屬灰度級空間,只處理黑色和白色,對它們進行組合可以產生不同程度的灰色。

對於 彩色 方式則有更多種類的顏色空間,但不論哪種方式都是把顏色分成三個或者四個基元素,通過組合基元素可以產生所有的顏色。rgb顏色空間是最常用的一種顏色空間,這歸功於它也是人眼內部構成顏色的方式。它的基色是紅色、綠色和藍色,有時為了表示透明顏色也會加入第四個元素 alpha (a)。

有很多的顏色系統,各有自身優勢:

每個組成元素都有其自己的定義域,取決於其資料型別。如何儲存乙個元素決定了我們在其定義域上能夠控制的精度。最小的資料型別是 char ,佔乙個位元組或者8位,可以是有符號型(0到255之間)或無符號型(-127到+127之間)。儘管使用三個 char 型元素已經可以表示1600萬種可能的顏色(使用rgb顏色空間),但若使用float(4位元組,32位)或double(8位元組,64位)則能給出更加精細的顏色分辨能力。但同時也要切記增加元素的尺寸也會增加了影象所佔的記憶體空間。

mat_對應的是cv_8u,mat_對應的是cv_8s,mat_對應的是cv_32s,mat_對應的是cv_32f,mat_對應的是cv_64f,對應的資料深度如下:

• cv_8u - 8-bit unsigned integers ( 0..255 )

• cv_8s - 8-bit signed integers ( -128..127 )

• cv_16u - 16-bit unsigned integers ( 0..65535 )

• cv_16s - 16-bit signed integers ( -32768..32767 )

• cv_32s - 32-bit signed integers ( -2147483648..2147483647 )

• cv_32f - 32-bit floating-point numbers ( -flt_max..flt_max, inf, nan )

• cv_64f - 64-bit floating-point numbers ( -dbl_max..dbl_max, inf, nan )

這裡還需要注意乙個問題,很多opencv的函式支援的資料深度只有8位和32位的,所以要少使用cv_64f,但是vs的編譯器又會把float資料自動變成double型,有些不太爽。

還有個需要注意的問題,就是流操作符《對於mat的操作,僅限於mat是2維的情況。

還有必要說一下mat的儲存是逐行的儲存的。

mat不但是乙個很讚的影象容器類,它同時也是乙個通用的矩陣類,所以可以用來建立和操作多維矩陣。建立乙個mat物件有多種方法:

mat()

建構函式:

mat m(2,2, cv_8uc3, scalar(0,0,255)); 

cout << "m = " << endl << " " << m << endl << endl;

對於二維多通道影象,首先要定義其尺寸,即行數和列數。

然後,需要指定儲存元素的資料型別以及每個矩陣點的通道數。為此,依據下面的規則有多種定義

cv_

[the

number

ofbits

peritem

][signed

orunsigned

][type

prefix]c

[the

channel

number

]

比如 cv_8uc3 表示使用8位的 unsigned char 型,每個畫素由三個元素組成三通道。預先定義的通道數可以多達四個。 scalar 是個short型vector。指定這個能夠使用指定的定製化值來初始化矩陣。當然,如果你需要更多通道數,你可以使用大寫的巨集並把通道數放在小括號中,如下所示

在 c\c++ 中通過建構函式進行初始化

int sz[3] = ; 

mat l(3,sz, cv_8uc(1), scalar::all(0));

上面的例子演示了如何建立乙個超過兩維的矩陣:指定維數,然後傳遞乙個指向乙個陣列的指標,這個陣列包含每個維度的尺寸;其餘的相

學習筆記 資料結構

一 常用的資料結構 1 線性資料結構 元素之間一般存在元素之間存在一對一關係,是最常用的一類資料結構,典型的有 陣列 棧 佇列和線性表 2 樹形結構 結點間具有層次關係,每一層的乙個結點能且只能和上一層的乙個結點相關,但同時可以和下一層的多個結點相關,稱為 一對多 關係,常見型別有 樹 堆 3 圖形...

學習筆記 資料結構 堆結構

堆結構 實質是陣列 特點 以陣列的形式去儲存完全二叉樹 原理 以前序遍歷完全二叉樹,得出結點的前序序列,以陣列的形式儲存該序列。查詢父,子結點通過陣列下標id間的轉換關係實現。優點 節省儲存空間,查詢效率高 缺點 1 只能表示完全二叉樹 更廣泛的可以說是完全n叉樹 2 對樹的插入,刪除操作執行效率低...

學習筆記 資料結構 雜湊

雜湊表的特點 什麼是完全雜湊 雜湊方式 直接定址表的特點 雜湊表的特點,可以解決什麼問題 什麼是衝突 如何避免衝突 鏈結法的特點,插入,刪除,查詢的時間複雜度是多少 開放定址方法的原理 什麼是裝載因子 雜湊函式有什麼 同義詞的概念 聚集 堆積 現象 單向雜湊表的特徵 如何提高雜湊表的查詢效率 通過一...