2修正

我們有多種方法從現(xiàn)實(shí)世界中獲取數(shù)字圖像,如數(shù)碼相機(jī)、掃描儀、計(jì)算機(jī)斷層掃描和核磁共振成像等。在任何情況下,我們(人類)看到的都是圖像。而當(dāng)我們將其轉(zhuǎn)換存入數(shù)字設(shè)備時,記錄的則是圖像的每個點(diǎn)的數(shù)值。

例如,在上面的圖片中,你可以看到,汽車車鏡只不過是一個包含了像素點(diǎn)的所有強(qiáng)度值的矩陣。我們?nèi)绾潍@取和存儲像素值可能根據(jù)我們的需要而變化,但最終,計(jì)算機(jī)世界中的所有圖像都可能被簡化為數(shù)字矩陣和描述矩陣本身的其他信息。OpenCV是一個計(jì)算機(jī)視覺庫,它的主要焦點(diǎn)是處理和操作這些信息。因此,您需要熟悉的第一件事是OpenCV如何存儲和處理圖像。

Mat

OpenCV出現(xiàn)于2001年。當(dāng)時這個庫是圍繞一個C接口構(gòu)建的,并將圖像存儲在內(nèi)存中,他們使用了一個名為IplImage的C結(jié)構(gòu)。這在大多數(shù)舊教程和教材中都能看到。它麻煩在把C語言的所有缺點(diǎn)都推上臺面。最大的問題在手動內(nèi)存管理。它建立在用戶負(fù)責(zé)處理內(nèi)存分配和回收的假設(shè)之上。盡管這不是小程序的問題,但是,一旦您的代碼庫增長了,那么處理這些問題的難度將超過您的開發(fā)目標(biāo)。

所幸,C++出現(xiàn)了,并引入了類的概念,通過自動內(nèi)存管理(或多或少)使用戶更容易。好消息是,C++與C完全兼容,因此不可能產(chǎn)生兼容性問題。因此,opencv2.0引入了一個新的C++接口,它提供了一種新的做事方式,這意味著您不需要修改內(nèi)存管理,使您的代碼簡潔(更少寫,以獲得更多)。C++接口的主要缺點(diǎn)是,目前許多嵌入式開發(fā)系統(tǒng)只支持C.因此,除非您的目標(biāo)是嵌入式平臺,否則使用舊的方法是沒有意義的(除非您是一個受虐待的程序員,并且您正在自找麻煩)

關(guān)于Mat,您需要知道的第一件事是,您不再需要手動分配它的內(nèi)存,并在您不需要它的時候立即釋放它。雖然這仍然是一種可能,但大多數(shù)OpenCV函數(shù)都會自動分配它的輸出數(shù)據(jù)。如果你傳遞一個已經(jīng)存在的Mat對象,它已經(jīng)為矩陣分配了所需的空間,那么這將被重用。換句話說,我們在任何時候都只使用我們執(zhí)行任務(wù)所需的內(nèi)存。

Mat基本上是一個類有兩個數(shù)據(jù)部分:矩陣頭(包含信息矩陣的大小等,用于存儲的方法,在解決矩陣存儲,等等)和一個指向包含像素值的矩陣(采取任何維數(shù)取決于選擇的方法來存儲)。矩陣頭的大小是恒定的,但是矩陣本身的大小可能因圖像而異,而且通常是按數(shù)量級放大的。

OpenCV是一個圖像處理庫。它包含大量的圖像處理功能。要解決計(jì)算難題,大多數(shù)情況下,您最終會使用庫的多個功能。正因?yàn)槿绱?,將圖像傳遞給函數(shù)是一種常見的做法。我們不應(yīng)該忘記,我們討論的是圖像處理算法,它的計(jì)算量非常大。我們最不想做的事情就是通過不必要地復(fù)制潛在的大圖片來進(jìn)一步降低程序的速度。

為了解決這個問題,OpenCV使用一個引用計(jì)數(shù)系統(tǒng)。其思想是,每個Mat對象都有自己的頭,但是矩陣可以通過它們的矩陣指針指向同一個地址來共享它們之間的兩個實(shí)例。而且,復(fù)制操作符只會復(fù)制標(biāo)題和指向大矩陣的指針,而不是數(shù)據(jù)本身。

Mat A, C;// creates just the header parts

A =imread(argv[1],IMREAD_COLOR);// here we'll know the method used (allocate matrix)

Mat B(A);// Use the copy constructor

C = A;// Assignment operator

所有上面的對象,最后都指向同一個單一的數(shù)據(jù)矩陣。但是,它們的標(biāo)題是不同的,并且使用它們中的任何一個進(jìn)行修改也會影響到所有其他的。在實(shí)踐中,不同的對象只是為相同的底層數(shù)據(jù)提供不同的訪問方法。然而,它們的頭部分是不同的。真正有趣的部分是,您可以創(chuàng)建只引用完整數(shù)據(jù)的子部分的頭部。例如,在一個圖像中創(chuàng)建一個感興趣的區(qū)域(ROI),您只需創(chuàng)建一個帶有新邊界的新標(biāo)頭

