在手势识别时,可利用模板手势与当前手势的边缘梯度方向直方图进行匹配来识别当前手势, 故而就需要构建图像的边缘梯度方向直方图.
梯度为:dx*dx+dy*dy开方.
梯度方向则为:dy/dx(注意dx为0的情况处理).
1 #include "stdafx.h" 2 #include "cv.h" 3 #include "highgui.h" 4 5 int main() 6 { 7 IplImage* src=cvLoadImage("C:/Users/shark/Desktop/fruits.jpg",0); 8 CvSize size=cvGetSize(src); 9 //边缘检测 10 IplImage* canny=cvCreateImage(size,8,1); 11 IplImage* canny32=cvCreateImage(size,IPL_DEPTH_32F,1); 12 cvCanny(src,canny,60,180,3); 13 cvConvert(canny,canny32); 14 //梯度计算 15 IplImage* dx=cvCreateImage(size,IPL_DEPTH_16S,1); 16 IplImage* dy=cvCreateImage(size,IPL_DEPTH_16S,1); 17 cvSobel(src,dx,1,0,3); 18 cvSobel(src,dy,0,1,3); 19 IplImage* dx32=cvCreateImage(size,IPL_DEPTH_32F,1); 20 IplImage* dy32=cvCreateImage(size,IPL_DEPTH_32F,1); 21 cvConvert(dx,dx32); 22 cvConvert(dy,dy32); 23 IplImage* gradient=cvCreateImage(size,IPL_DEPTH_32F,1); //梯度图像 24 IplImage* gradient_dir=cvCreateImage(size,IPL_DEPTH_32F,1); //梯度方向图像 25 cvDiv(dx32,dy32,gradient_dir); 26 27 cvMul(dx32,dx32,dx32,1.0); 28 cvMul(dy32,dy32,dy32,1.0); 29 cvAdd(dx32,dy32,gradient,0); 30 for(int i=0;i<size.height;i++) 31 for(int j=0;j<size.width;j++) 32 { 33 gradient->imageData[i*gradient->widthStep+j]=cvSqrt((float) 34 35 gradient->imageData[i*gradient->widthStep+j]); 36 } 37 float theta; 38 for(int i=0;i<size.height;i++) 39 for(int j=0;j<size.width;j++) 40 { 41 if(cvGetReal2D(canny32,i,j)!=0 && cvGetReal2D(dx32,i,j)!=0) 42 43 //dy/dx中dx!=0 44 { 45 theta=cvGetReal2D(gradient_dir,i,j); 46 theta=atan(theta); 47 cvSetReal2D(gradient_dir,i,j,theta); 48 } 49 else 50 { 51 cvSetReal2D(gradient_dir,i,j,0); 52 } 53 } 54 int bins=20; float max=0; 55 float range[]={-CV_PI/2,CV_PI/2}; 56 float* ranges[]={range}; 57 CvHistogram* hist=cvCreateHist(1,&bins,CV_HIST_ARRAY,ranges,1); 58 IplImage* hist_img=cvCreateImage(cvSize(320,200),8,3); 59 cvZero(hist_img); 60 cvCalcHist(&gradient_dir,hist,0,canny); //只计算边界直方图 61 cvGetMinMaxHistValue(hist,0,&max,0,0); 62 cvConvertScale(hist->bins,hist->bins,max?255./max:0.,0); //缩放bin到[0,255] 63 double bin_width=(double)hist_img->width/bins*3/4; 64 for(int i=0;i<bins;i++) 65 { 66 double val=cvGetReal1D(hist->bins,i)*hist_img->height/255; 67 CvPoint p0=cvPoint(30+i*bin_width,hist_img->height); 68 CvPoint p1=cvPoint(30+(i+1)*bin_width,hist_img->height-val); 69 cvRectangle(hist_img,p0,p1,cvScalar(0,255),1,8,0); 70 } 71 cvNamedWindow("hist_img"); 72 cvShowImage("hist_img",hist_img); 73 cvWaitKey(); 74 75 76 }
原图:
梯度方向直方图: