日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

OpenCV 常用算法

 牛人的尾巴 2014-09-30

OpenCV學(xué)習(xí)筆記(五)卡爾曼濾波器

 

 

 

卡爾曼濾波器 Kalman Filter

 

1    什么是卡爾曼濾波器

What is the Kalman Filter?

 

在學(xué)習(xí)卡爾曼濾波器之前,首先看看為什么叫“卡爾曼”。跟其他著名的理論(例如傅立葉變換,泰勒級數(shù)等等)一樣,卡爾曼也是一個人的名字,而跟他們不同的是,他是個現(xiàn)代人!

 

卡爾曼全名Rudolf Emil Kalman,匈牙利數(shù)學(xué)家,1930年出生于匈牙利首都布達佩斯。1953,1954年于麻省理工學(xué)院分別獲得電機工程學(xué)士及碩士學(xué)位。1957年于哥倫比亞大學(xué)獲得博士學(xué)位。我們現(xiàn)在要學(xué)習(xí)的卡爾曼濾波器,正是源于他的博士論文和1960年發(fā)表的論文《A New Approach to Linear Filtering and Prediction Problems》(線性濾波與預(yù)測問題的新方法)。如果對這編論文有興趣,可以到這里的地址下載: http://www.cs./~welch/media/pdf/Kalman1960.pdf。

 

簡單來說,卡爾曼濾波器是一個“optimal recursive data processing algorithm(最優(yōu)化自回歸數(shù)據(jù)處理算法)”。對于解決很大部分的問題,他是最優(yōu),效率最高甚至是最有用的。他的廣泛應(yīng)用已經(jīng)超過30年,包括機器人導(dǎo)航,控制,傳感器數(shù)據(jù)融合甚至在軍事方面的雷達系統(tǒng)以及導(dǎo)彈追蹤等等。近年來更被應(yīng)用于計算機圖像處理,例如頭臉識別,圖像分割,圖像邊緣檢測等等。

 

2.卡爾曼濾波器的介紹

Introduction to the Kalman Filter

 

為了可以更加容易的理解卡爾曼濾波器,這里會應(yīng)用形象的描述方法來講解,而不是像大多數(shù)參考書那樣羅列一大堆的數(shù)學(xué)公式和數(shù)學(xué)符號。但是,他的5條公式是其核心內(nèi)容。結(jié)合現(xiàn)代的計算機,其實卡爾曼的程序相當?shù)暮唵?,只要你理解了他的?/span>5條公式。

 

在介紹他的5條公式之前,先讓我們來根據(jù)下面的例子一步一步的探索。

 

假設(shè)我們要研究的對象是一個房間的溫度。根據(jù)你的經(jīng)驗判斷,這個房間的溫度是恒定的,也就是下一分鐘的溫度等于現(xiàn)在這一分鐘的溫度(假設(shè)我們用一分鐘來做時間單位)。假設(shè)你對你的經(jīng)驗不是100%的相信,可能會有上下偏差幾度。我們把這些偏差看成是高斯白噪聲(White Gaussian Noise),也就是這些偏差跟前后時間是沒有關(guān)系的而且符合高斯分配(Gaussian Distribution)。另外,我們在房間里放一個溫度計,但是這個溫度計也不準確的,測量值會比實際值偏差。我們也把這些偏差看成是高斯白噪聲。

 

好了,現(xiàn)在對于某一分鐘我們有兩個有關(guān)于該房間的溫度值:你根據(jù)經(jīng)驗的預(yù)測值(系統(tǒng)的預(yù)測值)和溫度計的值(測量值)。下面我們要用這兩個值結(jié)合他們各自的噪聲來估算出房間的實際溫度值。

 

假如我們要估算k時刻的是實際溫度值。首先你要根據(jù)k-1時刻的溫度值,來預(yù)測k時刻的溫度。因為你相信溫度是恒定的,所以你會得到k時刻的溫度預(yù)測值是跟k-1時刻一樣的,假設(shè)是23度,同時該值的高斯噪聲的偏差是5度(5是這樣得到的:如果k-1時刻估算出的最優(yōu)溫度值的偏差是3,你對自己預(yù)測的不確定度是4度,他們平方相加再開方,就是5)。然后,你從溫度計那里得到了k時刻的溫度值,假設(shè)是25度,同時該值的偏差是4度。

 

由于我們用于估算k時刻的實際溫度有兩個溫度值,分別是23度和25度。究竟實際溫度是多少呢?相信自己還是相信溫度計呢?究竟相信誰多一點,我們可以用他們的covariance來判斷。因為Kg^2=5^2/(5^2+4^2),所以Kg=0.78,我們可以估算出k時刻的實際溫度值是:23+0.78*(25-23)=24.56度??梢钥闯?,因為溫度計的covariance比較?。ū容^相信溫度計),所以估算出的最優(yōu)溫度值偏向溫度計的值。

 

現(xiàn)在我們已經(jīng)得到k時刻的最優(yōu)溫度值了,下一步就是要進入k+1時刻,進行新的最優(yōu)估算。到現(xiàn)在為止,好像還沒看到什么自回歸的東西出現(xiàn)。對了,在進入k+1時刻之前,我們還要算出k時刻那個最優(yōu)值(24.56度)的偏差。算法如下:((1-Kg)*5^2)^0.5=2.35。這里的5就是上面的k時刻你預(yù)測的那個23度溫度值的偏差,得出的2.35就是進入k+1時刻以后k時刻估算出的最優(yōu)溫度值的偏差(對應(yīng)于上面的3)。

 

就是這樣,卡爾曼濾波器就不斷的把covariance遞歸,從而估算出最優(yōu)的溫度值。他運行的很快,而且它只保留了上一時刻的covariance。上面的Kg,就是卡爾曼增益(Kalman Gain)。他可以隨不同的時刻而改變他自己的值,是不是很神奇!

 

下面就要言歸正傳,討論真正工程系統(tǒng)上的卡爾曼。

 

3    卡爾曼濾波器算法

The Kalman Filter Algorithm

 

在這一部分,我們就來描述源于Dr Kalman 的卡爾曼濾波器。下面的描述,會涉及一些基本的概念知識,包括概率(Probability),隨即變量(Random Variable),高斯或正態(tài)分配(Gaussian Distribution)還有State-space Model等等。但對于卡爾曼濾波器的詳細證明,這里不能一一描述。

 

首先,我們先要引入一個離散控制過程的系統(tǒng)。該系統(tǒng)可用一個線性隨機微分方程(Linear Stochastic Difference equation)來描述:

X(k)=A X(k-1)+B U(k)+W(k)

再加上系統(tǒng)的測量值:

Z(k)=H X(k)+V(k)

上兩式子中,X(k)k時刻的系統(tǒng)狀態(tài),U(k)k時刻對系統(tǒng)的控制量。AB是系統(tǒng)參數(shù),對于多模型系統(tǒng),他們?yōu)榫仃嚒?/span>Z(k)k時刻的測量值,H是測量系統(tǒng)的參數(shù),對于多測量系統(tǒng),H為矩陣。W(k)V(k)分別表示過程和測量的噪聲。他們被假設(shè)成高斯白噪聲(White Gaussian Noise),他們的covariance 分別是Q,R(這里我們假設(shè)他們不隨系統(tǒng)狀態(tài)變化而變化)。

 

對于滿足上面的條件(線性隨機微分系統(tǒng),過程和測量都是高斯白噪聲),卡爾曼濾波器是最優(yōu)的信息處理器。下面我們來用他們結(jié)合他們的covariances 來估算系統(tǒng)的最優(yōu)化輸出(類似上一節(jié)那個溫度的例子)。

 

首先我們要利用系統(tǒng)的過程模型,來預(yù)測下一狀態(tài)的系統(tǒng)。假設(shè)現(xiàn)在的系統(tǒng)狀態(tài)是k,根據(jù)系統(tǒng)的模型,可以基于系統(tǒng)的上一狀態(tài)而預(yù)測出現(xiàn)在狀態(tài):