Mat D (A,Rect(10, 10, 100, 100) );// using a rectangle

Mat E = A(Range::all(), Range(1,3));// using row and column boundaries

現(xiàn)在你可能會問,這個矩陣本身是否屬于多個墊子對象,當(dāng)它不再需要時,它負(fù)責(zé)清理它。簡短的回答是:最后一個使用它的對象。這是通過使用引用計(jì)數(shù)機(jī)制來處理的。每當(dāng)有人復(fù)制一個墊子對象的頭,就會為矩陣增加一個計(jì)數(shù)器。當(dāng)一個頭被清理時,這個計(jì)數(shù)器就會減少。當(dāng)計(jì)數(shù)器達(dá)到零時,矩陣也被釋放了。有時您也想要復(fù)制矩陣本身,所以O(shè)penCV提供了cv:::克隆()和cv::copyTo()函數(shù)。

Mat F = A.clone();

Mat G;

A.copyTo(G);

現(xiàn)在修改F或G不會影響到由墊子頭指向的矩陣。您需要記住的是:OpenCV函數(shù)的輸出圖像分配是自動的(除非另有說明)。您不需要使用OpenCVs C++接口來考慮內(nèi)存管理。賦值運(yùn)算符和復(fù)制構(gòu)造函數(shù)只復(fù)制標(biāo)題。圖像的底層矩陣可以使用cv:::克隆()和cv::copyTo()函數(shù)來復(fù)制。

存儲方法是關(guān)于如何儲存像素值的。您可以選擇使用的顏色空間和數(shù)據(jù)類型。顏色空間指的是我們?nèi)绾螌㈩伾M件組合成一種特定的顏色。最簡單的是灰色的比例,我們可以使用的顏色是黑白的。這些組合可以讓我們創(chuàng)造出許多灰色的陰影。

對于豐富多彩的方式,我們有更多的方法可供選擇。每一個都將其分解為3或4個基本組成部分,我們可以使用這些組合來創(chuàng)建其他的組件。最受歡迎的是RGB,主要是因?yàn)檫@也是我們的眼睛是如何構(gòu)建顏色的。它的底色是紅色、綠色和藍(lán)色。要對顏色的透明度進(jìn)行編碼,有時會有第四個元素:alpha(A)被添加。然而,還有很多其他的顏色系統(tǒng)都有各自的優(yōu)勢.

  RGB是最常見的,因?yàn)槲覀兊难劬κ褂玫氖穷愃频臇|西,但是請記住,OpenCV標(biāo)準(zhǔn)顯示系統(tǒng)使用BGR顏色空間(紅色和藍(lán)色通道的開關(guān))來組合顏色。

YCrCb被流行的JPEG圖像格式使用。

如果你需要測量一種顏色到另一種顏色的距離,那么它就會很方便。

每個建筑組件都有自己的有效域。這將導(dǎo)致使用的數(shù)據(jù)類型。我們?nèi)绾未鎯σ粋€組件定義了我們對其領(lǐng)域的控制。最小的數(shù)據(jù)類型可能是char,這意味著一個字節(jié)或8位。這可能是無符號的(也可以將值從0到255)或簽名(從-127到+127的值)。盡管在三個組件的情況下,這已經(jīng)提供了1600萬種可能的顏色(如RGB),但是我們可以通過使用浮點(diǎn)數(shù)(4字節(jié)=32位)或雙(8字節(jié)=64位)數(shù)據(jù)類型來獲得更精確的控制。然而,再保險

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

在Load、修改和保存一個圖像教程中,您已經(jīng)學(xué)習(xí)了如何通過使用cv::imwrite()函數(shù)來將矩陣寫入到圖像文件中。但是,為了便于調(diào)試,可以更方便地看到實(shí)際的值。你可以用Mat的運(yùn)算符來做這個,要知道這只適用于二維矩陣。

雖然Mat作為一個圖像容器很好地工作,但它也是一個通用的矩陣類。因此,創(chuàng)建和操作多維矩陣是可能的。您可以以多種方式創(chuàng)建Mat對象

cv::Mat::Mat Constructor

Mat M(2,2,CV_8UC3,Scalar(0,0,255));

cout <<"M = "<< endl <<" "<< M << endl << endl;

image

對于二維和多通道的圖像,我們首先定義它們的大?。盒泻土杏?jì)數(shù)。然后,我們需要指定用于存儲元素的數(shù)據(jù)類型和每個矩陣點(diǎn)的通道數(shù)量。為了做到這一點(diǎn),我們根據(jù)下面的約定構(gòu)造了多個定義

CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]

例如,CV 8UC3意味著我們使用的是8位長的無符號字符類型,每個像素有三個組成三個通道。這是預(yù)先定義的最多4個通道號碼。cv:標(biāo)量是四個元素的短向量。指定這一點(diǎn),您可以用定制值初始化所有矩陣點(diǎn)。如果您需要更多,您可以使用上面的宏創(chuàng)建類型,在括號中設(shè)置通道號,如下所示。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容