opencv學習筆記(三十四)記憶體和序列

2021-07-28 06:32:01 字數 3982 閱讀 7336

1、記憶體

opencv使用記憶體儲存器(memory storage)來統一管理各種動態物件的記憶體。記憶體儲存器在底層被實現為乙個有許多相同大小的記憶體塊組成的雙向鍊錶,通過這種結構,opencv可以從記憶體儲存器中快速地分配記憶體或將記憶體返回給記憶體儲存器。

opencv中基於記憶體儲存器實現的函式,經常需要向記憶體儲存器申請記憶體空間(特別是那些返回動態結果的函式)。

記憶體儲存器可以通過以下四個函式訪問:

①:cvmemstorage* cvcreatememstorage(

int block_size=0

); ②:void cvreleasememstorage(

cvmemstorage** storage

); ③:void cvclearmemstorage(

cvmemstorage* storage

); ④:void* cvmemstoragealloc(

cvmemstorage* storage,

size_t size

); cvcreatememstorage用於建立乙個記憶體儲存器。引數block_size對應記憶體儲存器中每個記憶體塊的大小。如果block_size為0,則表示記憶體塊採用預設的大小,記憶體塊預設的大小為64 kb。該函式返回乙個新建立的記憶體儲存器指標。

cvreleasememstorage函式通過storage獲取有效的記憶體儲存器的位址,然後釋放該記憶體儲存器的所有空間。該函式的用法和opencv中釋放影象、釋放矩陣或者釋放其他結構的函式方法類似。

cvclearmemstorage函式則用於清空記憶體儲存器。注意,該函式是僅有的一種釋放記憶體儲存器中分配的記憶體的方法。該函式和通常釋放記憶體的函式區別是,它只是將釋放的記憶體返還給記憶體儲存器,而並不返還給系統。實際上通過cvclearmemstorage,我們可以很方便地重複使用記憶體儲存器中記憶體空間。注意,刪除任何動態物件(如cvseq,cvset等)並不會將記憶體返還到記憶體儲存器(這些結構通過在內部建立乙個記憶體儲存器以達到記憶體重複利用的目的)。

就像malloc ( )可以從堆中分配空間一樣,opencv中的cvmemstoragealloc也可以從乙個記憶體儲存器中申請空間。只需要向cvmemstoragealloc指定乙個記憶體儲存器和要申請的記憶體空間大小,然後返回分配記憶體的位址(返回值和malloc一樣為void指標)。

2、序列

序列是記憶體儲存器中可以儲存的一種物件。序列是某種結構的鍊錶。opencv中,序列可以儲存多種不同的結構。你可以將序列想像為許多程式語言中都存在的容器類或者容器類模板(如c++中的vector)。序列在記憶體被實現為乙個雙端佇列(deque)。因此序列可以實現快速的隨機訪問,以及快速刪除頂端的元素,但是從中間刪除元素則稍慢些。

序列中有一些重要的屬性(參考例8_1)需要了解。首先,最常用到的是total成員,total儲存序列中儲存的資料的個數。其次是h_prev,h_next,v_prev,和v_ next,它們是cv_ tree_ node_ fields的一部分,指向其他的序列(分別為上下左右四個方向)。這4個指標不是用來訪問序列中的元素,而是用來鏈結不同的序列。opencv中也有其他的結構包含cv_ tree_ node_ fields,我們可以使用包含cv_ tree_ node_ fields的結構構造出更複雜的結構,例如佇列、樹、圖等。僅僅使用變數h_prev和h_next,可實現乙個簡單的鍊錶。另外兩個變數v_prev和v_next可以用於建立那些比較密切的複雜的拓撲結構。通過這四個變數,函式cvfindcontours可以將影象中的複雜的輪廓構造為輪廓樹。

2.1 建立序列cvcreateseq()

cvseq* cvcreateseq(

int seq_flags,

int header_size,

int elem_size,

cvmemstorage* storage

); 功能:建立一串行

呼叫這個函式首先需要知道一些資訊,這些資訊用於控制建立的序列採用何種方式來組織資料。還需要序列的頭大小(通常為sizeof(cvseq))