X(k|k-1)=A X(k-1|k-1)+B U(k) ……….. (1)

(1)中,X(k|k-1)是利用上一狀態(tài)預(yù)測的結(jié)果,X(k-1|k-1)是上一狀態(tài)最優(yōu)的結(jié)果,U(k)為現(xiàn)在狀態(tài)的控制量,如果沒有控制量,它可以為0。

 

到現(xiàn)在為止,我們的系統(tǒng)結(jié)果已經(jīng)更新了,可是,對應(yīng)于X(k|k-1)covariance還沒更新。我們用P表示covariance

P(k|k-1)=A P(k-1|k-1) A+Q ……… (2)

(2)中,P(k|k-1)X(k|k-1)對應(yīng)的covariance,P(k-1|k-1)X(k-1|k-1)對應(yīng)的covariance,A’表示A的轉(zhuǎn)置矩陣,Q是系統(tǒng)過程的covariance。式子1,2就是卡爾曼濾波器5個公式當中的前兩個,也就是對系統(tǒng)的預(yù)測。

 

現(xiàn)在我們有了現(xiàn)在狀態(tài)的預(yù)測結(jié)果,然后我們再收集現(xiàn)在狀態(tài)的測量值。結(jié)合預(yù)測值和測量值,我們可以得到現(xiàn)在狀態(tài)(k)的最優(yōu)化估算值X(k|k)

X(k|k)= X(k|k-1)+Kg(k) (Z(k)-H X(k|k-1)) ……… (3)

其中Kg為卡爾曼增益(Kalman Gain)

Kg(k)= P(k|k-1) H / (H P(k|k-1) H + R) ……… (4)

 

到現(xiàn)在為止,我們已經(jīng)得到了k狀態(tài)下最優(yōu)的估算值X(k|k)。但是為了要另卡爾曼濾波器不斷的運行下去直到系統(tǒng)過程結(jié)束,我們還要更新k狀態(tài)下X(k|k)covariance

P(k|k)=I-Kg(k) HP(k|k-1) ……… (5)

其中I 1的矩陣,對于單模型單測量,I=1。當系統(tǒng)進入k+1狀態(tài)時,P(k|k)就是式子(2)P(k-1|k-1)。這樣,算法就可以自回歸的運算下去。

 

卡爾曼濾波器的原理基本描述了,式子1,2,345就是他的5 個基本公式。根據(jù)這5個公式,可以很容易的實現(xiàn)計算機的程序

 

 

4月4日

OpenCV學(xué)習(xí)筆記(四)運動物體跟蹤的camshift算法

CamShift算法
簡介
CamShift算法,即"Continuously Apative Mean-Shift"算法,是一種運動跟蹤算法。它主要通過視頻圖像中運動物體的顏色信息來達到跟蹤的目的。我把這個算法分解成三個部分,便于理解:

Back Projection計算。

Mean Shift算法

CamShift算法

1 Back Projection計算
計算Back Projection的步驟是這樣的:

1. 計算被跟蹤目標的色彩直方圖。在各種色彩空間中,只有HSI空間(或與HSI類似的色彩空間)中的H分量可以表示顏色信息。所以在具體的計算過程中,首先將其他的色彩空間的值轉(zhuǎn)化到HSI空間,然后會其中的H分量做1D直方圖計算。

2. 根據(jù)獲得的色彩直方圖將原始圖像轉(zhuǎn)化成色彩概率分布圖像,這個過程就被稱作"Back Projection"。

在OpenCV中的直方圖函數(shù)中,包含Back Projection的函數(shù),函數(shù)原型是:

   void cvCalcBackProject(IplImage** img, CvArr** backproject, const CvHistogram* hist);

傳遞給這個函數(shù)的參數(shù)有三個:

1. IplImage** img:存放原始圖像,輸入。

2. CvArr** backproject:存放Back Projection結(jié)果,輸出。

3. CvHistogram* hist:存放直方圖,輸入

 

下面就給出計算Back Projection的OpenCV代碼。

1.準備一張只包含被跟蹤目標的圖片,將色彩空間轉(zhuǎn)化到HSI空間,獲得其中的H分量:

  IplImage* target=cvLoadImage("target.bmp",-1);  //裝載圖片

  IplImage* target_hsv=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );

  IplImage* target_hue=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );

  cvCvtColor(target,target_hsv,CV_BGR2HSV);       //轉(zhuǎn)化到HSV空間

  cvSplit( target_hsv, target_hue, NULL, NULL, NULL );    //獲得H分量

2.計算H分量的直方圖,即1D直方圖:

  IplImage* h_plane=cvCreateImage( cvGetSize(target_hsv),IPL_DEPTH_8U,1 );

  int hist_size[]={255};          //將H分量的值量化到[0,255]

  float* ranges[]={ {0,360} };    //H分量的取值范圍是[0,360)

  CvHistogram* hist=cvCreateHist(1, hist_size, ranges, 1);

  cvCalcHist(&target_hue, hist, 0, NULL);

在這里需要考慮H分量的取值范圍的問題,H分量的取值范圍是[0,360),這個取值范圍的值不能用一個byte來表示,為了能用一個byte表示,需要將H值做適當?shù)牧炕幚?在這里我們將H分量的范圍量化到[0,255].

4.計算Back Projection:

  IplImage* rawImage;

  //----------------------------------------------

  //get from video frame,unsigned byte,one channel

  //----------------------------------------------

  IplImage* result=cvCreateImage(cvGetSize(rawImage),IPL_DEPTH_8U,1);

  cvCalcBackProject(&rawImage,result,hist);

5.結(jié)果:result即為我們需要的.

2) Mean Shift算法
 

這里來到了CamShift算法,OpenCV實現(xiàn)的第二部分,這一次重點討論Mean Shift算法。

在討論Mean Shift算法之前,首先討論在2D概率分布圖像中,如何計算某個區(qū)域的重心(Mass Center)的問題,重心可以通過以下公式來計算:

1.計算區(qū)域內(nèi)0階矩

for(int i=0;i<height;i++)

  for(int j=0;j<width;j++)

     M00+=I(i,j)

2.區(qū)域內(nèi)1階矩:

for(int i=0;i<height;i++)

  for(int j=0;j<width;j++)

  {

    M10+=i*I(i,j);

    M01+=j*I(i,j);

  }

3.則Mass Center為:

Xc=M10/M00; Yc=M01/M00

接下來,討論Mean Shift算法的具體步驟,Mean Shift算法可以分為以下4步:

1.選擇窗的大小和初始位置.

2.計算此時窗口內(nèi)的Mass Center.

3.調(diào)整窗口的中心到Mass Center.

4.重復(fù)2和3,直到窗口中心"會聚",即每次窗口移動的距離小于一定的閾值。

 

在OpenCV中,提供Mean Shift算法的函數(shù),函數(shù)的原型是:

int cvMeanShift(IplImage* imgprob,CvRect windowIn,

                    CvTermCriteria criteria,CvConnectedComp* out);

 

需要的參數(shù)為:

1.IplImage* imgprob:2D概率分布圖像,傳入;

2.CvRect windowIn:初始的窗口,傳入;

3.CvTermCriteria criteria:停止迭代的標準,傳入;

4.CvConnectedComp* out:查詢結(jié)果,傳出。

(注:構(gòu)造CvTermCriteria變量需要三個參數(shù),一個是類型,另一個是迭代的最大次數(shù),最后一個表示特定的閾值。例如可以這樣構(gòu)造criteria:criteria=cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,10,0.1)。)

 

返回的參數(shù):

1.int:迭代的次數(shù)。

 

實現(xiàn)代碼:暫時缺

3) CamShift算法
1.原理

