【练习7.2】直方图归一化cvNormalizeHist、匹配cvCompareHist及各种匹配方法
题目要求 |
程序代码 |
结果图片 |
要言妙道 |
使用三种光照条件下的手的图像,利用cvCalcHist来获得直方图
a、获得图像HSV三维直方图
b、匹配三种光照条件下的直方图,使用所有的匹配方法,测试bin的值为2, 8, 16, 32, 256的情况
1 // OpenCVExerciseTesting.cpp : 定义控制台应用程序的入口点。 2 // 3 //D:\\Work\\Work_Programming\\Source\\Image\\lena.jpg 4 5 #include "stdafx.h" 6 #include <cv.h> 7 #include <highgui.h> 8 #include <iostream> 9 10 #include <opencv2/legacy/legacy.hpp> 11 //#pragma comment(lib, "opencv_legacy2411.lib") 12 13 using namespace cv; 14 using namespace std; 15 16 //函数声明-->--->-->--->-->--->-->--->// 17 18 19 //<--<--<--<--<--<--<--<--<--函数声明// 20 21 int _tmain(int argc, _TCHAR* argv[]) 22 { 23 char * soutceFile = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第7章\\hand_sample3.jpg"; 24 IplImage * image_Source = cvLoadImage(soutceFile, CV_LOAD_IMAGE_UNCHANGED); 25 assert(image_Source); 26 27 IplImage *image_HSV = cvCreateImage(cvGetSize(image_Source), IPL_DEPTH_8U, 3); 28 cvCvtColor(image_Source, image_HSV, CV_BGR2HSV); 29 IplImage * image_h = cvCreateImage(cvGetSize(image_HSV), IPL_DEPTH_8U, 1); 30 IplImage * image_s = cvCreateImage(cvGetSize(image_HSV), IPL_DEPTH_8U, 1); 31 IplImage * image_v = cvCreateImage(cvGetSize(image_HSV), IPL_DEPTH_8U, 1); 32 cvCvtPixToPlane(image_HSV, image_h, image_s, image_v, NULL); 33 34 CvHistogram * histgram_3D; 35 36 const int dims = 3; 37 int bin_2 = 2; 38 int bin_16 = 16; 39 int bin_256 = 256; 40 41 int hist_sizes[dims] = { bin_2, bin_2, bin_2 }; 42 int hist_type = CV_HIST_ARRAY; 43 float h_range[] = { 0, 180 }; 44 float s_range[] = { 0, 255 }; 45 float v_range[] = { 0, 255 }; 46 float *hist_ranges[dims] = { h_range, s_range, v_range }; 47 48 histgram_3D = cvCreateHist(dims, hist_sizes, hist_type, hist_ranges, 1); 49 50 IplImage *allImagePlane[dims] = { image_h, image_s, image_v }; 51 52 cvCalcHist(allImagePlane, histgram_3D); 53 54 system("pause"); 55 56 cvWaitKey(); 57 cvReleaseImage(&image_Source); 58 cvDestroyAllWindows(); 59 60 return 0; 61 } 62 63 void DrawHistogram(IplImage * image_hist, const CvHistogram * histogram) 64 { 65 66 67 } 68 69 70
1 // OpenCVExerciseTesting.cpp : 定义控制台应用程序的入口点。 2 // 3 //D:\\Work\\Work_Programming\\Source\\Image\\lena.jpg 4 5 #include "stdafx.h" 6 #include <cv.h> 7 #include <highgui.h> 8 #include <iostream> 9 10 #include <opencv2/legacy/legacy.hpp> 11 //#pragma comment(lib, "opencv_legacy2411.lib") 12 13 using namespace cv; 14 using namespace std; 15 16 //函数声明-->--->-->--->-->--->-->--->// 17 18 CvHistogram * Create3DHistogram(const int dims, int bins); 19 void CreateSingleImage(IplImage * image_Src, IplImage **image_r, IplImage **image_g, IplImage **image_b); 20 void DrawHistogram(IplImage ** image_hist, const CvHistogram * histogram, int scaleValue); 21 22 //<--<--<--<--<--<--<--<--<--函数声明// 23 24 int _tmain(int argc, _TCHAR* argv[]) 25 { 26 const char * soutceFile_InDoor = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第7章\\hand_sample3.jpg"; 27 const char * soutceFile_OutDoor = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第7章\\hand_sample2.jpg"; 28 const char * soutceFile_OutDoorSun = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第7章\\hand_sample1.jpg"; 29 30 IplImage * image_Source_Indoor = cvLoadImage(soutceFile_InDoor, CV_LOAD_IMAGE_UNCHANGED); 31 assert(image_Source_Indoor); 32 IplImage * image_Source_Outdoor = cvLoadImage(soutceFile_OutDoor, CV_LOAD_IMAGE_UNCHANGED); 33 assert(image_Source_Outdoor); 34 IplImage * image_Source_OutdoorSun = cvLoadImage(soutceFile_OutDoorSun, CV_LOAD_IMAGE_UNCHANGED); 35 assert(image_Source_OutdoorSun); 36 37 IplImage * image_r; 38 IplImage * image_g; 39 IplImage * image_b; 40 41 CvHistogram * histgram_3D_InDoor; 42 CvHistogram * histgram_3D_OutDoor; 43 CvHistogram * histgram_3D_OutDoorSun; 44 45 double histCompare; 46 47 const int dims = 3; 48 int bin_N[] = { 2, 8, 16, 32, 256 }; 49 size_t length_bin_N = sizeof(bin_N) / sizeof(bin_N[0]); 50 51 for (size_t i = 0; i < length_bin_N; ++i) 52 { 53 //室内直方图 54 CreateSingleImage(image_Source_Indoor, &image_r, &image_g, &image_b); 55 cvCvtPixToPlane(image_Source_Indoor, image_r, image_g, image_b, NULL); 56 IplImage *allImagePlane[3] = { image_r, image_g, image_b }; 57 58 histgram_3D_InDoor = Create3DHistogram(dims, bin_N[i]); 59 cvCalcHist(allImagePlane, histgram_3D_InDoor); 60 cvNormalizeHist(histgram_3D_InDoor, 1.0); 61 62 cvReleaseImage(&image_r); 63 cvReleaseImage(&image_g); 64 cvReleaseImage(&image_b); 65 66 //室外直方图 67 CreateSingleImage(image_Source_Outdoor, &image_r, &image_g, &image_b); 68 cvCvtPixToPlane(image_Source_Outdoor, image_r, image_g, image_b, NULL); 69 allImagePlane[0] = image_r; 70 allImagePlane[1] = image_g; 71 allImagePlane[2] = image_b; 72 73 histgram_3D_OutDoor = Create3DHistogram(dims, bin_N[i]); 74 cvCalcHist(allImagePlane, histgram_3D_OutDoor); 75 cvNormalizeHist(histgram_3D_OutDoor, 1.0); 76 77 cvReleaseImage(&image_r); 78 cvReleaseImage(&image_g); 79 cvReleaseImage(&image_b); 80 81 //室外阳光直方图 82 CreateSingleImage(image_Source_OutdoorSun, &image_r, &image_g, &image_b); 83 cvCvtPixToPlane(image_Source_OutdoorSun, image_r, image_g, image_b, NULL); 84 allImagePlane[0] = image_r; 85 allImagePlane[1] = image_g; 86 allImagePlane[2] = image_b; 87 88 histgram_3D_OutDoorSun = Create3DHistogram(dims, bin_N[i]); 89 cvCalcHist(allImagePlane, histgram_3D_OutDoorSun); 90 cvNormalizeHist(histgram_3D_OutDoorSun, 1.0); 91 92 cvReleaseImage(&image_r); 93 cvReleaseImage(&image_g); 94 cvReleaseImage(&image_b); 95 96 if (bin_N[i] == 8) 97 { 98 cvNamedWindow("bin等于8时的室内直方图", CV_WINDOW_AUTOSIZE); 99 cvNamedWindow("bin等于8时的室外直方图", CV_WINDOW_AUTOSIZE); 100 cvNamedWindow("bin等于8时的室外阳光直方图", CV_WINDOW_AUTOSIZE); 101 102 IplImage *histImage_Indoor; 103 IplImage *histImage_Outdoor; 104 IplImage *histImage_OutdoorSun; 105 106 DrawHistogram(&histImage_Indoor, histgram_3D_InDoor, 1000); 107 cvShowImage("bin等于8时的室内直方图", histImage_Indoor); 108 cvReleaseImage(&histImage_Indoor); 109 110 DrawHistogram(&histImage_Outdoor, histgram_3D_OutDoor, 1000); 111 cvShowImage("bin等于8时的室外直方图", histImage_Outdoor); 112 cvReleaseImage(&histImage_Outdoor); 113 114 DrawHistogram(&histImage_OutdoorSun, histgram_3D_OutDoorSun, 1000); 115 cvShowImage("bin等于8时的室外阳光直方图", histImage_OutdoorSun); 116 cvReleaseImage(&histImage_OutdoorSun); 117 } 118 119 //输出匹配结果 120 cout << "-- bin为"<<bin_N[i]<<" -- " << endl; 121 cout << "===============================================================================" << endl; 122 123 cout << "CV_COMP_CORREL方法:数值越大越匹配,范围:完全匹配:1,完全不匹配:-1,无关联:0" << endl; 124 cout << "-------------------------------------------------------------------------------" << endl; 125 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_CORREL); 126 cout << "InDoor与OutDoor :" << histCompare << endl; 127 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_CORREL); 128 cout << "InDoor与OutDoorSun :" << histCompare << endl; 129 histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_CORREL); 130 cout << "OutDoor与OutDoorSun:" << histCompare << endl; 131 132 cout << endl; 133 134 cout << "CV_COMP_CHISQR方法:数值越小越匹配,范围:0到无穷大" << endl; 135 cout << "-------------------------------------------------------------------------------" << endl; 136 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_CHISQR); 137 cout << "InDoor与OutDoor :" << histCompare << endl; 138 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_CHISQR); 139 cout << "InDoor与OutDoorSun :" << histCompare << endl; 140 histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_CHISQR); 141 cout << "OutDoor与OutDoorSun:" << histCompare << endl; 142 143 cout << endl; 144 145 cout << "CV_COMP_INTERSECT方法:低分代表坏的匹配,范围:如果两个直方图都被归一化到1,则0~1" << endl; 146 cout << "-------------------------------------------------------------------------------" << endl; 147 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_INTERSECT); 148 cout << "InDoor与OutDoor :" << histCompare << endl; 149 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_INTERSECT); 150 cout << "InDoor与OutDoorSun :" << histCompare << endl; 151 histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_INTERSECT); 152 cout << "OutDoor与OutDoorSun:" << histCompare << endl; 153 154 cout << endl; 155 156 cout << "CV_COMP_BHATTACHARYYA方法:低分代表好的匹配,范围:0~1" << endl; 157 cout << "-------------------------------------------------------------------------------" << endl; 158 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_BHATTACHARYYA); 159 cout << "InDoor与OutDoor :" << histCompare << endl; 160 histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_BHATTACHARYYA); 161 cout << "InDoor与OutDoorSun :" << histCompare << endl; 162 histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_BHATTACHARYYA); 163 cout << "OutDoor与OutDoorSun:" << histCompare << endl; 164 165 cout << endl; 166 cout << endl; 167 cout << endl; 168 169 cvReleaseHist(&histgram_3D_InDoor); 170 cvReleaseHist(&histgram_3D_OutDoor); 171 cvReleaseHist(&histgram_3D_OutDoorSun); 172 } 173 174 //system("pause"); 175 176 cvWaitKey(); 177 cvReleaseImage(&image_Source_Indoor); 178 cvReleaseImage(&image_Source_Outdoor); 179 cvReleaseImage(&image_Source_OutdoorSun); 180 181 cvDestroyAllWindows(); 182 183 return 0; 184 } 185 186 CvHistogram * Create3DHistogram(const int dims, int bins) 187 { 188 int hist_sizes[] = { bins, bins, bins }; 189 int hist_type = CV_HIST_ARRAY; 190 float r_range[] = { 0, 255 }; 191 float g_range[] = { 0, 255 }; 192 float b_range[] = { 0, 255 }; 193 float *hist_ranges[] = { r_range, g_range, b_range }; 194 195 return cvCreateHist(dims, hist_sizes, hist_type, hist_ranges, 1); 196 } 197 198 void CreateSingleImage(IplImage * image_Src, IplImage **image_r, IplImage **image_g, IplImage **image_b) 199 { 200 IplImage * image_temp = cvCreateImage(cvGetSize(image_Src), IPL_DEPTH_8U, 1); 201 //image_r = &image_temp; 202 //如果用上面这行这种方式,编译通过,但运行崩溃,本函数结束后image_r便被释放, 203 //因为image_temp只是一个指针变量,占用四个字节的局部变量,对它取地址即&image_temp只是这个局部指针变量的地址,函数结束后自然释放掉 204 //但是,将使用下面这行:将image_temp指针变量所保存的地址赋值给“*image_r”,这个地址是从cvCreateImagere中turn出来的,自然不会随函数结束而释放 205 *image_r = image_temp; 206 207 *image_g = cvCloneImage(image_temp); 208 *image_b = cvCloneImage(image_temp); 209 cvZero(*image_r); 210 cvZero(*image_g); 211 cvZero(*image_b); 212 } 213 214 //目前只实现绘制三维直方图 215 void DrawHistogram(IplImage ** image_hist, const CvHistogram * histogram,int scaleValue) 216 { 217 //直方图:横坐标表示各个bin,纵坐标表示各个bin归一化后的值 218 int hist_dims = histogram->mat.dims; 219 220 int bin_size1, bin_size2, bin_size3; 221 222 if (hist_dims == 3) 223 { 224 bin_size1 = histogram->mat.dim[0].size; 225 bin_size2 = histogram->mat.dim[1].size; 226 bin_size3 = histogram->mat.dim[2].size; 227 } 228 else 229 { 230 return; 231 } 232 233 int bin_count = bin_size1*bin_size2*bin_size3; 234 float max_temp; 235 cvGetMinMaxHistValue(histogram, NULL, &max_temp); 236 int max_value = (int)(max_temp*scaleValue) + 1; 237 CvSize hist_imageSize = cvSize(bin_count, max_value); 238 *image_hist = cvCreateImage(hist_imageSize, IPL_DEPTH_8U, 1); 239 (*image_hist)->origin = 1; 240 cvZero(*image_hist); 241 242 int x; 243 int value; 244 245 for (int r = 0; r < bin_size1; ++r) 246 { 247 for (int g = 0; g < bin_size2; ++g) 248 { 249 for (int b = 0; b < bin_size3; ++b) 250 { 251 x = r*(bin_size1*bin_size2) + g*bin_size2 + b; 252 value = (int)(cvQueryHistValue_3D(histogram, r, g, b)*scaleValue); 253 /* if (value == 0) 254 { 255 value = 10; 256 }*/ 257 cvRectangle(*image_hist, cvPoint(x, 0), cvPoint(x, value), cvScalar(255)); 258 } 259 } 260 } 261 }
①二维直方图bin的多少是各维度bin的乘积,以h和s二维直方图来说,如果h的bin的个数为30,s的bin的个数为32,则,二维直方图的bin的个数为30×32,访问的时候要使用cvQueryHistValue_2D
②由于需要匹配“各种光线”下的直方图,所以,代码中将BGR图像转成了HSV图像 cvCvtColor(image_Source, image_HSV, CV_BGR2HSV);
③书中Example 7-1统计的是HS直方图,即色调和饱和度,没有统计亮度,针对三种光线下的手的图像,如果统计亮度即V的直方图,三种环境下的匹配结果值肯定不匹配度很高。这点在230页有专门的讲解,为什么只选取HS两维而避开V维,是这个道理。
④为什么说是手的肤色直方图,从图7-6的表述来看,所谓肤色直方图即肤色所在图片的直方图,在英文版更看得出这个意思。
⑤一般情况下在对比直方图之前,都应该自行进行归一化操作,因为如果不归一化,像直方图相交等概念就没有任何意义(即使运行)
‖==========钟于原创 乐于分享 宁静致远 毋忆典藏==========‖