引數:

seq_flags為序列的符號標誌。如果序列不會被傳遞給任何使用特定序列的函式,那麼將它設為0,否則從預定義的序列型別中選擇一合適的型別。

header_size為序列頭部的大小;必須大於或等於sizeof(cvseq)。如果制定了型別或它的副檔名,則此型別必須適合基類的頭部大小。

elem_size為元素的大小,以位元組計。這個大小必須與序列型別(由seq_flags指定)相一致。

例如,對於乙個點的序列,元素型別 cv_seq_eltype_point應當被指定,引數elem_size必須等同於sizeof(cvpoint)。storage為指向前面定義的記憶體儲存器。

2.2 刪除序列cvclearseq()

void cvclearseq(

cvseq* seq

); 該函式可以清空序列中的所有元素。不過該函式不會將不再使用的記憶體返回到記憶體儲存器中,也不會釋放給系統。但是當重新向序列中新增元素時,可以重複使用這裡面的記憶體塊。如果你想**序列中的記憶體塊,必須使用cvclearmemstore來實現。

3、直接訪問序列中的元素

cvgetseqelem()

格式:char * cvgetseqelem(seq,index)

用法:

1. 首先返回的是char型別的指標,當然也可以利用強制型別轉換,轉換為序列中實際儲存的資料型別。

例如:for(int i = 0; itotal;++i)

2.seq是需要檢測的序列,而index顧名思義是元素在序列中的索引,即第幾個元素。

cvseqelemidx()

格式:

int cvseqelemidx(

const cvseq* seq,

const void* element,

cvseqblock** block=null

); cvseqelemidx函式是乙個相對耗時的操作,因此使用的時候需要慎重(所花的時候跟序列的大小成正比)。

功能:返回序列中元素的索引。

4、切片、複製和移動序列中的資料

複製cvcloneseq()

cvseq* cvcloneseq(const cvseq* seq,cvmemstorage* storage=null);

該函式是對cvseqslice()進行簡單的包裝。cvseqslice()函式可以為序列中的子串行生成乙個新的序列(深度複製);也可以僅僅為子串行建立乙個頭,和原來序列共用元素空間。

複製cvseqslice()

cvseq* cvseqslice(

const cvseq* seq,

cvmemstorage* storage=null,

int copy_data=0

); cvseqslice中有乙個cvslice型別的引數,對應乙個切片。我們可以用

cvslice(a,b)函式,或gv_whole_seq巨集來定義切片,其中a對應開始,b對應結尾。在建立子串行的時候,只有切片之間的元素才會被複製(b如果為cv_whole_seq_end_index則表示序列在a位置後面的所有元素)。引數copy_data表示是否進行深度複製,如果進行深度複製則要複製每個元素。

刪除cvseqremove()

void cvseqremove(cvseq* seq,int index)

功能:刪除序列中的指定位置的元素

插入cvseqinsert()

char* cvseqinsert(cvseq* seq,int before_index,void* element=null)

功能:在序列中的指定位置新增元素

詳見

CUDA學習(三十四)

c語言擴充套件 函式執行空間說明符 函式執行空間說明符表示函式是在主機上還是在裝置上執行,以及函式是從主機還是從裝置中呼叫。device device 執行空間說明符宣告乙個函式 global 和 device 執行空間說明符不能一起使用。global 空間說明符將乙個函式宣告為乙個核心。這樣的功能...

Swift學習筆記(三十四) 函式型別

1 函式也可以賦值給乙個變數,此時這個變數的型別是什麼呢?import foundation func add a int,b int int let anotheradd int,int int add anotheradd 3,4 2 如果引數的返回值為空,那麼這個函式型別應該怎麼寫呢?impo...

C 學習筆記(三十四)知識整理1

1.整數轉化字串,不用itoa using namespace std 字串整數轉化 int main s i 0 cout s endl i i 1 while i 0 str j 0 cout str endl getchar return 0 2.字串轉化整數 using namespace ...