在了解了MeanShift算法以后,我們將MeanShift算法擴展到連續(xù)圖像序列(一般都是指視頻圖像序列),這樣就形成了CamShift算法。CamShift算法的全稱是"Continuously Apaptive Mean-SHIFT",它的基本思想是視頻圖像的所有幀作MeanShift運算,并將上一幀的結(jié)果(即Search Window的中心和大?。┳鳛橄乱粠琈eanShift算法的Search Window的初始值,如此迭代下去,就可以實現(xiàn)對目標的跟蹤。整個算法的具體步驟分5步:

Step 1:將整個圖像設(shè)為搜尋區(qū)域。

Step 2:初始話Search Window的大小和位置。

Step 3:計算Search Window內(nèi)的彩色概率分布,此區(qū)域的大小比Search Window要稍微大一點。

Step 4:運行MeanShift。獲得Search Window新的位置和大小。

Step 5:在下一幀視頻圖像中,用Step 3獲得的值初始化Search Window的位置和大小。跳轉(zhuǎn)到Step 3繼續(xù)運行。

2.實現(xiàn)

在OpenCV中,有實現(xiàn)CamShift算法的函數(shù),此函數(shù)的原型是:

  cvCamShift(IplImage* imgprob, CvRect windowIn,

                CvTermCriteria criteria,

                CvConnectedComp* out, CvBox2D* box=0);

其中:

   imgprob:色彩概率分布圖像。

   windowIn:Search Window的初始值。

   Criteria:用來判斷搜尋是否停止的一個標準。

   out:保存運算結(jié)果,包括新的Search Window的位置和面積。

   box:包含被跟蹤物體的最小矩形。

 

說明:

1.在OpenCV 4.0 beta的目錄中,有CamShift的例子。遺憾的是這個例子目標的跟蹤是半自動的,即需要人手工選定一個目標。我正在努力嘗試全自動的目標跟蹤,希望可以和大家能在這方面與大家交流。

 

3月31日

OpenCV學(xué)習(xí)筆記(三)人臉檢測的代碼分析

OpenCV學(xué)習(xí)筆記(三)人臉檢測的代碼分析
一、預(yù)備知識:
1、動態(tài)內(nèi)存存儲及操作函數(shù)
CvMemStorage
typedef struct CvMemStorage
{
    struct CvMemBlock* bottom;/* first allocated block */
    struct CvMemBlock* top; /* the current memory block - top of the stack */
    struct CvMemStorage* parent; /* borrows new blocks from */
    int block_size; /* block size */
    int free_space; /* free space in the top block (in bytes) */
} CvMemStorage;
內(nèi)存存儲器是一個可用來存儲諸如序列,輪廓,圖形,子劃分等動態(tài)增長數(shù)據(jù)結(jié)構(gòu)的底層結(jié)構(gòu)。它是由一系列以同等大小的內(nèi)存塊構(gòu)成,呈列表型 ---bottom 域指的是列首,top 域指的是當前指向的塊但未必是列尾.在bottom和top之間所有的塊(包括bottom, 不包括top)被完全占據(jù)了空間;在 top和列尾之間所有的塊(包括塊尾,不包括top)則是空的;而top塊本身則被占據(jù)了部分空間 -- free_space 指的是top塊剩余的空字節(jié)數(shù)。新分配的內(nèi)存緩沖區(qū)(或顯示的通過 cvMemStorageAlloc 函數(shù)分配,或隱示的通過 cvSeqPush, cvGraphAddEdge等高級函數(shù)分配)總是起始于當前塊(即top塊)的剩余那部分,如果剩余那部分能滿足要求(夠分配的大?。?。分配后,free_space 就減少了新分配的那部分內(nèi)存大小,外加一些用來保存適當列型的附加大小。當top塊的剩余空間無法滿足被分配的塊(緩沖區(qū))大小時,top塊的下一個存儲塊被置為當前塊(新的top塊) --  free_space 被置為先前分配的整個塊的大小。如果已經(jīng)不存在空的存儲塊(即:top塊已是列尾),則必須再分配一個新的塊(或從parent那繼承,見 cvCreateChildMemStorage)并將該塊加到列尾上去。于是,存儲器(memory storage)就如同棧(Stack)那樣, bottom指向棧底,(top, free_space)對指向棧頂。棧頂可通過 cvSaveMemStoragePos保存,通過 cvRestoreMemStoragePos 恢復(fù)指向, 通過 cvClearStorage 重置。
CvMemBlock
內(nèi)存存儲塊結(jié)構(gòu)
typedef struct CvMemBlock
{
    struct CvMemBlock* prev;
    struct CvMemBlock* next;
} CvMemBlock;
CvMemBlock 代表一個單獨的內(nèi)存存儲塊結(jié)構(gòu)。 內(nèi)存存儲塊中的實際數(shù)據(jù)存儲在 header塊 之后(即:存在一個頭指針 head 指向的塊 header ,該塊不存儲數(shù)據(jù)),于是,內(nèi)存塊的第 i 個字節(jié)可以通過表達式 ((char*)(mem_block_ptr+1))[i] 獲得。然而,通常沒必要直接去獲得存儲結(jié)構(gòu)的域。
CvMemStoragePos
內(nèi)存存儲塊地址
typedef struct CvMemStoragePos
{
    CvMemBlock* top;
    int free_space;
} CvMemStoragePos;
該結(jié)構(gòu)(如以下所說)保存棧頂?shù)牡刂?,棧頂可以通過 cvSaveMemStoragePos 保存,也可以通過 cvRestoreMemStoragePos 恢復(fù)。
________________________________________
cvCreateMemStorage
創(chuàng)建內(nèi)存塊
CvMemStorage* cvCreateMemStorage( int block_size=0 );
 block_size:存儲塊的大小以字節(jié)表示。如果大小是 0 byte, 則將該塊設(shè)置成默認值  當前默認大小為64k.
函數(shù) cvCreateMemStorage 創(chuàng)建一內(nèi)存塊并返回指向塊首的指針。起初,存儲塊是空的。頭部(即:header)的所有域值都為 0,除了 block_size 外.
________________________________________
cvCreateChildMemStorage
創(chuàng)建子內(nèi)存塊
CvMemStorage* cvCreateChildMemStorage( CvMemStorage* parent );
parent    父內(nèi)存塊
函數(shù) cvCreateChildMemStorage 創(chuàng)建一類似于普通內(nèi)存塊的子內(nèi)存塊,除了內(nèi)存分配/釋放機制不同外。當一個子存儲塊需要一個新的塊加入時,它就試圖從parent 那得到這樣一個塊。如果 parent 中 還未被占據(jù)空間的那些塊中的第一個塊是可獲得的,就獲取第一個塊(依此類推),再將該塊從 parent  那里去除。如果不存在這樣的塊,則 parent 要么分配一個,要么從它自己 parent (即:parent 的 parent) 那借個過來。換句話說,完全有可能形成一個鏈或更為復(fù)雜的結(jié)構(gòu),其中的內(nèi)存存儲塊互為 child/ parent 關(guān)系(父子關(guān)系)。當子存儲結(jié)構(gòu)被釋放或清除,它就把所有的塊還給各自的 parent. 在其他方面,子存儲結(jié)構(gòu)同普通存儲結(jié)構(gòu)一樣。
子存儲結(jié)構(gòu)在下列情況中是非常有用的。想象一下,如果用戶需要處理存儲在某個塊中的動態(tài)數(shù)據(jù),再將處理的結(jié)果存放在該塊中。在使用了最簡單的方法處理后,臨時數(shù)據(jù)作為輸入和輸出數(shù)據(jù)被存放在了同一個存儲塊中,于是該存儲塊看上去就類似下面處理后的樣子: Dynamic data processing without using child storage. 結(jié)果,在存儲塊中,出現(xiàn)了垃圾(臨時數(shù)據(jù))。然而,如果在開始處理數(shù)據(jù)前就先建立一個子存儲塊,將臨時數(shù)據(jù)寫入子存儲塊中并在最后釋放子存儲塊,那么最終在 源/目的存儲塊 (source / destination storage) 中就不會出現(xiàn)垃圾, 于是該存儲塊看上去應(yīng)該是如下形式:Dynamic data processing using a child storage.
cvReleaseMemStorage
釋放內(nèi)存塊
void cvReleaseMemStorage( CvMemStorage** storage );
storage: 指向被釋放了的存儲塊的指針
函數(shù) cvReleaseMemStorage 釋放所有的存儲(內(nèi)存)塊 或者 將它們返回給各自的 parent(如果需要的話)。 接下來再釋放 header塊(即:釋放頭指針 head 指向的塊 = free(head))并清除指向該塊的指針(即:head = NULL)。在釋放作為 parent 的塊之前,先清除各自的 child 塊。
cvClearMemStorage
清空內(nèi)存存儲塊
void cvClearMemStorage( CvMemStorage* storage );
storage:存儲存儲塊
函數(shù) cvClearMemStorage 將存儲塊的 top 置到存儲塊的頭部(注:清空存儲塊中的存儲內(nèi)容)。該函數(shù)并不釋放內(nèi)存(僅清空內(nèi)存)。假使該內(nèi)存塊有一個父內(nèi)存塊(即:存在一內(nèi)存塊與其有父子關(guān)系),則函數(shù)就將所有的塊返回給其 parent.
cvMemStorageAlloc
在存儲塊中分配以內(nèi)存緩沖區(qū)
void* cvMemStorageAlloc( CvMemStorage* storage, size_t size );
storage:內(nèi)存塊.
size:緩沖區(qū)的大小.
函數(shù) cvMemStorageAlloc 在存儲塊中分配一內(nèi)存緩沖區(qū)。該緩沖區(qū)的大小不能超過內(nèi)存塊的大小,否則就會導(dǎo)致運行時錯誤。緩沖區(qū)的地址被調(diào)整為CV_STRUCT_ALIGN 字節(jié) (當前為 sizeof(double)).
cvMemStorageAllocString
在存儲塊中分配一文本字符串
typedef struct CvString
{
    int len;
    char* ptr;
}
CvString;
CvString cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, int len=-1 );
storage:存儲塊
ptr:字符串
len:字符串的長度(不計算'/0')。如果參數(shù)為負數(shù),函數(shù)就計算該字符串的長度。
函數(shù) cvMemStorageAlloString 在存儲塊中創(chuàng)建了一字符串的拷貝。它返回一結(jié)構(gòu),該結(jié)構(gòu)包含字符串的長度(該長度或通過用戶傳遞,或通過計算得到)和指向被拷貝了的字符串的指針。
cvSaveMemStoragePos
保存內(nèi)存塊的位置(地址)
void cvSaveMemStoragePos( const CvMemStorage* storage, CvMemStoragePos* pos );
storage:內(nèi)存塊.
pos:內(nèi)存塊頂部位置。
函數(shù) cvSaveMemStoragePos 將存儲塊的當前位置保存到參數(shù) pos 中。 函數(shù) cvRestoreMemStoragePos 可進一步獲取該位置(地址)。
cvRestoreMemStoragePos
恢復(fù)內(nèi)存存儲塊的位置
void cvRestoreMemStoragePos( CvMemStorage* storage, CvMemStoragePos* pos );
storage:內(nèi)存塊.
pos:新的存儲塊的位置
函數(shù) cvRestoreMemStoragePos 通過參數(shù) pos 恢復(fù)內(nèi)存塊的位置。該函數(shù)和函數(shù) cvClearMemStorage 是釋放被占用內(nèi)存塊的唯一方法。注意:沒有什么方法可去釋放存儲塊中被占用的部分內(nèi)存。
2、分類器結(jié)構(gòu)及操作函數(shù):
CvHaarFeature
#define CV_HAAR_FEATURE_MAX  3
typedef struct CvHaarFeature
{
    int  tilted; 
    struct
    {
        CvRect r;
        float weight;
} rect[CV_HAAR_FEATURE_MAX];
 
}
CvHaarFeature;
一個 harr 特征由 2-3 個具有相應(yīng)權(quán)重的矩形組成
titled :/* 0 means up-right feature, 1 means 45--rotated feature */
rect[CV_HAAR_FEATURE_MAX];  /* 2-3 rectangles with weights of opposite signs and       with absolute values inversely proportional to the areas of the rectangles. if rect[2].weight !=0, then  the feature consists of 3 rectangles, otherwise it consists of 2 */
CvHaarClassifier
typedef struct CvHaarClassifier
{
    int count; 
    CvHaarFeature* haar_feature;
    float* threshold;
    int* left;
    int* right;
    float* alpha;
}
CvHaarClassifier;
/* a single tree classifier (stump in the simplest case) that returns the response for the feature   at the particular image location (i.e. pixel sum over subrectangles of the window) and gives out a value depending on the responce */
int count;  /* number of nodes in the decision tree */
 /* these are "parallel" arrays. Every index i corresponds to a node of the decision tree (root has 0-th index).
left[i] - index of the left child (or negated index if the left child is a leaf)
right[i] - index of the right child (or negated index if the right child is a leaf)
threshold[i] - branch threshold. if feature responce is <= threshold, left branch                      is chosen, otherwise right branch is chosed.
alpha[i] - output value correponding to the leaf. */
CvHaarStageClassifier
typedef struct CvHaarStageClassifier
{
    int  count;  /* number of classifiers in the battery */
    float threshold; /* threshold for the boosted classifier */
    CvHaarClassifier* classifier; /* array of classifiers */
    /* these fields are used for organizing trees of stage classifiers,
       rather than just stright cascades */
    int next;
    int child;
    int parent;
}
CvHaarStageClassifier;

