第七章 学习OpenCV(11)
运行结果如下图:
尝试识别手势。实现例13功能,但是利用EMD匹配策略,本例仅对Compare_Gesture_Hist()函数做了适当修改,具体代码如下:
void Compare_Gesture_Hist(IplImage *sobel1, IplImage *sobel2, IplImage *test, IplImage** canny, IplImage* hist_img)
{
//建立直方图
CvHistogram *hist_model1, *hist_model2, *hist_test;
int bins = 20;
int hist_size[] = { bins }; //对应维数包含bins个数的数组
float range[] = { -CV_PI / 2, CV_PI / 2 };
float* ranges[] = { range }; //划分范围数对, ****均匀bin,range只要最大最小边界
//创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
hist_model1 = cvCreateHist(1, hist_size, CV_HIST_ARRAY, ranges, 1);
hist_model2 = cvCreateHist(1, hist_size, CV_HIST_ARRAY, ranges, 1);
hist_test = cvCreateHist(1, hist_size, CV_HIST_ARRAY, ranges, 1);
IplImage *planes1[] = { sobel1 };
IplImage *planes2[] = { sobel2 };
IplImage *planes3[] = { test };
cvCalcHist(planes1, hist_model1, 0, canny[0]); //计算直方图(图像,直方图结构,不累加,掩码)
cvCalcHist(planes2, hist_model2, 0, canny[1]); //计算直方图(图像,直方图结构,不累加,掩码)
cvCalcHist(planes3, hist_test, 0, canny[2]); //计算直方图(图像,直方图结构,不累加,掩码)
cvNormalizeHist(hist_model1, 1.0); //直方图归一化
cvNormalizeHist(hist_model2, 1.0); //直方图归一化
cvNormalizeHist(hist_test, 1.0); //直方图归一化
//EMD
CvMat *sig1, *sig2, *sig_test;
int numrows = bins;
sig1 = cvCreateMat(numrows, 2, CV_32FC1); //numrows行 2列 矩阵
sig2 = cvCreateMat(numrows, 2, CV_32FC1);
sig_test = cvCreateMat(numrows, 2, CV_32FC1);
for (int h = 0; h < bins; h++)
{
float bin_val = 0.0;
bin_val = cvQueryHistValue_1D(hist_model1, h);
//h:行数 s_bins:总列数(行长度)s:列数 h*s_bins+s 当前bin对应的sig行数
cvSet2D(sig1, h, 0, cvScalar(bin_val));
cvSet2D(sig1, h, 1, cvScalar(h));
bin_val = cvQueryHistValue_1D(hist_model2, h);
//h:行数 s_bins:总列数(行长度)s:列数 h*s_bins+s 当前bin对应的sig行数
cvSet2D(sig2, h, 0, cvScalar(bin_val));
cvSet2D(sig2, h, 1, cvScalar(h));
bin_val = cvQueryHistValue_1D(hist_test, h);
//h:行数 s_bins:总列数(行长度)s:列数 h*s_bins+s 当前bin对应的sig行数
cvSet2D(sig_test, h, 0, cvScalar(bin_val));
cvSet2D(sig_test, h, 1, cvScalar(h));
}
float emd1 = cvCalcEMD2(sig1, sig_test, CV_DIST_L2);
float emd2 = cvCalcEMD2(sig2, sig_test, CV_DIST_L2);
printf("EMD距离1:%f; \n", emd1);
printf("EMD距离2:%f; \n", emd2);
if ((emd1 <= 1) && (emd2 >= 4))
{
cvDrawRect(hist_img, cvPoint(100, 100), cvPoint(200, 200), cvScalar(255, 0, 0), CV_FILLED, 8);
}
if ((emd1 >= 1.7) && (emd2 <= 3.4))
{
cvDrawRect(hist_img, cvPoint(100, 100), cvPoint(200, 200), cvScalar(0, 0, 255), CV_FILLED, 8);
}
printf("\n");
cout << endl;
////比较直方图
//for (int j = 0; j < 4; j++)
//{
// double value1 = cvCompareHist(hist_test, hist_model1, j); //相关方式比较
// double value2 = cvCompareHist(hist_test, hist_model2, j); //相关方式比较
// //if (j == 0)
// //{
// // std::printf(" Hist_test & Hist_model1 ,CV_COMP_CORREL: %lf;\n", value1);
// // std::printf(" Hist_test & Hist_model2 ,CV_COMP_CORREL: %lf;\n", value2);
// //}
// if (j == 1)
// {
// std::printf(" Hist_test & Hist_model1 ,CV_COMP_CHISQR: %lf;\n", value1);
// std::printf(" Hist_test & Hist_model2 ,CV_COMP_CHISQR: %lf;\n", value2);
// if ((value1 <= 0.25) && (value2 >= 0.55))
// {
// cvDrawRect(hist_img, cvPoint(100, 100), cvPoint(200, 200), cvScalar(255, 0, 0), CV_FILLED, 8);
// }
// if ((value1 >= 0.45) && (value2 <= 0.4))
// {
// cvDrawRect(hist_img, cvPoint(100, 100), cvPoint(200, 200), cvScalar(0, 0, 255), CV_FILLED, 8);
// }
// }
// //if (j == 2)
// //{
// // std::printf(" Hist_test & Hist_model1 ,CV_COMP_INTERSECT: %lf;\n", value1);
// // std::printf(" Hist_test & Hist_model2 ,CV_COMP_INTERSECT: %lf;\n", value2);
// //}
// //if (j == 3)
// //{
// // std::printf(" Hist_test & Hist_model1 ,CV_CCOMP_BHATTACHARYYA: %lf;\n", value1);
// // std::printf(" Hist_test & Hist_model2 ,CV_CCOMP_BHATTACHARYYA: %lf;\n", value2);
// //}
// std::printf("\n");
//}
运行结果如下图:
f inline '函数表达式','变量1','变量2',... y f 实参列表 实参列表应与定义时的变量顺序保持一致 例: 方式三:内联函数和匿名函数 内联函数 调用方式 f inline 'x^2+y','x','y' y f 2,3 根据实际情况,定义函数时可能需要使用数组运算 例: 方式三:内联函数和匿名函数 匿名函数 + 函数句柄 f @ 变量列表 表达式 y f 实参列表 调用方式 f @ x,y x^2 + y。 f=inline('函数表达式','变量1','变量2',...) y=f(实参列表) 实参列表应与定义时的变量顺序保持一致 例: 方式三:内联函数和匿名函数 内联函数 调用方式 f=inline('x^2+y','x','y') y=f(2,3) 根据实际情况,定义函数时可能需要使用数组运算 例: 方式三:内联函数和匿名函数 匿名函数 + 函数句柄 f = @ (变量列表) 表达式 y=f(实参列表) 调用方式 f = @(x,y) x^2 + y。当按下选中键时,先判断是否已经选中了要移动的区域,如果已经选中了要移动的区域就调用move()函数完成由要移动的区域到要移动到的区域的移动过程,接着调用repaint()函数刷新屏幕,然后将已选择标记置成false,继续调用win()函数判断是否完成了任务,否则如果还没有选定要移动的区域则再判断当前选中区域是否为空白,如果不是空白就将选中标记置成true,然后刷新屏幕.这里介绍一个技巧,在开发程序遇到复杂的逻辑的时候,可以构造一格打印函数来将所关心的数据结构打印出来以利调试,这里我们就构造一个printgrid()函数,这个函数纯粹是为了调试之用,效果这得不错.至此我们完成了编码前的全部工作。
说的真好