前一篇講了使用cvCalcBackProject 尋找 手 的膚色地方
這一篇講 在一幅圖像中尋找 某個特定的小物體
步驟:
1.使用一幅只包含小物體的圖片(圖片大小和物體一樣大即可, 不需要向上一篇同樣大),計算其二維直方圖 (HSV空間中的 h(亮度)和 s (飽和度) 二維直方圖 (還可以和圖像的梯度和(或)梯度角度結(jié)合起來,查找紋理相似 和(或) 顏色相似
2.輸入一幅待搜索的圖片, 轉(zhuǎn)化為HSV空間 ,只取h 和 s 分量
3. 設(shè)置搜索塊大小和物體大小相同(即和第1步中圖片大小相同) ,使用cvCalcBackProjectPatch反向塊投影 和圖片result
4.在result中取最大值所在位置,即可得到物體在輸入圖片中的位置了。 (或者設(shè)定一個閾值)
示例程序如下:
#include <iostream> #include <cv.h> #include <highgui.h> #include <cxcore.h>
using namespace std;
void GetHSV(const IplImage *image,IplImage **h,IplImage **s,IplImage **v);
int main() { IplImage *src = cvLoadImage("f:\\images\\bluecup.jpg"); IplImage *h_src = NULL ,*s_src = NULL; GetHSV(src,&h_src,&s_src,NULL); IplImage *images[] = {h_src,s_src}; CvHistogram *hist_src; {//計算二維直方圖 int dims = 2; int size[] = {30,32}; // 這個地方不要取的太大! //當(dāng)取為size[] = {180,256}時E7200CPU會運(yùn)行長達(dá)10幾分鐘的! float range_h[] = {0,180} //再用cvCvtColor轉(zhuǎn)換時h已經(jīng)歸一化到180了 ,range_s[] = {0,256}; float *ranges[] = {range_h,range_s}; hist_src = cvCreateHist(dims,size,CV_HIST_ARRAY,ranges); cvCalcHist(images,hist_src); cvNormalizeHist(hist_src,1); }
IplImage *dst = cvLoadImage("f:\\images\\adrian1.jpg"); IplImage *h_dst = NULL,*s_dst = NULL; GetHSV(dst,&h_dst,&s_dst,NULL); images[0] = h_dst ,images[1] = s_dst;
CvSize patch_size = cvSize(src->width,src->height); IplImage *result = cvCreateImage(cvSize(h_dst->width - patch_size.width +1,h_dst->height - patch_size.height +1) ,IPL_DEPTH_32F,1);//塊搜索時處理邊緣是直接舍去,故result的大小比dst小path_size大小 //32F類型,取值為0~1最亮為1,可直接顯示 //CV_COMP_CORREL相關(guān)度,1時最匹配,0時最不匹配 cvCalcBackProjectPatch(images,result,patch_size,hist_src,CV_COMP_CORREL,1); cvShowImage("result",result); //找出最大值位置,可得到此位置即為杯子所在位置 CvPoint max_location; cvMinMaxLoc(result,NULL,NULL,NULL,&max_location,NULL); //加上邊緣,得到在原始圖像中的實(shí)際位置 max_location.x += cvRound(patch_size.width/2); max_location.y += cvRound(patch_size.height/2); //在dst圖像中用紅色小圓點(diǎn)標(biāo)出位置 cvCircle(dst,max_location,3,CV_RGB(255,0,0),-1);
cvShowImage("dst",dst); cvWaitKey();
cvReleaseImage(&src); cvReleaseImage(&dst); cvReleaseImage(&h_src); cvReleaseImage(&h_dst); cvReleaseImage(&s_dst); cvReleaseImage(&s_src); cvReleaseHist(&hist_src); cvReleaseImage(&result); cvDestroyAllWindows(); }
void GetHSV(const IplImage *image , IplImage **h,IplImage **s,IplImage **v) { IplImage *hsv = cvCreateImage(cvGetSize(image),8,3); cvCvtColor(image,hsv,CV_BGR2HSV); if((h != NULL) && (*h == NULL)) *h = cvCreateImage(cvGetSize(image),8,1); if((s != NULL) && (*s == NULL)) *s = cvCreateImage(cvGetSize(image),8,1); if((v != NULL) && (*v == NULL)) *v = cvCreateImage(cvGetSize(image),8,1);
cvSplit(hsv,*h,(s == NULL)?NULL:*s,(v==NULL)?NULL:*v,NULL); cvReleaseImage(&hsv); }
第一步物體圖片src剛好包含要搜索的物體:
第二步輸入圖像即待搜索的圖像如下:
在我的E7200 CPU , 1GB內(nèi)存 上大概運(yùn)行了20秒內(nèi)吧,將size內(nèi)的數(shù)應(yīng)該可以再適當(dāng)改的更小此,速度就會提高更多了
結(jié)果如下(見圖中紅色小圓圈標(biāo)記出來):
若待搜索的圖片里有多個此物體,也是可以通過這種方法找出來的
產(chǎn)于cvCalcBackProjectPatch的大概意義 ,
按我的理解的話,應(yīng)該是通過塊窗口搜索圖像,比較窗口中對應(yīng)像素的二維直方圖與給定直方圖的差異,若完全相同,那當(dāng)然就越匹配
對于不同的相關(guān)度方法,越匹配,其值由相關(guān)度方法而定,
如本程序使用的是
即越相似,則值越接近1. 反之則趨于0
其實(shí)使用的時候還可以將圖像的梯度考慮進(jìn)去求解,
如求出圖像的梯度+色彩的多維直方圖,這樣就能得搜索到一定紋理特征和顏色特征的物體了。
ps:此方法搜索是通過統(tǒng)計學(xué)特征相似度!和模板匹配法是不同的,各有個的用途
如果只是為了檢測某個不變的實(shí)物,,還不如使用模板匹配函數(shù),更快
轉(zhuǎn)載請注明出處,若有錯誤,請大家指正.
|