/* a boosted battery of classifiers(=stage classifier): the stage classifier returns 1 if the sum of the classifiers' responces is greater than threshold and 0 otherwise */
int  count;  /* number of classifiers in the battery */
float threshold; /* threshold for the boosted classifier */
CvHaarClassifier* classifier; /* array of classifiers */
/* these fields are used for organizing trees of stage classifiers, rather than just stright cascades */
CvHaarClassifierCascade
typedef struct CvHidHaarClassifierCascade CvHidHaarClassifierCascade;
typedef struct CvHaarClassifierCascade
{
    int  flags;
    int  count;
    CvSize orig_window_size;
    CvSize real_window_size;
    double scale;
    CvHaarStageClassifier* stage_classifier;
    CvHidHaarClassifierCascade* hid_cascade;
}
CvHaarClassifierCascade;

/* cascade or tree of stage classifiers */
int  flags; /* signature */
int  count; /* number of stages */
CvSize orig_window_size; /* original object size (the cascade is trained for) */
/* these two parameters are set by cvSetImagesForHaarClassifierCascade */
CvSize real_window_size; /* current object size */
double scale; /* current scale */
CvHaarStageClassifier* stage_classifier; /* array of stage classifiers */
CvHidHaarClassifierCascade* hid_cascade; /* hidden optimized representation of the cascade, created by cvSetImagesForHaarClassifierCascade */
所有的結(jié)構(gòu)都代表一個級聯(lián)boosted Haar分類器。級聯(lián)有下面的等級結(jié)構(gòu):
    Cascade:
        Stage1:
            Classifier11:
                Feature11
            Classifier12:
                Feature12
            ...
        Stage2:
            Classifier21:
                Feature21
            ...
        ...
整個等級可以手工構(gòu)建,也可以利用函數(shù)cvLoadHaarClassifierCascade從已有的磁盤文件或嵌入式基中導(dǎo)入。
特征檢測用到的函數(shù):
cvLoadHaarClassifierCascade
從文件中裝載訓(xùn)練好的級聯(lián)分類器或者從OpenCV中嵌入的分類器數(shù)據(jù)庫中導(dǎo)入
CvHaarClassifierCascade* cvLoadHaarClassifierCascade(
                         const char* directory,
                         CvSize orig_window_size );
