W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
OpenCV教程這里提到的所有源代碼都是作為OpenCV常規(guī)版本的一部分提供的,因此請(qǐng)?jiān)陂_始復(fù)制和粘貼代碼之前檢查。以下教程列表將自動(dòng)從位于我們的GIT存儲(chǔ)庫(kù)中的reST文件生成。
和往常一樣,我們很樂(lè)意聽到您的意見(jiàn),并收到您對(duì)任何教程的貢獻(xiàn)。
該文檔的其他章節(jié)描述了每個(gè)模塊的功能。但首先,請(qǐng)確保熟悉庫(kù)中使用的常見(jiàn)API概念。
所有OpenCV類和函數(shù)都放在cv命名空間中。因此,要從代碼訪問(wèn)此功能,請(qǐng)使用cv :: specifier或使用命名空間cv; 指示:
#include“opencv2 / core.hpp”
...
cv :: Mat H = cv :: findHomography(points1,points2,CV_RANSAC,5);
...
or:
#include "opencv2/core.hpp"
using namespace cv;
...
Mat H = findHomography(points1, points2, CV_RANSAC, 5 );
...
當(dāng)前或未來(lái)的OpenCV外部名稱中的一些可能與STL或其他庫(kù)沖突。在這種情況下,使用顯式命名空間說(shuō)明符來(lái)解決名稱沖突:
Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a);
a /= std::log(2.);
OpenCV自動(dòng)處理所有內(nèi)存。
首先,函數(shù)和方法使用的std :: vector,Mat和其他數(shù)據(jù)結(jié)構(gòu)具有析構(gòu)函數(shù),在需要時(shí)釋放底層內(nèi)存緩沖區(qū)。這意味著析構(gòu)函數(shù)并不總是像Mat一樣釋放緩沖區(qū)。他們考慮到可能的數(shù)據(jù)共享。析構(gòu)函數(shù)遞減與矩陣數(shù)據(jù)緩沖器相關(guān)聯(lián)的引用計(jì)數(shù)器。當(dāng)且僅當(dāng)引用計(jì)數(shù)器達(dá)到零時(shí),即當(dāng)沒(méi)有其他結(jié)構(gòu)指向相同的緩沖區(qū)時(shí),緩沖區(qū)被解除分配。類似地,當(dāng)Mat實(shí)例被復(fù)制時(shí),實(shí)際數(shù)據(jù)沒(méi)有被真正復(fù)制。相反,引用計(jì)數(shù)器增加以記住相同數(shù)據(jù)的另一個(gè)所有者。還有Mat :: clone方法可以創(chuàng)建矩陣數(shù)據(jù)的完整副本。見(jiàn)下面的例子:
// create a big 8Mb matrix
Mat A(1000, 1000, CV_64F);
// create another header for the same matrix;
// this is an instant operation, regardless of the matrix size.
Mat B = A;
// create another header for the 3-rd row of A; no data is copied either
Mat C = B.row(3);
// now create a separate copy of the matrix
Mat D = B.clone();
// copy the 5-th row of B to C, that is, copy the 5-th row of A
// to the 3-rd row of A.
B.row(5).copyTo(C);
// now let A and D share the data; after that the modified version
// of A is still referenced by B and C.
A = D;
// now make B an empty matrix (which references no memory buffers),
// but the modified version of A will still be referenced by C,
// despite that C is just a single row of the original A
B.release();
// finally, make a full copy of C. As a result, the big modified
// matrix will be deallocated, since it is not referenced by anyone
C = C.clone();
你看到Mat和其他基本結(jié)構(gòu)的使用很簡(jiǎn)單。但是,如果不考慮自動(dòng)內(nèi)存管理,高級(jí)類甚至用戶數(shù)據(jù)類型的創(chuàng)建呢?對(duì)于他們來(lái)說(shuō),OpenCV提供了類似于C ++ 11中的std :: shared_ptr的Ptr模板類。所以,而不是使用簡(jiǎn)單的指針:
T * ptr = new T(...);
您可以使用:
Ptr <T> ptr(new T(...));
or:
Ptr <T> ptr = makePtr <T>(...);
Ptr <T>封裝了一個(gè)指向T實(shí)例的指針和與該指針關(guān)聯(lián)的引用計(jì)數(shù)器。有關(guān)詳細(xì)信息,請(qǐng)參閱Ptr說(shuō)明。
OpenCV自動(dòng)釋放內(nèi)存,并且大部分時(shí)間自動(dòng)為輸出功能參數(shù)分配內(nèi)存。因此,如果一個(gè)函數(shù)有一個(gè)或多個(gè)輸入數(shù)組(cv :: Mat實(shí)例)和一些輸出數(shù)組,輸出數(shù)組將被自動(dòng)分配或重新分配。輸出數(shù)組的大小和類型根據(jù)輸入數(shù)組的大小和類型確定。如果需要,函數(shù)需要額外的參數(shù)來(lái)幫助找出輸出數(shù)組屬性。
例:
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0);
if(!cap.isOpened()) return -1;
Mat frame, edges;
namedWindow("edges",1);
for(;;)
{
cap >> frame;
cvtColor(frame, edges, COLOR_BGR2GRAY);
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
imshow("edges", edges);
if(waitKey(30) >= 0) break;
}
return 0;
}
由于視頻幀分辨率和比特深度對(duì)于視頻采集模塊是已知的,所以陣列幀由>>運(yùn)算符自動(dòng)分配。陣列邊緣由cvtColor函數(shù)自動(dòng)分配。它具有與輸入數(shù)組相同的大小和位深度。通道的數(shù)量為1,因?yàn)轭伾D(zhuǎn)換代碼COLOR_BGR2GRAY被傳遞,這意味著要進(jìn)行灰度轉(zhuǎn)換的顏色。請(qǐng)注意,幀和邊緣在循環(huán)體的第一次執(zhí)行期間僅被分配一次,因?yàn)樗邢乱粋€(gè)視頻幀具有相同的分辨率。如果您以某種方式更改視頻分辨率,則會(huì)自動(dòng)重新分配陣列。
該技術(shù)的關(guān)鍵組件是Mat :: create方法。它需要所需的數(shù)組大小和類型。如果數(shù)組已經(jīng)具有指定的大小和類型,該方法什么也不做。否則,它釋放先前分配的數(shù)據(jù)(如果有的話)(這部分涉及遞減引用計(jì)數(shù)器并將其與零進(jìn)行比較),然后分配所需大小的新緩沖區(qū)。大多數(shù)函數(shù)調(diào)用每個(gè)輸出數(shù)組的Mat :: create方法,因此實(shí)現(xiàn)了自動(dòng)輸出數(shù)據(jù)分配。
這個(gè)方案的一些顯著的例外是cv :: mixChannels,cv :: RNG :: fill和一些其他的功能和方法。他們不能分配輸出數(shù)組,所以你必須提前做到這一點(diǎn)。
作為計(jì)算機(jī)視覺(jué)庫(kù),OpenCV對(duì)圖像像素進(jìn)行了大量的處理,圖像像素通常以每個(gè)通道緊湊的8位或16位形式編碼,因此具有有限的范圍。此外,對(duì)于圖像的某些操作,如顏色空間轉(zhuǎn)換,亮度/對(duì)比度調(diào)整,銳化,復(fù)雜插值(雙立方體,Lanczos)可以在可用范圍之外產(chǎn)生值。如果只存儲(chǔ)結(jié)果中最低的8(16)位,則會(huì)導(dǎo)致視覺(jué)偽影,并可能影響進(jìn)一步的圖像分析。為了解決這個(gè)問(wèn)題,使用了所謂的飽和算術(shù)。例如,要將r操作的結(jié)果存儲(chǔ)到8位圖像,您可以在0..255范圍內(nèi)找到最接近的值:
類似的規(guī)則適用于8位有符號(hào)的16位有符號(hào)和無(wú)符號(hào)類型。這個(gè)語(yǔ)義在庫(kù)中隨處可見(jiàn)。在C ++代碼中,使用類似于標(biāo)準(zhǔn)C ++轉(zhuǎn)換操作的saturate_cast <>函數(shù)完成。見(jiàn)下面提供的公式的實(shí)現(xiàn):
(y,x)= saturate_cast <uchar>(r);
其中cv :: uchar是一個(gè)OpenCV 8位無(wú)符號(hào)整數(shù)類型。在優(yōu)化的SIMD代碼中,使用諸如paddusb,packuswb等SSE2指令。它們幫助實(shí)現(xiàn)與C ++代碼完全相同的行為。
模板是C ++的一個(gè)很好的功能,可以實(shí)現(xiàn)非常強(qiáng)大,高效且安全的數(shù)據(jù)結(jié)構(gòu)和算法。然而,廣泛使用模板可能會(huì)大大增加編譯時(shí)間和代碼大小。此外,當(dāng)僅使用模板時(shí),難以分離接口和實(shí)現(xiàn)。這對(duì)于基本算法來(lái)說(shuō)可能是很好的,但對(duì)于單個(gè)算法可能跨越數(shù)千行代碼的計(jì)算機(jī)視覺(jué)庫(kù)而言并不好。因此,為了簡(jiǎn)化其他語(yǔ)言的綁定,如Python,Java,沒(méi)有模板或模板功能有限的Matlab,目前的OpenCV實(shí)現(xiàn)是基于模板上的多態(tài)和運(yùn)行時(shí)調(diào)度。在那些運(yùn)行時(shí)調(diào)度太慢(像像素訪問(wèn)操作符)的地方,不可能(通用的Ptr <>實(shí)現(xiàn)),或只是非常不方便(saturate_cast <>()),目前的實(shí)現(xiàn)引入了小模板類,方法和函數(shù)。目前OpenCV版本中的其他任何地方,模板的使用受到限制。
因此,庫(kù)可以操作的原始數(shù)據(jù)類型有限。也就是說(shuō),數(shù)組元素應(yīng)該具有以下類型之一:
對(duì)于這些基本類型,應(yīng)用以下計(jì)算:
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
可以使用以下選項(xiàng)指定多通道(n通道)類型:
例:
Mat mtx(3, 3, CV_32F); // make a 3x3 floating-point matrix
Mat cmtx(10, 1, CV_64FC2); // make a 10x1 2-channel floating-point
// matrix (10-element complex vector)
Mat img(Size(1920, 1080), CV_8UC3); // make a 3-channel (color) image
// of 1920 columns and 1080 rows.
Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); // make a 1-channel image of
// the same size and same
// channel type as img
使用OpenCV無(wú)法構(gòu)建或處理具有更復(fù)雜元素的數(shù)組。此外,每個(gè)函數(shù)或方法只能處理所有可能的數(shù)組類型的子集。通常,算法越復(fù)雜,支持的格式子集越小。見(jiàn)下文典型的例子:
每個(gè)功能的支持類型的子集已經(jīng)根據(jù)實(shí)際需要定義,并且可以在將來(lái)根據(jù)用戶請(qǐng)求進(jìn)行擴(kuò)展。
許多OpenCV功能處理密集的二維或多維數(shù)字?jǐn)?shù)組。通常,這些函數(shù)以cppMat為參數(shù),但在某些情況下,使用std :: vector <>(例如,對(duì)于一個(gè)點(diǎn)集合)或Matx <>(對(duì)于3x3單應(yīng)性矩陣等)來(lái)說(shuō)更方便。為了避免API中的許多重復(fù),引入了特殊的“代理”類?;镜摹按怼鳖愂荌nputArray。它用于在函數(shù)輸入上傳遞只讀數(shù)組。派生自InputArray類的OutputArray用于指定函數(shù)的輸出數(shù)組。通常,您不應(yīng)該關(guān)心這些中間類型(而不應(yīng)該明確地聲明這些類型的變量) - 它們都將自動(dòng)工作。你可以假設(shè),而不是InputArray / OutputArray,你可以隨時(shí)使用Mat,std :: vector <>,Matx <>,Vec <>或Scalar。當(dāng)一個(gè)函數(shù)有一個(gè)可選的輸入或輸出數(shù)組,并且你沒(méi)有或不想要一個(gè),通過(guò)cv :: noArray()。
OpenCV使用異常來(lái)表示關(guān)鍵錯(cuò)誤。當(dāng)輸入數(shù)據(jù)具有正確的格式并且屬于指定的值范圍時(shí),但是由于某種原因(例如,優(yōu)化算法沒(méi)有收斂),算法無(wú)法成功,它返回一個(gè)特殊的錯(cuò)誤代碼(通常只是一個(gè)布爾變量) 。
例外可以是cv :: Exception類或其衍生物的實(shí)例。反過(guò)來(lái),cv :: Exception是std :: exception的派生詞。因此,可以使用其他標(biāo)準(zhǔn)C ++庫(kù)組件在代碼中正確處理。
通常會(huì)使用CV_Error(errcode,description)宏或其類似printf的CV_Error_(errcode,printf-spec,(printf-args))變體或使用CV_Assert(condition)宏來(lái)檢查該條件和當(dāng)不滿意時(shí)拋出異常。對(duì)于性能關(guān)鍵的代碼,CV_DbgAssert(條件)僅保留在調(diào)試配置中。由于自動(dòng)內(nèi)存管理,所有中間緩沖區(qū)會(huì)在突發(fā)錯(cuò)誤的情況下自動(dòng)釋放。如果需要,您只需要添加一個(gè)try語(yǔ)句即可捕獲異常:
try
{
... // call OpenCV
}
catch( cv::Exception& e )
{
const char* err_msg = e.what();
std::cout << "exception caught: " << err_msg << std::endl;
}
目前的OpenCV實(shí)現(xiàn)完全可重新進(jìn)入。也就是說(shuō),可以從不同的線程調(diào)用類實(shí)例的相同函數(shù),相同的常量方法或不同類實(shí)例的相同的非常量方法。另外,同樣的cv :: mat可以用于不同的線程,因?yàn)橐糜?jì)數(shù)操作使用特定于架構(gòu)的原子指令。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: