1有道直譯

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

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

MAT

OpenCV自2001年以來就一直存在。在那些日子里,圖書館是圍繞一個(gè)C接口構(gòu)建的,并將圖像存儲(chǔ)在內(nèi)存中,他們使用了一個(gè)名為IplImage的C結(jié)構(gòu)。這是你將在大多數(shù)舊的教程和教育材料中看到的。這個(gè)問題的問題在于,它把C語言的所有缺點(diǎn)都帶到了桌子上。最大的問題是手動(dòng)內(nèi)存管理。它建立在用戶負(fù)責(zé)處理內(nèi)存分配和回收的假設(shè)之上。雖然這不是小程序的問題,但是一旦您的代碼庫增長(zhǎng)了,那么處理所有這些問題將會(huì)更加困難,而不是專注于解決您的開發(fā)目標(biāo)。

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

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

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

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

為了解決這個(gè)問題,OpenCV使用一個(gè)引用計(jì)數(shù)系統(tǒng)。其思想是,每個(gè)Mat對(duì)象都有自己的頭,但是矩陣可以通過它們的矩陣指針指向同一個(gè)地址來共享它們之間的兩個(gè)實(shí)例。而且,復(fù)制操作符只會(huì)復(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


所有上面的對(duì)象,最后都指向同一個(gè)單一的數(shù)據(jù)矩陣。但是,它們的標(biāo)題是不同的,并且使用它們中的任何一個(gè)進(jìn)行修改也會(huì)影響到所有其他的。在實(shí)踐中,不同的對(duì)象只是為相同的底層數(shù)據(jù)提供不同的訪問方法。然而,它們的頭部分是不同的。真正有趣的部分是,您可以創(chuàng)建只引用完整數(shù)據(jù)的子部分的頭部。例如,在一個(gè)圖像中創(chuàng)建一個(gè)感興趣的區(qū)域(ROI),您只需創(chuàng)建一個(gè)帶有新邊界的新標(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)在你可能會(huì)問,這個(gè)矩陣本身是否屬于多個(gè)墊子對(duì)象,當(dāng)它不再需要時(shí),它負(fù)責(zé)清理它。簡(jiǎn)短的回答是:最后一個(gè)使用它的對(duì)象。這是通過使用引用計(jì)數(shù)機(jī)制來處理的。每當(dāng)有人復(fù)制一個(gè)墊子對(duì)象的頭,就會(huì)為矩陣增加一個(gè)計(jì)數(shù)器。當(dāng)一個(gè)頭被清理時(shí),這個(gè)計(jì)數(shù)器就會(huì)減少。當(dāng)計(jì)數(shù)器達(dá)到零時(shí),矩陣也被釋放了。有時(shí)您也想要復(fù)制矩陣本身,所以O(shè)penCV提供了cv:::克隆()和cv::copyTo()函數(shù)。

Mat F = A.clone();

Mat G;

A.copyTo(G);

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

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

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

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


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

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

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

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

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

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

cv::Mat::Mat?Constructor

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

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

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

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

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

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

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

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