directory :訓(xùn)練好的級聯(lián)分類器的路徑
orig_window_size:級聯(lián)分類器訓(xùn)練中采用的檢測目標的尺寸。因為這個信息沒有在級聯(lián)分類器中存儲,所有要單獨指出。
函數(shù) cvLoadHaarClassifierCascade 用于從文件中裝載訓(xùn)練好的利用海爾特征的級聯(lián)分類器,或者從OpenCV中嵌入的分類器數(shù)據(jù)庫中導(dǎo)入。分類器的訓(xùn)練可以應(yīng)用函數(shù)haartraining(詳細察看opencv/apps/haartraining)
函數(shù) 已經(jīng)過時了?,F(xiàn)在的目標檢測分類器通常存儲在  XML 或 YAML 文件中,而不是通過路徑導(dǎo)入。從文件中導(dǎo)入分類器,可以使用函數(shù) cvLoad 。
cvReleaseHaarClassifierCascade
釋放haar classifier cascade。
void cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** cascade );
cascade :雙指針類型指針指向要釋放的cascade. 指針由函數(shù)聲明。
函數(shù) cvReleaseHaarClassifierCascade 釋放cascade的動態(tài)內(nèi)存,其中cascade的動態(tài)內(nèi)存或者是手工創(chuàng)建,或者通過函數(shù) cvLoadHaarClassifierCascade 或 cvLoad分配。
cvHaarDetectObjects
檢測圖像中的目標
typedef struct CvAvgComp
{
CvRect rect; /* bounding rectangle for the object (average rectangle of a group) */
int neighbors; /* number of neighbor rectangles in the group */
}
CvAvgComp;
CvSeq* cvHaarDetectObjects( const CvArr* image,
CvHaarClassifierCascade* cascade,
                            CvMemStorage* storage,
                            double scale_factor=1.1,
                            int min_neighbors=3, int flags=0,
                            CvSize min_size=cvSize(0,0) );
image 被檢圖像
cascade harr 分類器級聯(lián)的內(nèi)部標識形式
storage 用來存儲檢測到的一序列候選目標矩形框的內(nèi)存區(qū)域。
scale_factor 在前后兩次相繼的掃描中,搜索窗口的比例系數(shù)。例如1.1指將搜索窗口依次擴大10%。
min_neighbors 構(gòu)成檢測目標的相鄰矩形的最小個數(shù)(缺?。?)。如果組成檢測目標的小矩形的個數(shù)和小于min_neighbors-1 都會被排除。如果min_neighbors 為 0, 則函數(shù)不做任何操作就返回所有的被檢候選矩形框,這種設(shè)定值一般用在用戶自定義對檢測結(jié)果的組合程序上。
flags 操作方式。當前唯一可以定義的操作方式是 CV_HAAR_DO_CANNY_PRUNING。如果被設(shè)定,函數(shù)利用Canny邊緣檢測器來排除一些邊緣很少或者很多的圖像區(qū)域,因為這樣的區(qū)域一般不含被檢目標。人臉檢測中通過設(shè)定閾值使用了這種方法,并因此提高了檢測速度。 
min_size 檢測窗口的最小尺寸。缺省的情況下被設(shè)為分類器訓(xùn)練時采用的樣本尺寸(人臉檢測中缺省大小是~20×20)。
函數(shù) cvHaarDetectObjects 使用針對某目標物體訓(xùn)練的級聯(lián)分類器在圖像中找到包含目標物體的矩形區(qū)域,并且將這些區(qū)域作為一序列的矩形框返回。函數(shù)以不同比例大小的掃描窗口對圖像進行幾次搜索(察看cvSetImagesForHaarClassifierCascade)。 每次都要對圖像中的這些重疊區(qū)域利用cvRunHaarClassifierCascade進行檢測。 有時候也會利用某些繼承(heuristics)技術(shù)以減少分析的候選區(qū)域,例如利用 Canny 裁減 (prunning)方法。 函數(shù)在處理和收集到候選的方框(全部通過級聯(lián)分類器各層的區(qū)域)之后,接著對這些區(qū)域進行組合并且返回一系列各個足夠大的組合中的平均矩形。調(diào)節(jié)程序中的缺省參數(shù)(scale_factor=1.1, min_neighbors=3, flags=0)用于對目標進行更精確同時也是耗時較長的進一步檢測。為了能對視頻圖像進行更快的實時檢測,參數(shù)設(shè)置通常是:scale_factor=1.2, min_neighbors=2, flags=CV_HAAR_DO_CANNY_PRUNING, min_size=<minimum possible face size> (例如, 對于視頻會議的圖像區(qū)域).
cvSetImagesForHaarClassifierCascade
為隱藏的cascade(hidden cascade)指定圖像
void cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascade,
                                          const CvArr* sum, const CvArr* sqsum,
                                          const CvArr* tilted_sum, double scale );
cascade 隱藏 Harr 分類器級聯(lián) (Hidden Haar classifier cascade), 由函數(shù) cvCreateHidHaarClassifierCascade生成
sum 32-比特,單通道圖像的積分圖像(Integral (sum) 單通道 image of 32-比特 integer format). 這幅圖像以及隨后的兩幅用于對快速特征的評價和亮度/對比度的歸一化。 它們都可以利用函數(shù) cvIntegral從8-比特或浮點數(shù) 單通道的輸入圖像中得到。
sqsum 單通道64比特圖像的平方和圖像
tilted_sum 單通道32比特整數(shù)格式的圖像的傾斜和(Tilted sum)
scale cascade的窗口比例. 如果 scale=1, 就只用原始窗口尺寸檢測 (只檢測同樣尺寸大小的目標物體) - 原始窗口尺寸在函數(shù)cvLoadHaarClassifierCascade中定義 (在 "<default_face_cascade>"中缺省為24x24), 如果scale=2, 使用的窗口是上面的兩倍 (在face cascade中缺省值是48x48 )。 這樣盡管可以將檢測速度提高四倍,但同時尺寸小于48x48的人臉將不能被檢測到。
函數(shù) cvSetImagesForHaarClassifierCascade 為hidden classifier cascade 指定圖像 and/or 窗口比例系數(shù)。 如果圖像指針為空,會繼續(xù)使用原來的圖像(i.e. NULLs 意味這"不改變圖像")。比例系數(shù)沒有 "protection" 值,但是原來的值可以通過函數(shù) cvGetHaarClassifierCascadeScale 重新得到并使用。這個函數(shù)用于對特定圖像中檢測特定目標尺寸的cascade分類器的設(shè)定。函數(shù)通過cvHaarDetectObjects進行內(nèi)部調(diào)用,但當需要在更低一層的函數(shù)cvRunHaarClassifierCascade中使用的時候,用戶也可以自行調(diào)用。
cvRunHaarClassifierCascade
在給定位置的圖像中運行 cascade of boosted classifier
int cvRunHaarClassifierCascade( CvHaarClassifierCascade* cascade,
                                CvPoint pt, int start_stage=0 );
cascade Haar 級聯(lián)分類器
pt 待檢測區(qū)域的左上角坐標。待檢測區(qū)域大小為原始窗口尺寸乘以當前設(shè)定的比例系數(shù)。當前窗口尺寸可以通過cvGetHaarClassifierCascadeWindowSize重新得到。
start_stage 級聯(lián)層的初始下標值(從0開始計數(shù))。函數(shù)假定前面所有每層的分類器都已通過。這個特征通過函數(shù)cvHaarDetectObjects內(nèi)部調(diào)用,用于更好的處理器高速緩沖存儲器。
函數(shù) cvRunHaarHaarClassifierCascade 用于對單幅圖片的檢測。在函數(shù)調(diào)用前首先利用 cvSetImagesForHaarClassifierCascade設(shè)定積分圖和合適的比例系數(shù) (=> 窗口尺寸)。當分析的矩形框全部通過級聯(lián)分類器每一層的時返回正值(這是一個候選目標),否則返回0或負值。
二、例程分析:
例子:利用級聯(lián)的Haar classifiers尋找檢測目標(e.g. faces).
#include "cv.h"
#include "highgui.h"
//讀取訓(xùn)練好的分類器。
CvHaarClassifierCascade* load_object_detector( const char* cascade_path )
{
    return (CvHaarClassifierCascade*)cvLoad( cascade_path );
}

