题目要求 |
程序代码 |
结果图片 |
要言妙道 |
收集三种光照条件下的手的直方图,计算它们之间的EMD距离
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 void CreateSignatureFromHistogram(const CvHistogram * histgogram, CvMat ** signature); 22 23 //<--<--<--<--<--<--<--<--<--函数声明// 24 25 int _tmain(int argc, _TCHAR* argv[]) 26 { 27 const char * soutceFile_InDoor = "D:\Work\Work_Programming\Source\Image\OpenCVExerciseImage\第7章\hand_sample3.jpg"; 28 const char * soutceFile_OutDoor = "D:\Work\Work_Programming\Source\Image\OpenCVExerciseImage\第7章\hand_sample2.jpg"; 29 const char * soutceFile_OutDoorSun = "D:\Work\Work_Programming\Source\Image\OpenCVExerciseImage\第7章\hand_sample1.jpg"; 30 31 IplImage * image_Source_Indoor = cvLoadImage(soutceFile_InDoor, CV_LOAD_IMAGE_UNCHANGED); 32 assert(image_Source_Indoor); 33 IplImage * image_Source_Outdoor = cvLoadImage(soutceFile_OutDoor, CV_LOAD_IMAGE_UNCHANGED); 34 assert(image_Source_Outdoor); 35 IplImage * image_Source_OutdoorSun = cvLoadImage(soutceFile_OutDoorSun, CV_LOAD_IMAGE_UNCHANGED); 36 assert(image_Source_OutdoorSun); 37 38 IplImage * image_r; 39 IplImage * image_g; 40 IplImage * image_b; 41 42 CvHistogram * histgram_3D_InDoor; 43 CvHistogram * histgram_3D_OutDoor; 44 CvHistogram * histgram_3D_OutDoorSun; 45 CvMat * sig_Indoor, *sig_Outdoor, *sig_OutdoorSun; 46 47 double emd_result; 48 49 const int dims = 3; 50 int bin_N[] = { 8 }; //本题只计算bin值为8的情况 51 size_t length_bin_N = sizeof(bin_N) / sizeof(bin_N[0]); 52 53 for (size_t i = 0; i < length_bin_N; ++i) 54 { 55 //室内直方图 56 CreateSingleImage(image_Source_Indoor, &image_r, &image_g, &image_b); 57 cvCvtPixToPlane(image_Source_Indoor, image_r, image_g, image_b, NULL); 58 IplImage *allImagePlane[3] = { image_r, image_g, image_b }; 59 60 histgram_3D_InDoor = Create3DHistogram(dims, bin_N[i]); 61 cvCalcHist(allImagePlane, histgram_3D_InDoor); 62 //cvNormalizeHist(histgram_3D_InDoor, 1.0); 63 CreateSignatureFromHistogram(histgram_3D_InDoor, &sig_Indoor); 64 65 cvReleaseImage(&image_r); 66 cvReleaseImage(&image_g); 67 cvReleaseImage(&image_b); 68 69 //室外直方图 70 CreateSingleImage(image_Source_Outdoor, &image_r, &image_g, &image_b); 71 cvCvtPixToPlane(image_Source_Outdoor, image_r, image_g, image_b, NULL); 72 allImagePlane[0] = image_r; 73 allImagePlane[1] = image_g; 74 allImagePlane[2] = image_b; 75 76 histgram_3D_OutDoor = Create3DHistogram(dims, bin_N[i]); 77 cvCalcHist(allImagePlane, histgram_3D_OutDoor); 78 //cvNormalizeHist(histgram_3D_OutDoor, 1.0); 79 CreateSignatureFromHistogram(histgram_3D_OutDoor, &sig_Outdoor); 80 81 cvReleaseImage(&image_r); 82 cvReleaseImage(&image_g); 83 cvReleaseImage(&image_b); 84 85 //室外阳光直方图 86 CreateSingleImage(image_Source_OutdoorSun, &image_r, &image_g, &image_b); 87 cvCvtPixToPlane(image_Source_OutdoorSun, image_r, image_g, image_b, NULL); 88 allImagePlane[0] = image_r; 89 allImagePlane[1] = image_g; 90 allImagePlane[2] = image_b; 91 92 histgram_3D_OutDoorSun = Create3DHistogram(dims, bin_N[i]); 93 cvCalcHist(allImagePlane, histgram_3D_OutDoorSun); 94 //cvNormalizeHist(histgram_3D_OutDoorSun, 1.0); 95 CreateSignatureFromHistogram(histgram_3D_OutDoorSun, &sig_OutdoorSun); 96 97 cvReleaseImage(&image_r); 98 cvReleaseImage(&image_g); 99 cvReleaseImage(&image_b); 100 101 cout << "=============直方图EMD距离:0表示最精确的匹配=============" << endl << endl; 102 cout << "-------------Indoor和Outdoor直方图EMD距离-------------" << endl; 103 emd_result = cvCalcEMD2(sig_Indoor, sig_Outdoor, CV_DIST_L2); 104 cout << emd_result << endl; 105 106 cout << "-------------Indoor和OutdoorSun直方图EMD距离-------------" << endl; 107 emd_result = cvCalcEMD2(sig_Indoor, sig_OutdoorSun, CV_DIST_L2); 108 cout << emd_result << endl; 109 110 cout << "-------------Outdoor和OutdoorSun直方图EMD距离-------------" << endl; 111 emd_result = cvCalcEMD2(sig_OutdoorSun, sig_Outdoor, CV_DIST_L2); 112 cout << emd_result << endl; 113 emd_result = cvCalcEMD2(sig_Outdoor, sig_OutdoorSun, CV_DIST_L2); 114 cout << emd_result<<" 可见cvCalcEMD2参数signature顺序无关,不影响结果" << endl; 115 116 cvReleaseMat(&sig_Indoor); 117 cvReleaseMat(&sig_Outdoor); 118 cvReleaseMat(&sig_OutdoorSun); 119 120 cvReleaseHist(&histgram_3D_InDoor); 121 cvReleaseHist(&histgram_3D_OutDoor); 122 cvReleaseHist(&histgram_3D_OutDoorSun); 123 } 124 125 system("pause"); 126 127 cvWaitKey(); 128 cvReleaseImage(&image_Source_Indoor); 129 cvReleaseImage(&image_Source_Outdoor); 130 cvReleaseImage(&image_Source_OutdoorSun); 131 132 cvDestroyAllWindows(); 133 134 return 0; 135 } 136 137 CvHistogram * Create3DHistogram(const int dims, int bins) 138 { 139 int hist_sizes[] = { bins, bins, bins }; 140 int hist_type = CV_HIST_ARRAY; 141 float r_range[] = { 0, 255 }; 142 float g_range[] = { 0, 255 }; 143 float b_range[] = { 0, 255 }; 144 float *hist_ranges[] = { r_range, g_range, b_range }; 145 146 return cvCreateHist(dims, hist_sizes, hist_type, hist_ranges, 1); 147 } 148 149 void CreateSingleImage(IplImage * image_Src, IplImage **image_r, IplImage **image_g, IplImage **image_b) 150 { 151 IplImage * image_temp = cvCreateImage(cvGetSize(image_Src), IPL_DEPTH_8U, 1); 152 //image_r = &image_temp; 153 //如果用上面这行这种方式,编译通过,但运行崩溃,本函数结束后image_r便被释放, 154 //因为image_temp只是一个指针变量,占用四个字节的局部变量,对它取地址即&image_temp只是这个局部指针变量的地址,函数结束后自然释放掉 155 //但是,将使用下面这行:将image_temp指针变量所保存的地址赋值给“*image_r”,这个地址是从cvCreateImagere中turn出来的,自然不会随函数结束而释放 156 *image_r = image_temp; 157 158 *image_g = cvCloneImage(image_temp); 159 *image_b = cvCloneImage(image_temp); 160 cvZero(*image_r); 161 cvZero(*image_g); 162 cvZero(*image_b); 163 } 164 165 //目前只实现绘制三维直方图 166 void DrawHistogram(IplImage ** image_hist, const CvHistogram * histogram,int scaleValue) 167 { 168 //直方图:横坐标表示各个bin,纵坐标表示各个bin归一化后的值 169 int hist_dims = histogram->mat.dims; 170 171 int bin_size1, bin_size2, bin_size3; 172 173 if (hist_dims == 3) 174 { 175 bin_size1 = histogram->mat.dim[0].size; 176 bin_size2 = histogram->mat.dim[1].size; 177 bin_size3 = histogram->mat.dim[2].size; 178 } 179 else 180 { 181 return; 182 } 183 184 int bin_count = bin_size1*bin_size2*bin_size3; 185 float max_temp; 186 cvGetMinMaxHistValue(histogram, NULL, &max_temp); 187 int max_value = (int)(max_temp*scaleValue) + 1; 188 CvSize hist_imageSize = cvSize(bin_count, max_value); 189 *image_hist = cvCreateImage(hist_imageSize, IPL_DEPTH_8U, 1); 190 (*image_hist)->origin = 1; 191 cvZero(*image_hist); 192 193 int x; 194 int value; 195 196 for (int r = 0; r < bin_size1; ++r) 197 { 198 for (int g = 0; g < bin_size2; ++g) 199 { 200 for (int b = 0; b < bin_size3; ++b) 201 { 202 x = r*(bin_size1*bin_size2) + g*bin_size2 + b; 203 value = (int)(cvQueryHistValue_3D(histogram, r, g, b)*scaleValue); 204 /* if (value == 0) 205 { 206 value = 10; 207 }*/ 208 cvRectangle(*image_hist, cvPoint(x, 0), cvPoint(x, value), cvScalar(255)); 209 } 210 } 211 } 212 } 213 214 void CreateSignatureFromHistogram(const CvHistogram * histgogram,CvMat ** signature) 215 { 216 int hist_dims = histgogram->mat.dims; 217 218 int bin_size1, bin_size2, bin_size3; 219 220 //只实现从三维直方图的创建 221 if (hist_dims == 3) 222 { 223 bin_size1 = histgogram->mat.dim[0].size; 224 bin_size2 = histgogram->mat.dim[1].size; 225 bin_size3 = histgogram->mat.dim[2].size; 226 } 227 else 228 { 229 return; 230 } 231 232 int numrows = bin_size1*bin_size2*bin_size3; 233 *signature = cvCreateMat(numrows, 4, CV_32FC1); 234 235 float bin_value; 236 int idx; 237 for (int r = 0; r < bin_size1; ++r) 238 { 239 for (int g = 0; g < bin_size2; ++g) 240 { 241 for (int b = 0; b < bin_size3; ++b) 242 { 243 idx = r*(bin_size1*bin_size2) + g*bin_size2 + b; 244 bin_value = cvQueryHistValue_3D(histgogram, r, g, b); 245 cvSet2D(*signature, idx, 0, cvScalar(bin_value)); 246 cvSet2D(*signature, idx, 1, cvScalar(r)); 247 cvSet2D(*signature, idx, 2, cvScalar(g)); 248 cvSet2D(*signature, idx, 3, cvScalar(b)); 249 } 250 } 251 } 252 }
①EMD用来度量两个分布之间的相似性