void detect_and_draw_objects( IplImage* image,
                              CvHaarClassifierCascade* cascade,
                              int do_pyramids )
{
    IplImage* small_image = image;
    CvMemStorage* storage = cvCreateMemStorage(0); //創(chuàng)建動態(tài)內(nèi)存
    CvSeq* faces;
    int i, scale = 1;
    /* if the flag is specified, down-scale the 輸入圖像 to get a
       performance boost w/o loosing quality (perhaps) */
    if( do_pyramids )
    {
        small_image = cvCreateImage( cvSize(image->width/2,image->height/2), IPL_DEPTH_8U, 3 );
        cvPyrDown( image, small_image, CV_GAUSSIAN_5x5 );//函數(shù) cvPyrDown 使用 Gaussian 金字塔分解對輸入圖像向下采樣。首先它對輸入圖像用指定濾波器進行卷積,然后通過拒絕偶數(shù)的行與列來下采樣圖像。
        scale = 2;
    }
    /* use the fastest variant */
    faces = cvHaarDetectObjects( small_image, cascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING );
    /* draw all the rectangles */
    for( i = 0; i < faces->total; i++ )
    {
        /* extract the rectanlges only */
        CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i, 0 );
        cvRectangle( image, cvPoint(face_rect.x*scale,face_rect.y*scale),
                     cvPoint((face_rect.x+face_rect.width)*scale,
                             (face_rect.y+face_rect.height)*scale),
                     CV_RGB(255,0,0), 3 );
    }
    if( small_image != image )
        cvReleaseImage( &small_image );
    cvReleaseMemStorage( &storage );  //釋放動態(tài)內(nèi)存
}
/* takes image filename and cascade path from the command line */
int main( int argc, char** argv )
{
    IplImage* image;
    if( argc==3 && (image = cvLoadImage( argv[1], 1 )) != 0 )
    {
        CvHaarClassifierCascade* cascade = load_object_detector(argv[2]);
        detect_and_draw_objects( image, cascade, 1 );
        cvNamedWindow( "test", 0 );
        cvShowImage( "test", image );
        cvWaitKey(0);
        cvReleaseHaarClassifierCascade( &cascade );
        cvReleaseImage( &image );
    }
    return 0;
}
關(guān)鍵代碼很簡單,裝載分類器,對輸入圖像進行金字塔采樣,然后用cv的函數(shù)進行檢測目標,最后輸出檢測到的目標矩形。

OpenCV學(xué)習(xí)筆記(二)基于Haar-like特征的層疊推進分類器快速目標檢測


OpenCV學(xué)習(xí)筆記之二――基于Haar-like特征的層疊推進分類器快速目標檢測
一、簡介
目標檢測方法最初由Paul Viola [Viola01]提出,并由Rainer Lienhart [Lienhart02]對這一方法進行了改善。該方法的基本步驟為: 首先,利用樣本(大約幾百幅樣本圖片)的 harr 特征進行分類器訓(xùn)練,得到一個級聯(lián)的boosted分類器。
分類器中的"級聯(lián)"是指最終的分類器是由幾個簡單分類器級聯(lián)組成。在圖像檢測中,被檢窗口依次通過每一級分類器, 這樣在前面幾層的檢測中大部分的候選區(qū)域就被排除了,全部通過每一級分類器檢測的區(qū)域即為目標區(qū)域。
分類器訓(xùn)練完以后,就可以應(yīng)用于輸入圖像中的感興趣區(qū)域(與訓(xùn)練樣本相同的尺寸)的檢測。檢測到目標區(qū)域(汽車或人臉)分類器輸出為1,否則輸出為0。為了檢測整副圖像,可以在圖像中移動搜索窗口,檢測每一個位置來確定可能的目標。 為了搜索不同大小的目標物體,分類器被設(shè)計為可以進行尺寸改變,這樣比改變待檢圖像的尺寸大小更為有效。所以,為了在圖像中檢測未知大小的目標物體,掃描程序通常需要用不同比例大小的搜索窗口對圖片進行幾次掃描。
目前支持這種分類器的boosting技術(shù)有四種: Discrete Adaboost, Real Adaboost, Gentle Adaboost and Logitboost。
"boosted" 即指級聯(lián)分類器的每一層都可以從中選取一個boosting算法(權(quán)重投票),并利用基礎(chǔ)分類器的自我訓(xùn)練得到。
根據(jù)上面的分析,目標檢測分為三個步驟:
1、 樣本的創(chuàng)建
2、 訓(xùn)練分類器
3、 利用訓(xùn)練好的分類器進行目標檢測。
二、樣本創(chuàng)建
訓(xùn)練樣本分為正例樣本和反例樣本,其中正例樣本是指待檢目標樣本(例如人臉或汽車等),反例樣本指其它任意圖片,所有的樣本圖片都被歸一化為同樣的尺寸大小(例如,20x20)。
負樣本
負樣本可以來自于任意的圖片,但這些圖片不能包含目標特征。負樣本由背景描述文件來描述。背景描述文件是一個文本文件,每一行包含了一個負樣本圖片的文件名(基于描述文件的相對路徑)。該文件必須手工創(chuàng)建。
e.g: 負樣本描述文件的一個例子:
假定目錄結(jié)構(gòu)如下:
/img
img1.jpg
img2.jpg
bg.txt
則背景描述文件bg.txt的內(nèi)容為:
img/img1.jpg
img/img2.jpg
正樣本
正樣本由程序craatesample程序來創(chuàng)建。該程序的源代碼由OpenCV給出,并且在bin目錄下包含了這個可執(zhí)行的程序。
正樣本可以由單個的目標圖片或者一系列的事先標記好的圖片來創(chuàng)建。
Createsamples程序的命令行參數(shù):
命令行參數(shù):
-vec <vec_file_name>
訓(xùn)練好的正樣本的輸出文件名。
-img<image_file_name>
源目標圖片(例如:一個公司圖標)
-bg<background_file_name>
背景描述文件。
-num<number_of_samples>
要產(chǎn)生的正樣本的數(shù)量,和正樣本圖片數(shù)目相同。
-bgcolor<background_color>
背景色(假定當前圖片為灰度圖)。背景色制定了透明色。對于壓縮圖片,顏色方差量由bgthresh參數(shù)來指定。則在bgcolor-bgthresh和bgcolor+bgthresh中間的像素被認為是透明的。
-bgthresh<background_color_threshold>
-inv
如果指定,顏色會反色
-randinv
如果指定,顏色會任意反色
-maxidev<max_intensity_deviation>
背景色最大的偏離度。
-maxangel<max_x_rotation_angle>
-maxangle<max_y_rotation_angle>,
-maxzangle<max_x_rotation_angle>
最大旋轉(zhuǎn)角度,以弧度為單位。
-show
如果指定,每個樣本會被顯示出來,按下"esc"會關(guān)閉這一開關(guān),即不顯示樣本圖片,而創(chuàng)建過程繼續(xù)。這是個有用的debug選項。
-w<sample_width>
輸出樣本的寬度(以像素為單位)
-h(huán)《sample_height》
輸出樣本的高度,以像素為單位。
注:正樣本也可以從一個預(yù)先標記好的圖像集合中獲取。這個集合由一個文本文件來描述,類似于背景描述文件。每一個文本行對應(yīng)一個圖片。每行的第一個元素是圖片文件名,第二個元素是對象實體的個數(shù)。后面緊跟著的是與之匹配的矩形框(x, y, 寬度,高度)。
下面是一個創(chuàng)建樣本的例子:
假定我們要進行人臉的檢測,有5個正樣本圖片文件img1.bmp,…img5.bmp;有2個背景圖片文件:bg1.bmp,bg2.bmp,文件目錄結(jié)構(gòu)如下:
positive
  img1.bmp
  ……
  Img5.bmp
negative
  bg1.bmp
  bg2.bmp
info.dat
bg.txt
正樣本描述文件info.dat的內(nèi)容如下:
Positive/imag1.bmp 1 0 0 24 28
……
Positive/imag5.bmp 1 0 0 24 28
圖片img1.bmp包含了單個目標對象實體,矩形為(0,0,24,28)。
注意:要從圖片集中創(chuàng)建正樣本,要用-info參數(shù)而不是用-img參數(shù)。
-info <collect_file_name>
標記特征的圖片集合的描述文件。
背景(負樣本)描述文件的內(nèi)容如下:
nagative/bg1.bmp
nagative/bg2.bmp
我們用一個批處理文件run.bat來進行正樣本的創(chuàng)建:該文件的內(nèi)容如下:
cd  e:/face/bin
CreateSamples   -vec e:/face/a.vec
 -info e:/face/info.dat
-bg e:/face/bg.txt
-num 5
-show
-w 24
 -h 28
其中e:/face/bin目錄包含了createsamples可執(zhí)行程序,生成的正樣本文件a.vec在e:/face目錄下。
三、訓(xùn)練分類器
樣本創(chuàng)建之后,接下來要訓(xùn)練分類器,這個過程是由haartraining程序來實現(xiàn)的。該程序源碼由OpenCV自帶,且可執(zhí)行程序在OpenCV安裝目錄的bin目錄下。
Haartraining的命令行參數(shù)如下:
-data<dir_name>
存放訓(xùn)練好的分類器的路徑名。
-vec<vec_file_name>
正樣本文件名(由trainingssamples程序或者由其他的方法創(chuàng)建的)
-bg<background_file_name>
背景描述文件。
-npos<number_of_positive_samples>,
-nneg<number_of_negative_samples>
用來訓(xùn)練每一個分類器階段的正/負樣本。合理的值是:nPos = 7000;nNeg = 3000
-nstages<number_of_stages>
訓(xùn)練的階段數(shù)。
-nsplits<number_of_splits>
決定用于階段分類器的弱分類器。如果1,則一個簡單的stump classifier被使用。如果是2或者更多,則帶有number_of_splits個內(nèi)部節(jié)點的CART分類器被使用。
-mem<memory_in_MB>
預(yù)先計算的以MB為單位的可用內(nèi)存。內(nèi)存越大則訓(xùn)練的速度越快。
-sym(default)
-nonsym
指定訓(xùn)練的目標對象是否垂直對稱。垂直對稱提高目標的訓(xùn)練速度。例如,正面部是垂直對稱的。
-minhitrate《min_hit_rate》
每個階段分類器需要的最小的命中率。總的命中率為min_hit_rate的number_of_stages次方。
-maxfalsealarm<max_false_alarm_rate>
沒有階段分類器的最大錯誤報警率??偟腻e誤警告率為max_false_alarm_rate的number_of_stages次方。
-weighttrimming<weight_trimming>
指定是否使用權(quán)修正和使用多大的權(quán)修正。一個基本的選擇是0.9
-eqw
-mode<basic(default)|core|all>
選擇用來訓(xùn)練的haar特征集的種類。basic僅僅使用垂直特征。all使用垂直和45度角旋轉(zhuǎn)特征。
-w《sample_width》
-h(huán)《sample_height》
訓(xùn)練樣本的尺寸,(以像素為單位)。必須和訓(xùn)練樣本創(chuàng)建的尺寸相同。
一個訓(xùn)練分類器的例子:
同上例,分類器訓(xùn)練的過程用一個批處理文件run2.bat來完成:
cd e:/face/bin
haartraining -data e:/face/data
-vec e:/face/a.vec
-bg e:/face/bg.txt
-npos 5
-nneg 2
 -w 24
 -h 28
訓(xùn)練結(jié)束后,會在目錄data下生成一些子目錄,即為訓(xùn)練好的分類器。
注:OpenCv的某些版本可以將這些目錄中的分類器直接轉(zhuǎn)換成xml文件。但在實際的操作中,haartraining程序卻好像永遠不會停止,而且沒有生成xml文件,后來在OpenCV的yahoo論壇上找到一個haarconv的程序,才將分類器轉(zhuǎn)換為xml文件,其中的原因尚待研究。
四、目標檢測
OpenCV的cvHaarDetectObjects()函數(shù)(在haarFaceDetect演示程序中示例)被用來做偵測。關(guān)于該檢測的詳細分析,將在下面的筆記中詳細描述。

 
3月29日

一個合格的程序員該做的事情


2006.03.15  來自:CSDN 選自Mailbomb 的blog  
 

  程序員每天該做的事

1、總結(jié)自己一天任務(wù)的完成情況

最好的方式是寫工作日志,把自己今天完成了什么事情,遇見了什么問題都記錄下來,日后翻看好處多多

2、考慮自己明天應(yīng)該做的主要工作

把明天要做的事情列出來,并按照優(yōu)先級排列,第二天應(yīng)該把自己效率最高的時間分配給最重要的工作

3、考慮自己一天工作中失誤的地方,并想出避免下一次再犯的方法

出錯不要緊,最重要的是不要重復(fù)犯相同的錯誤,那是愚蠢

4、考慮自己一天工作完成的質(zhì)量和效率能否還能提高

一天只提高1%,365天你的效率就能提高多少倍你知道嗎? (1+0.01)^365 = 37 倍

5、看一個有用的新聞網(wǎng)站或讀一張有用的報紙,了解業(yè)界動態(tài)

閉門造車是不行的,了解一下別人都在做什么,對自己能帶來很多啟示

6、記住一位同事的名字及其特點

你認識公司的所有同事嗎?你了解他們嗎?

7、清理自己的代碼

今天完成的代碼,把中間的調(diào)試信息,測試代碼清理掉,按照編碼風(fēng)格整理好,注釋都寫好了嗎?

8、清理自己的桌面

當日事當日畢,保持清潔干勁的桌面才能讓你工作時不分心,程序員特別要把電腦的桌面清理干凈

程序員每月該做的事

1、至少和一個同事一起吃飯或喝茶
不光了解自己工作伙伴的工作,還要了解他們的生活

2、自我考核一次
相對正式地考核自己一下,你對得起這個月的工資嗎?

3、對你的同事考核一次
你的同事表現(xiàn)怎么樣?哪些人值得學(xué)習(xí),哪些人需要幫助?

3、制定下月的計劃,確定下月的工作重點

4、總結(jié)自己工作質(zhì)量改進狀況
自己的質(zhì)量提高了多少?

5、有針對性地對一項工作指標做深入地分析并得出改進的方案
可以是對自己的,也可以是對公司的,一定要深入地分析后拿出自己的觀點來。要想在老板面前說得上話,做的成事,工作上功夫要做足。

6、與老板溝通一次
最好是面對面地溝通,好好表現(xiàn)一下自己,虛心聽取老板的意見,更重要的是要了解老板當前關(guān)心的重點

程序員每年該做的事

1、年終總結(jié)
每個公司都會做的事情,但你真正認真地總結(jié)過自己嗎?

2、兌現(xiàn)給自己、給家人的承諾
給老婆、兒子的新年禮物買了沒有?給自己的呢?

3、下年度工作規(guī)劃
好好想想自己明年的發(fā)展目標,爭取升職/加薪、跳槽還是自己出來干?

4、掌握一項新技術(shù)
至少是一項,作為程序員一年要是一項新技術(shù)都學(xué)不到手,那就一定會被淘汰。
掌握可不是看本書就行的,要真正懂得應(yīng)用,最好你能夠?qū)懸黄坛贪l(fā)表到你的blog

5、推出一種新產(chǎn)品
可以是一個真正的產(chǎn)品,也可以只是一個類庫,只要是你創(chuàng)造的東西就行,讓別人使用它,也為世界作點貢獻。當然如果真的很有價值,收點注冊費也是應(yīng)該的

6、與父母團聚一次
?;丶铱纯?,常回家看看

 

3月28日

OpenCV學(xué)習(xí)筆記(一)概述和系統(tǒng)配置


OpenCV學(xué)習(xí)筆記(一)概述和系統(tǒng)配置

一、概述
OpenCV是英特爾公司于1999年在俄羅斯設(shè)立的軟件開發(fā)中心“Software Development Center”開發(fā)的。該公司一直致力于基于個人電腦的計算機視覺應(yīng)用的開發(fā),可以實時追蹤的視覺用戶接口技術(shù)的普及為目標。初步擬定應(yīng)用于Human-Computer Interaction(HCI,人機互動)、物體確定、面孔識別、表情識別,移動物體追蹤、自主運動(Ego-motion)、移動機器人等領(lǐng)域。因此,“OpenCV 2.1將提供給玩具制造商及機器人制造商等從事計算機視覺相關(guān)技術(shù)的各類企業(yè)/團體”
    OpenCV將以公開源碼的方式提供,也就是接受方有權(quán)在修改之后另行向第三方提供。源代碼(C語言)中包括有庫(Library)的所有功能。詳細情況刊登在OpenCV的WWW站點上。
英特爾公司解釋說,“速度更高的微處理器、廉價的數(shù)碼相機以及USB 2等技術(shù)使高速視頻捕獲(Video Capture)成為可能,因此,基于普通個人電腦的實時計算機視覺將有望實現(xiàn)”。
OpenCV的最新版本為beta5。
二、OpenCV組成部分
目前OpenCV包含下面幾個部分:
    cvcore:一些基本函數(shù)(各種數(shù)據(jù)類型的基本運算等)
    cv:    圖像處理和計算機視覺功能(圖像處理,結(jié)構(gòu)分析,運動分析,物體跟蹤,模式識別,攝像機定標)
    cvaux:一些實驗性的函數(shù)(view morphing,三維跟蹤,pca,hmm)
    highgui 用戶交互部分(GUI,圖像視頻I/O,系統(tǒng)調(diào)用函數(shù))
    另外還有cvcam,不過linux版本已經(jīng)拋棄。windows版本中將directX支持加入highgui后,cvcam將被徹底去掉。
三、OpenCV特點
OpenCV是Intel公司開發(fā)的圖像處理和計算機視覺函數(shù)庫,它有以下特點:
1) 開放C源碼
2) 基于Intel處理器指令集開發(fā)的優(yōu)化代碼
3) 統(tǒng)一的結(jié)構(gòu)和功能定義
4) 強大的圖像和矩陣運算能力
5) 方便靈活的用戶接口
6)同時支持MS-WINDOWS、LINUX平臺
四、下載OpenCV
    http://www./projects/opencvlibrary
五、參考資料
    =》源代碼及文檔下載:SOURCEFORGE.NET
http:///projects/opencvlibrary/
    =》INTEL的OPENCV主頁:
http://www.intel.com/research/mrl/research/opencv/
    =》YAHOO OPENCV 的郵件列表:
http://groups.yahoo.com/group/OpenCV/
    =》CMU(卡耐基-梅隆大學(xué))的計算機視覺主頁:
http://www-2.cs./afs/cs/project/cil/ftp/html/vision.html
    =》OPENCV 更為詳細的介紹
http://www.//incoming/sourcecode/opencv/chinese_docs/index.htm
    =》OPENCV 的常用問題與解答
http://www.//incoming/sourcecode/opencv/chinese_docs/faq.htm
    =》OPENCV 的安裝指南
http://www.//incoming/sourcecode/opencv/chinese_docs/install
    =》更多的最新資料,請訪問
http://blog.csdn.net/hunnishhttp://rocee.
六、創(chuàng)建一個 DeveloperStudio 項目來開始 OpenCV
1. 在 Developer Studio 中創(chuàng)建新的應(yīng)用程序:
選擇菜單 "File"->"New..."->"Projects" . 選擇 "Win32 Application" 或 "Win32 console application" - 后者是更簡單的方法。
鍵入項目名稱,并且選擇存儲位置
可以為項目創(chuàng)建一個單獨的 workspace ("Create new workspace") , 也可以將新的項目加入到當前的 workspace 中 ("Add to current workspace").
單擊 "next" 
選擇 "An empty project", 點擊 "Finish", "OK".
經(jīng)過以上步驟,Developer Studio 會創(chuàng)建一個項目目錄 (缺省情況下,目錄名就是項目名), .dsp 文件以及.dsw,.ncb ... ,如果你創(chuàng)建自己的workspace.
2添加文件到 project 中:
選擇菜單"File"->"New..."->"Files" .
選擇"C++ Source File", 鍵入文件名,點擊"OK"
增加 OpenCV 相關(guān)的 頭文件目錄 #include :
        #include "cv.h"
        /* #inlcude "cvaux.h" // experimental stuff (if need) */
        #include "highgui.h"
     
或者你可以拷貝部分已有的文件 (如:opencv/samples/c/morphology.c) 到項目目錄中,打開它,并且加入到項目中 (右鍵點擊編輯器的視圖 -> "Insert File into Project" -> ).
3配置項目:
選擇菜單"Project"->"Settings..."以激活項目配置對話框 .
在左邊選擇你的項目.
調(diào)節(jié)設(shè)置,對 Release 和 Debug 配置都有效:
選擇 "Settings For:"->"All Configurations"
選擇 "C/C++" tab -> "Preprocessor" category -> "Additional Include Directories:". 加入用逗號分隔的相對路徑 (對文件 .dsp 而言) 或絕對路徑
 d:/opencv/cxcore/include,d:/opencv/cv/include,d:/opencv/otherlibs/highgui, d:/opencv/cvaux/include(optionally,)
選擇 "Link" tab -> "Input" category -> "Additional library path:".
加入輸入庫所在的路徑 (cxcore[d].lib cv[d].lib hihghui[d].lib cvaux[d].lib)
d:/opencv/lib
調(diào)節(jié) "Debug" 配置:
選擇 "Settings For:"->"Win32 Debug".
選擇 "Link" tab -> "General" category -> "Object/library modules". 加入空格分隔的 cvd.lib,cxcored.lib highguid.lib,cvauxd.lib (optionally)
可以改變輸出文件的名稱和位置。如想把產(chǎn)生的 .exe 文件放置于項目目錄而不是Debug/ 子目錄下,可在 "Link" tab -> "General" category -> "Output file name:" 中鍵入 ./d.exe 
調(diào)節(jié) "Release" 配置
選擇 "Settings For:"->"Win32 Release".
選擇 "Link" tab -> "General" category -> "Object/library modules". 加入空格分隔的cv.lib cxcore.lib highgui.lib cvaux.lib (optionally)
4增加從屬性項目到 workspace 中:
選擇菜單: "Project" -> "Insert project into workspace".
選擇 opencv/cv/make/cv.dsp.
同樣步驟對 opencv/cvaux/make/cvaux.dsp, opencv/otherlibs/highgui/highgui.dsp.
設(shè)置從屬性:
選擇菜單: "Project" -> "Dependencies..."
對 "cv" 選擇 "cxcore",
對 "cvaux" 選擇 "cv", "cxcore",
對 "highgui" 選擇 "cxcore",
對你的項目,選擇所有的: "cxcore", "cv", "cvaux", "highgui".
從屬性配置保證了在源代碼被改變的情況下,自動重新編譯 opencv 庫.
5就這么多??梢跃幾g并且運行一切了。
七、庫設(shè)置:
   靜態(tài)庫設(shè)置:
   Opencv程序需要靜態(tài)庫設(shè)置,其release版本的靜態(tài)庫在系統(tǒng)的lib目錄下,其debug版本的靜態(tài)庫需要重新全編譯所有的程序。
    動態(tài)庫設(shè)置:
   OPenCV啟動時需要一些動態(tài)庫的支持,這些動態(tài)庫必須放在系統(tǒng)目錄下或者當前目錄下。
    Cv097.dll,cvaux097.dll,cvcam097.dll,cxcore097.dll highguid097.dll,libguide40.dll

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多