├── Boosted_tree ├── BT_architecture.h └── main.cpp ├── Random_forest ├── RF_architecture.h └── main.cpp ├── README.MD └── dataGen └── main.cpp /Boosted_tree/BT_architecture.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mks0601/Fast-Feature-Pyramids-for-Object-Detection/HEAD/Boosted_tree/BT_architecture.h -------------------------------------------------------------------------------- /Random_forest/RF_architecture.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mks0601/Fast-Feature-Pyramids-for-Object-Detection/HEAD/Random_forest/RF_architecture.h -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Fast Feature pyramid for object detection 2 | http://vision.cornell.edu/se3/wp-content/uploads/2014/09/DollarPAMI14pyramids_0.pdf 3 | 4 | Implemented with C++ using Random forest, boosted decision tree 5 | 6 | Yields similar performance with paper(Random forest: 14fps, Boosted Trees: 18fps) 7 | 8 | ACF feature used 9 | 10 | ## Result(green: GT, blue: detected pedestrian) 11 | ![acf](https://cloud.githubusercontent.com/assets/13601723/15353065/21459712-1d22-11e6-89b0-e46d5676dafe.png) 12 | 13 | ![3](https://cloud.githubusercontent.com/assets/13601723/15353119/55c302f4-1d22-11e6-9083-2053ee84a217.png) 14 | ![2](https://cloud.githubusercontent.com/assets/13601723/15353120/55e80dd8-1d22-11e6-89d3-abebb90fb106.png) 15 | ![1](https://cloud.githubusercontent.com/assets/13601723/15353121/5606a018-1d22-11e6-9421-80e6d231b495.png) 16 | ![137](https://cloud.githubusercontent.com/assets/13601723/15404863/7246a034-1e3a-11e6-991e-302ad53f6112.jpg) 17 | ![159](https://cloud.githubusercontent.com/assets/13601723/15404865/72b5c568-1e3a-11e6-8b6b-580d08c0183a.jpg) 18 | ![162](https://cloud.githubusercontent.com/assets/13601723/15404864/72b4052a-1e3a-11e6-9951-1b11fee74967.jpg) 19 | ![178](https://cloud.githubusercontent.com/assets/13601723/15404866/72b67b3e-1e3a-11e6-9c73-4b84ca2b7e11.jpg) 20 | 21 | -------------------------------------------------------------------------------- /dataGen/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define patch_row 160 14 | #define patch_col 96 15 | #define crop_per_image 100 16 | #define negative_image_dir "D:\\Study/Data/INRIA_Pedestrian/Train/neg/" 17 | #define save_dir "D:\\Study/Data/INRIA_Pedestrian/train_64x128_H96/neg/" 18 | 19 | using namespace std; 20 | using namespace cv; 21 | 22 | 23 | vector get_all_files_names_within_folder(string folder) 24 | { 25 | vector names; 26 | char search_path[1000]; 27 | sprintf_s(search_path, 1000, "%s*.*", folder.c_str()); 28 | WIN32_FIND_DATA fd; 29 | HANDLE hFind = ::FindFirstFile(search_path, &fd); 30 | if (hFind != INVALID_HANDLE_VALUE) { 31 | do { 32 | // read all (real) files in current folder 33 | // , delete '!' read other 2 default folder . and .. 34 | if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 35 | names.push_back(fd.cFileName); 36 | } 37 | } while (::FindNextFile(hFind, &fd)); 38 | ::FindClose(hFind); 39 | } 40 | return names; 41 | } 42 | 43 | 44 | int main() 45 | { 46 | stringstream ss; 47 | vector file_list; 48 | int count = 0; 49 | 50 | srand(time(NULL)); 51 | 52 | cout << "NEGATIVE image parsing is in processing..." << endl; 53 | 54 | 55 | 56 | ss << save_dir; 57 | file_list = get_all_files_names_within_folder(ss.str()); 58 | ss.str(""); 59 | ss.clear(); 60 | 61 | for (int i = 0; i < file_list.size(); i++) 62 | { 63 | ss << save_dir << file_list[i]; 64 | remove(ss.str().c_str()); 65 | ss.str(""); 66 | ss.clear(); 67 | } 68 | 69 | file_list.clear(); 70 | ss.str(""); 71 | ss.clear(); 72 | 73 | 74 | 75 | 76 | ss << negative_image_dir; 77 | 78 | file_list = get_all_files_names_within_folder(ss.str()); 79 | 80 | ss.str(""); 81 | ss.clear(); 82 | 83 | for (int i = 0; i < file_list.size(); i++) 84 | { 85 | string file_name = file_list.at(i); 86 | 87 | 88 | ss << negative_image_dir << file_name; 89 | 90 | Mat image; 91 | image = imread(ss.str()); 92 | 93 | ss.str(""); 94 | ss.clear(); 95 | 96 | vectorrand_col; 97 | vectorrand_row; 98 | int size = 0; 99 | 100 | for (int negative_number = 0; negative_number < crop_per_image; negative_number++) 101 | { 102 | 103 | bool pass = true; 104 | 105 | int col_index = rand() % (image.cols - patch_col); 106 | int row_index = rand() % (image.rows - patch_row); 107 | 108 | for (int j = 0; j < size; j++) 109 | { 110 | if (col_index == rand_col.at(j) && row_index == rand_row.at(j)) 111 | pass = false; 112 | } 113 | 114 | if (!pass) 115 | negative_number--; 116 | 117 | else 118 | { 119 | rand_col.push_back(col_index); 120 | rand_row.push_back(row_index); 121 | size++; 122 | } 123 | 124 | } 125 | 126 | 127 | for (int j = 0; j < crop_per_image; j++) 128 | { 129 | Mat crop; 130 | crop = image(Rect(rand_col.at(j), rand_row.at(j), patch_col, patch_row)); 131 | 132 | ss << save_dir << count << ".jpg"; 133 | count++; 134 | 135 | imwrite(ss.str(), crop); 136 | 137 | ss.str(""); 138 | ss.clear(); 139 | } 140 | 141 | } 142 | // 143 | 144 | cout << "Done!" << endl; 145 | return 0; 146 | } -------------------------------------------------------------------------------- /Random_forest/main.cpp: -------------------------------------------------------------------------------- 1 | #include "RF_architecture.h" 2 | 3 | void main() 4 | { 5 | 6 | node tree_head[100]; 7 | node* tree_ptr; 8 | int M = 5; 9 | int NofBoot = 20; 10 | int NofTree = 100; 11 | int maxDepth = 6; 12 | int minCount = 10; 13 | 14 | vector pedestrian_feature_value; 15 | vector negative_feature_value; 16 | 17 | clock_t begin, end; 18 | begin = clock(); 19 | 20 | srand(time(NULL)); 21 | 22 | /* 23 | //positive HOG load 24 | for (int i = 0; i < 2416; i++) 25 | { 26 | FILE* fp_pos; 27 | char filename[100]; 28 | 29 | sprintf_s(filename, "pos_hog/%d.txt", i+1); 30 | 31 | fopen_s(&fp_pos, filename, "r"); 32 | 33 | 34 | Mat* sample_matrix = new Mat(1, 15 * 7 * 9 * 4, CV_32FC1); 35 | 36 | 37 | for (int index = 0; index < 3780; index++) 38 | { 39 | float hog_tmp; 40 | fscanf_s(fp_pos, "%f", &hog_tmp); 41 | sample_matrix->at(0, index) = hog_tmp; 42 | } 43 | 44 | 45 | fclose(fp_pos); 46 | 47 | struct feature_value_struct tmp; 48 | tmp.hog_value = sample_matrix; 49 | pedestrian_feature_value.push_back(tmp); 50 | 51 | } 52 | printf("Loading positive HOG complete!!\n"); 53 | 54 | 55 | //negative HOG load 56 | for (int i = 0; i < 1218*8; i++) 57 | { 58 | FILE* fp_neg; 59 | char filename[100]; 60 | 61 | sprintf_s(filename, "neg_bagging/%d.txt", i+1); 62 | 63 | fopen_s(&fp_neg, filename, "r"); 64 | 65 | 66 | Mat* sample_matrix = new Mat(1, 15 * 7 * 9 * 4, CV_32FC1); 67 | 68 | 69 | for (int index = 0; index < 3780; index++) 70 | { 71 | float hog_tmp; 72 | fscanf_s(fp_neg, "%f", &hog_tmp); 73 | sample_matrix->at(0, index) = hog_tmp; 74 | } 75 | 76 | 77 | fclose(fp_neg); 78 | 79 | struct feature_value_struct tmp; 80 | tmp.hog_value = sample_matrix; 81 | negative_feature_value.push_back(tmp); 82 | 83 | } 84 | printf("Loading negative HOG complete!!\n\n"); 85 | 86 | 87 | printf("Training START!!\n"); 88 | for (int boot_number = 0; boot_number < NofBoot; boot_number++) 89 | { 90 | 91 | 92 | for (int tree_number = boot_number*M; tree_number < (boot_number+1)*M; tree_number++) 93 | { 94 | 95 | tree_ptr = &tree_head[tree_number]; 96 | 97 | //tree initialize 98 | tree_ptr->pedestrian_feature_value = pedestrian_feature_value; 99 | tree_ptr->negative_feature_value = negative_feature_value; 100 | tree_ptr->distribution_pedestrian = ((double)(tree_ptr->pedestrian_feature_value.size())) / ((double)(tree_ptr->pedestrian_feature_value.size()) + (double)(tree_ptr->negative_feature_value.size())); 101 | tree_ptr->distribution_negative = ((double)(tree_ptr->negative_feature_value.size())) / ((double)(tree_ptr->pedestrian_feature_value.size()) + (double)(tree_ptr->negative_feature_value.size())); 102 | tree_ptr->count_pedestrian = tree_ptr->pedestrian_feature_value.size(); 103 | tree_ptr->count_negative = tree_ptr->negative_feature_value.size(); 104 | tree_ptr->depth = 0; 105 | 106 | printf("%dth tree is in training...\n", tree_number + 1); 107 | 108 | split_node(tree_ptr, 1, maxDepth, minCount);//split!! 109 | } 110 | 111 | 112 | //delete negative features and search a false-positive examples by bootstrapping 113 | for (vector::iterator it = negative_feature_value.begin(); it != negative_feature_value.end(); it++) 114 | delete it->hog_value; 115 | 116 | negative_feature_value.clear(); 117 | 118 | 119 | if ((boot_number + 1)*M == NofTree) 120 | break; 121 | 122 | 123 | //Bootstrap in order to collect false-positive images 124 | printf("\nBootstrap start!\n"); 125 | for (; negative_feature_value.size() < 1218 * 8;) 126 | { 127 | int file_index = rand() % 1218 + 1; 128 | int x, y; 129 | int width, height; 130 | char filename[100]; 131 | sprintf_s(filename, "neg_original/%d.jpg", file_index); 132 | Mat boot_image = imread(filename); 133 | Mat gray; 134 | cvtColor(boot_image, gray, CV_BGR2GRAY); 135 | printf("%dth bootstrapping... negative_feature_value vector size : %d\n", boot_number+1,negative_feature_value.size()); 136 | 137 | while (gray.cols > 64 && gray.rows > 128) 138 | { 139 | 140 | 141 | 142 | HOGDescriptor boot_hog; 143 | vector boot_hog_value; 144 | vector boot_locations; 145 | 146 | width = gray.cols; 147 | height = gray.rows; 148 | 149 | 150 | while ((width - 16) % 8 != 0) 151 | width--; 152 | while ((height - 16) % 8 != 0) 153 | height--; 154 | 155 | 156 | boot_hog.winSize = Size(width, height); 157 | 158 | boot_hog.compute(gray, boot_hog_value, Size(0, 0), Size(0, 0), boot_locations); 159 | 160 | x = 0; 161 | y = 0; 162 | 163 | 164 | for (;; x = x + 8) 165 | { 166 | 167 | if (x + 64 > width) 168 | { 169 | x = 0; 170 | y = y + 8; 171 | } 172 | 173 | if (y + 128 > height) 174 | break; 175 | 176 | Mat sample_matrix(1, 15 * 7 * 9 * 4, CV_32FC1); 177 | 178 | 179 | int elem; 180 | int y_index = y / 8; 181 | 182 | for (int x_index = x / 8; x_index < x / 8 + 7; x_index++) 183 | { 184 | elem = (9 * 4 * (height / 8 - 1))*x_index + (9 * 4)*y_index; 185 | 186 | for (int c = (x_index - x / 8) * 15 * 4 * 9; c < (x_index - x / 8 + 1) * 15 * 4 * 9; c++) 187 | sample_matrix.at(0, c) = boot_hog_value.at(elem++); 188 | } 189 | 190 | 191 | double pedestrian_confidence = 0; 192 | for (int tree_number = 0; tree_number < (boot_number + 1)*M; tree_number++) 193 | { 194 | 195 | tree_ptr = &tree_head[tree_number]; 196 | 197 | for (;;) 198 | { 199 | 200 | if (tree_ptr->left_child == NULL && tree_ptr->right_child == NULL) 201 | break; 202 | 203 | else 204 | { 205 | 206 | if (sample_matrix.at(0, tree_ptr->index) < tree_ptr->tau) 207 | tree_ptr = tree_ptr->left_child; 208 | else 209 | tree_ptr = tree_ptr->right_child; 210 | 211 | } 212 | 213 | } 214 | 215 | pedestrian_confidence += tree_ptr->distribution_pedestrian; 216 | } 217 | 218 | pedestrian_confidence /= (double)((boot_number + 1)*M); 219 | 220 | 221 | if (pedestrian_confidence > 0.25) 222 | { 223 | Mat* boot_matrix = new Mat(1, 15 * 7 * 9 * 4, CV_32FC1); 224 | *boot_matrix = sample_matrix; 225 | struct feature_value_struct tmp; 226 | tmp.hog_value = boot_matrix; 227 | negative_feature_value.push_back(tmp); 228 | } 229 | } 230 | 231 | Mat resized_image; 232 | resize(gray, resized_image, Size(floor((double)gray.cols / 1.05), floor((double)gray.rows / 1.05)), 0, 0, INTER_LINEAR); 233 | gray = resized_image; 234 | 235 | } 236 | } 237 | 238 | 239 | } 240 | 241 | 242 | //memory deallocation 243 | for (vector::iterator it = pedestrian_feature_value.begin(); it != pedestrian_feature_value.end(); it++) 244 | delete it->hog_value; 245 | 246 | pedestrian_feature_value.clear(); 247 | 248 | 249 | save_tree(tree_head, NofTree); 250 | */ 251 | 252 | load_tree(tree_head, NofTree); 253 | 254 | 255 | //training tree complete 256 | printf("Training complete!!\n\n"); 257 | 258 | end = clock(); 259 | clock_t training_time = end - begin; 260 | cout << (double)(end - begin) / CLOCKS_PER_SEC << "seconds for training" << endl << endl; 261 | 262 | 263 | 264 | printf("Testing start!\n"); 265 | 266 | begin = clock(); 267 | 268 | int miss_pedestrian[100];//count missed pedestrian 269 | int false_positive[100];//count false-positive 270 | int count_pedestrian = 0;//total number of pedestrian 271 | 272 | 273 | for (int i = 0; i < 100; i++) 274 | { 275 | miss_pedestrian[i] = 0; 276 | false_positive[i] = 0; 277 | } 278 | 279 | 280 | vector ground_truth_vector[100];//groundtruth 281 | vector bounding_box[100];//bounding box 282 | double scale = pow(0.5, 0.125); 283 | double lamda = 0.21; 284 | int count_scale; 285 | for (int i = 0; i < 288; i++) 286 | { 287 | 288 | printf("%dth image is in testing...\n", i + 1); 289 | 290 | count_scale = 0; 291 | 292 | char filename[100]; 293 | sprintf_s(filename, "test/%d.jpg", i + 1); 294 | 295 | 296 | Mat test_image; 297 | test_image = imread(filename); 298 | Mat gray; 299 | cvtColor(test_image, gray, CV_BGR2GRAY); 300 | 301 | 302 | double pedestrian_confidence = 0; 303 | double negative_confidence = 0; 304 | 305 | 306 | int x; 307 | int y; 308 | int width; 309 | int height; 310 | 311 | 312 | //modify width and height in order to calculate HOG feature 313 | int original_width = test_image.cols; 314 | int original_height = test_image.rows; 315 | 316 | while ((original_width - 16) % 8 != 0) 317 | original_width--; 318 | while ((original_height - 16) % 8 != 0) 319 | original_height--; 320 | 321 | 322 | int scaled_x; 323 | int scaled_y; 324 | int scaled_width; 325 | int scaled_height; 326 | 327 | 328 | for (int p = 0; p < 100; p++) 329 | { 330 | bounding_box[p].clear(); 331 | ground_truth_vector[p].clear(); 332 | } 333 | 334 | 335 | //groundtruth parsing 336 | FILE* fp_groundtruth; 337 | char filename_groundtruth[100]; 338 | sprintf_s(filename_groundtruth, "groundtruth/%d.txt", i + 1); 339 | fopen_s(&fp_groundtruth, filename_groundtruth, "r"); 340 | 341 | char cordinate[100]; 342 | 343 | while (fgets(cordinate, sizeof(cordinate), fp_groundtruth)) 344 | { 345 | count_pedestrian++; 346 | 347 | char* str = cordinate; 348 | int tmp; 349 | int x_min; 350 | int y_min; 351 | int x_max; 352 | int y_max; 353 | 354 | for (tmp = 0; tmp < 4; tmp++) 355 | { 356 | const char *begin = str; 357 | 358 | while (*str != ' ' && *str != '\n') 359 | str++; 360 | 361 | if (tmp == 0) 362 | x_min = atoi(string(begin, str).c_str()); 363 | if (tmp == 1) 364 | y_min = atoi(string(begin, str).c_str()); 365 | if (tmp == 2) 366 | x_max = atoi(string(begin, str).c_str()); 367 | if (tmp == 3) 368 | y_max = atoi(string(begin, str).c_str()); 369 | 370 | str++; 371 | } 372 | 373 | struct ground_truth tmp_struct; 374 | tmp_struct.is_detected = false; 375 | tmp_struct.x_max = x_max; 376 | tmp_struct.x_min = x_min; 377 | tmp_struct.y_max = y_max; 378 | tmp_struct.y_min = y_min; 379 | 380 | for (int p = 0; p < 100; p++) 381 | ground_truth_vector[p].push_back(tmp_struct); 382 | 383 | } 384 | 385 | fclose(fp_groundtruth); 386 | 387 | HOGDescriptor testing_hog; 388 | vector testing_hog_value; 389 | vector testing_locations; 390 | 391 | width = gray.cols; 392 | height = gray.rows; 393 | 394 | 395 | while ((width - 16) % 8 != 0) 396 | width--; 397 | while ((height - 16) % 8 != 0) 398 | height--; 399 | 400 | 401 | testing_hog.winSize = Size(width, height); 402 | 403 | testing_hog.compute(gray, testing_hog_value, Size(0, 0), Size(0, 0), testing_locations); 404 | 405 | float*** hog_value = get_hog(testing_hog_value, Size(width, height), Size(8, 8)); 406 | 407 | 408 | while (width> 64 && height > 128) 409 | { 410 | x = 0; 411 | y = 0; 412 | 413 | //window stride is 8 pixel in both of x and y cordinate 414 | for (;; x = x + 8) 415 | { 416 | 417 | if (x + 64 > width) 418 | { 419 | x = 0; 420 | y = y + 8; 421 | } 422 | 423 | if (y + 128 > height) 424 | break; 425 | 426 | 427 | 428 | pedestrian_confidence = 0; 429 | for (int tree_number = 0; tree_number < M; tree_number++) 430 | { 431 | 432 | 433 | tree_ptr = &tree_head[tree_number]; 434 | 435 | for (;;) 436 | { 437 | 438 | if (tree_ptr->left_child == NULL && tree_ptr->right_child == NULL) 439 | break; 440 | 441 | else 442 | { 443 | 444 | if (testing_hog_value.at((9 * 4 * (height / 8 - 1))*(x / 8 + tree_ptr->index / (15 * 4 * 9)) + (9 * 4)*(y / 8) + tree_ptr->index % (15 * 4 * 9)) < tree_ptr->tau) 445 | tree_ptr = tree_ptr->left_child; 446 | else 447 | tree_ptr = tree_ptr->right_child; 448 | 449 | } 450 | 451 | } 452 | 453 | pedestrian_confidence += tree_ptr->distribution_pedestrian; 454 | 455 | } 456 | 457 | pedestrian_confidence = pedestrian_confidence / (double)(M); 458 | negative_confidence = negative_confidence / (double)(M); 459 | 460 | int t = M; 461 | 462 | //soft cascade 463 | while (pedestrian_confidence > 0.1 && t < NofTree) 464 | { 465 | tree_ptr = &tree_head[t]; 466 | 467 | for (;;) 468 | { 469 | 470 | if (tree_ptr->left_child == NULL && tree_ptr->right_child == NULL) 471 | break; 472 | 473 | else 474 | { 475 | 476 | if (testing_hog_value.at((9 * 4 * (height / 8 - 1))*(x / 8 + tree_ptr->index / (15 * 4 * 9)) + (9 * 4)*(y / 8) + tree_ptr->index % (15 * 4 * 9)) < tree_ptr->tau) 477 | tree_ptr = tree_ptr->left_child; 478 | else 479 | tree_ptr = tree_ptr->right_child; 480 | 481 | } 482 | 483 | } 484 | 485 | double tmp_score = tree_ptr->distribution_pedestrian; 486 | 487 | 488 | pedestrian_confidence = ((double)(1)) / ((double)(t + 1))*(pedestrian_confidence*(double)t + tmp_score); 489 | t++; 490 | 491 | } 492 | 493 | 494 | //make bounding box 495 | int bb_num = 0; 496 | for (double threshold = -0.3; threshold<0.3; threshold = threshold + 0.006) 497 | { 498 | 499 | if (pedestrian_confidence > 0.50 + threshold) 500 | { 501 | 502 | scaled_y = (int)((double)original_height) * (((double)(y + 8)) / ((double)height)); 503 | 504 | scaled_height = (int)((0.75)*(((double)original_height) * (((double)(y + 8) + (double)128) / ((double)height)) - (double)scaled_y)); 505 | 506 | scaled_x = (int)(((double)original_width) * (((double)(x + 8)) / ((double)width)) + 0.05*(double)scaled_height); 507 | scaled_width = (int)(0.4*(double)scaled_height); 508 | 509 | struct bounding_box tmp; 510 | tmp.rect = Rect(scaled_x, scaled_y, scaled_width, scaled_height); 511 | tmp.confidence = pedestrian_confidence; 512 | tmp.is_false_positive = true; 513 | tmp.is_suppressed = false; 514 | 515 | bounding_box[bb_num].push_back(tmp); 516 | 517 | } 518 | bb_num++; 519 | 520 | } 521 | 522 | 523 | } 524 | 525 | //Fast feature pyramid! 526 | if ((count_scale + 1) % 4 == 0) 527 | { 528 | for (int y = 0; y suppressed_bounding_box[100]; 605 | 606 | //Non-Maximum-Suppresion 607 | for (int p = 0; p < 100; p++) 608 | { 609 | int original_size = -1; 610 | int suppressed_size = 1; 611 | 612 | 613 | while (bounding_box[p].size()>1 && suppressed_size != original_size) 614 | { 615 | while (1) 616 | { 617 | suppressed_size = 0; 618 | vector::iterator loc; 619 | float maxValue = -1; 620 | 621 | 622 | for (vector::iterator it = bounding_box[p].begin(); it != bounding_box[p].end(); it++) 623 | { 624 | if (it->confidence > maxValue && it->is_suppressed == false) 625 | { 626 | maxValue = it->confidence; 627 | loc = it; 628 | } 629 | 630 | if (it->is_suppressed == false) 631 | suppressed_size++; 632 | } 633 | 634 | if (suppressed_size == 0) 635 | break; 636 | 637 | struct bounding_box NMS_bb; 638 | NMS_bb.confidence = loc->confidence; 639 | NMS_bb.is_false_positive = true; 640 | NMS_bb.is_suppressed = false; 641 | NMS_bb.rect = loc->rect; 642 | 643 | NMS(&bounding_box[p], *loc); 644 | 645 | suppressed_bounding_box[p].push_back(NMS_bb); 646 | 647 | } 648 | 649 | 650 | original_size = bounding_box[p].size(); 651 | bounding_box[p] = suppressed_bounding_box[p]; 652 | suppressed_bounding_box[p].clear(); 653 | suppressed_size = bounding_box[p].size(); 654 | 655 | } 656 | } 657 | 658 | 659 | //determine detected groundtruth and false-positive bounding box 660 | for (int bb_num = 0; bb_num < 100; bb_num++) 661 | { 662 | for (vector ::iterator it = ground_truth_vector[bb_num].begin(); it != ground_truth_vector[bb_num].end(); it++) 663 | { 664 | for (vector::iterator it2 = bounding_box[bb_num].begin(); it2 != bounding_box[bb_num].end(); it2++) 665 | { 666 | int width_intersect = min(it->x_max, it2->rect.width + it2->rect.x) - max(it2->rect.x, it->x_min); 667 | int height_intersect = min(it->y_max, it2->rect.height + it2->rect.y) - max(it2->rect.y, it->y_min); 668 | int area_intersect = width_intersect * height_intersect; 669 | int area_union = it2->rect.height *it2->rect.width + (it->x_max - it->x_min)*(it->y_max - it->y_min) - area_intersect; 670 | double overlap_ratio = (double)(area_intersect) / (double)(area_union); 671 | 672 | if (width_intersect > 0 && height_intersect > 0 && overlap_ratio > 0.5) 673 | { 674 | it->is_detected = true; 675 | it2->is_false_positive = false; 676 | } 677 | 678 | } 679 | 680 | } 681 | } 682 | 683 | 684 | 685 | for (int p = 0; p < 100; p++) 686 | { 687 | for (vector::iterator it = bounding_box[p].begin(); it != bounding_box[p].end(); it++) 688 | { 689 | 690 | if (it->is_false_positive == true) 691 | false_positive[p]++; 692 | } 693 | 694 | for (vector::iterator it2 = ground_truth_vector[p].begin(); it2 != ground_truth_vector[p].end(); it2++) 695 | { 696 | if (it2->is_detected == false) 697 | miss_pedestrian[p]++; 698 | } 699 | 700 | } 701 | 702 | char filename_result[100]; 703 | sprintf_s(filename_result, "result/%d.jpg", i + 1); 704 | 705 | //draw bounding box and write image(RED is false-positive, BLUE is true-positive, GREEN is groundtruth) 706 | for (vector::iterator it = bounding_box[0].begin(); it != bounding_box[0].end(); it++) 707 | { 708 | if (it->is_false_positive == true) 709 | rectangle(test_image, it->rect, CV_RGB(255, 0, 0), 2); 710 | else 711 | rectangle(test_image, it->rect, CV_RGB(0, 0, 255), 2); 712 | } 713 | 714 | for (vector::iterator it = ground_truth_vector[0].begin(); it != ground_truth_vector[0].end(); it++) 715 | rectangle(test_image, Rect(it->x_min, it->y_min, it->x_max - it->x_min, it->y_max - it->y_min), CV_RGB(0, 255, 0), 2); 716 | 717 | imwrite(filename_result, test_image); 718 | 719 | 720 | 721 | } 722 | printf("Testing complete!!\n\n"); 723 | end = clock(); 724 | cout << (double)(end - begin) / CLOCKS_PER_SEC << "seconds for 288 test images" << endl << endl; 725 | cout << (double)training_time / CLOCKS_PER_SEC << "seconds for training" << endl << endl; 726 | 727 | FILE* result; 728 | fopen_s(&result, "result.txt", "w"); 729 | for (int p = 0; p < 100; p++) 730 | fprintf_s(result, "%lf %lf\n", (double)miss_pedestrian[p] / (double)count_pedestrian, (double)false_positive[p] / (double)288); 731 | 732 | fclose(result); 733 | 734 | 735 | 736 | } 737 | -------------------------------------------------------------------------------- /Boosted_tree/main.cpp: -------------------------------------------------------------------------------- 1 | #include "BT_architecture.h" 2 | 3 | 4 | void main() 5 | { 6 | 7 | vector tree_head; 8 | node* tree_ptr; 9 | int NofTree = 2000; 10 | int NofBoot = 2; 11 | int initial_negative = 1218 * 5; 12 | int soft_cascade_number = 40; 13 | int maxDepth = 2; 14 | double alpha_sum = 0; 15 | double minCount = 10 * (1.0 / 2416.0 + 1.0 / (double)initial_negative); 16 | 17 | vector pedestrian_feature_value; 18 | vector negative_feature_value; 19 | 20 | 21 | clock_t begin, end; 22 | begin = clock(); 23 | 24 | srand(time(NULL)); 25 | 26 | /* 27 | //positive training image's HOG feature load 28 | for (int i = 0; i < 2416; i++) 29 | { 30 | 31 | FILE* fp_pos; 32 | char filename[100]; 33 | 34 | sprintf_s(filename, "pos_hog/%d.txt", i + 1); 35 | 36 | fopen_s(&fp_pos, filename, "r"); 37 | 38 | 39 | Mat sample_matrix(1, 15 * 7 * 9 * 4, CV_32FC1); 40 | 41 | 42 | for (int index = 0; index < 3780; index++) 43 | { 44 | float hog_tmp; 45 | fscanf_s(fp_pos, "%f", &hog_tmp); 46 | sample_matrix.at(0, index) = hog_tmp; 47 | } 48 | 49 | 50 | fclose(fp_pos); 51 | 52 | struct feature_value_struct* tmp = new struct feature_value_struct(); 53 | tmp->hog_value = sample_matrix; 54 | tmp->weight = (double)1 / (double)(2*2416); 55 | pedestrian_feature_value.push_back(tmp); 56 | } 57 | printf("Loading positive HOG feature complete!!\n"); 58 | 59 | 60 | //negative training image's HOG feature load 61 | for (int i = 0; i < initial_negative; i++) 62 | { 63 | FILE* fp_neg; 64 | char filename[100]; 65 | int fileindex = rand() % (1218 * 5) + 1; 66 | 67 | sprintf_s(filename, "neg_adaboost/%d.txt", i+1); 68 | fopen_s(&fp_neg, filename, "r"); 69 | 70 | 71 | Mat sample_matrix(1, 15 * 7 * 9 * 4, CV_32FC1); 72 | 73 | 74 | for (int index = 0; index < 3780; index++) 75 | { 76 | float hog_tmp; 77 | fscanf_s(fp_neg, "%f", &hog_tmp); 78 | sample_matrix.at(0, index) = hog_tmp; 79 | } 80 | 81 | 82 | fclose(fp_neg); 83 | 84 | struct feature_value_struct* tmp = new struct feature_value_struct(); 85 | tmp->hog_value = sample_matrix; 86 | tmp->weight = (double)1 / (double)(2 * initial_negative); 87 | negative_feature_value.push_back(tmp); 88 | 89 | } 90 | printf("Loading negative HOG feature complete!!\n"); 91 | 92 | 93 | 94 | for (int boot_number = 0; ;boot_number++) 95 | { 96 | 97 | alpha_sum = 0; 98 | 99 | 100 | //weight initialize 101 | for (int index = 0; index < pedestrian_feature_value.size(); index++) 102 | pedestrian_feature_value.at(index)->weight = (double)1 / (double)(2 * 2416); 103 | 104 | for (int index = 0; index < negative_feature_value.size(); index++) 105 | negative_feature_value.at(index)->weight = (double)1 / (double)(2 * negative_feature_value.size()); 106 | 107 | 108 | for (int tree_number = 0; tree_number < NofTree;tree_number++) 109 | { 110 | double training_error; 111 | double pedestrian_sum = 0; 112 | double negative_sum = 0; 113 | double sum; 114 | 115 | 116 | //weight normalization 117 | for (int index = 0; index < pedestrian_feature_value.size(); index++) 118 | pedestrian_sum += pedestrian_feature_value.at(index)->weight; 119 | 120 | for (int index = 0; index < negative_feature_value.size(); index++) 121 | negative_sum += negative_feature_value.at(index)->weight; 122 | 123 | sum = pedestrian_sum + negative_sum; 124 | 125 | for (int index = 0; index < pedestrian_feature_value.size(); index++) 126 | pedestrian_feature_value.at(index)->weight = pedestrian_feature_value.at(index)->weight / sum; 127 | 128 | for (int index = 0; index < negative_feature_value.size(); index++) 129 | negative_feature_value.at(index)->weight = negative_feature_value.at(index)->weight / sum; 130 | 131 | 132 | //tree initialize 133 | tree_ptr = new node(); 134 | tree_ptr->pedestrian_feature_value = pedestrian_feature_value; 135 | tree_ptr->negative_feature_value = negative_feature_value; 136 | tree_ptr->distribution_pedestrian = pedestrian_sum / (pedestrian_sum + negative_sum); 137 | tree_ptr->distribution_negative = negative_sum / (pedestrian_sum + negative_sum); 138 | tree_ptr->count_pedestrian = pedestrian_sum; 139 | tree_ptr->count_negative = negative_sum; 140 | tree_ptr->depth = 0; 141 | 142 | //grow tree 143 | split_node(tree_ptr, 1, maxDepth, minCount); 144 | 145 | training_error = get_error(tree_ptr); 146 | 147 | printf("%dth bootstrap is done! %dth tree is in training in ... error : %f\n", boot_number,tree_number + 1, training_error); 148 | 149 | //if error>=0.5, it is useless! 150 | if (training_error >= 0.5) 151 | { 152 | delete_tree(tree_ptr); 153 | break; 154 | } 155 | 156 | 157 | tree_head.push_back(tree_ptr); 158 | 159 | //calculate alpha 160 | tree_ptr->alpha = 0.5*log((1 - training_error) / training_error); 161 | alpha_sum += tree_ptr->alpha; 162 | 163 | //decide features are classified correctly or not 164 | update_feature(tree_ptr); 165 | 166 | 167 | //weight update 168 | for (int index = 0; index < pedestrian_feature_value.size(); index++) 169 | { 170 | 171 | if (pedestrian_feature_value.at(index)->is_correct == true) 172 | pedestrian_feature_value.at(index)->weight *= exp(-1 * tree_ptr->alpha); 173 | else 174 | pedestrian_feature_value.at(index)->weight *= exp(tree_ptr->alpha); 175 | 176 | } 177 | 178 | for (int index = 0; index < negative_feature_value.size(); index++) 179 | { 180 | 181 | if (negative_feature_value.at(index)->is_correct == true) 182 | negative_feature_value.at(index)->weight *= exp(-1 * tree_ptr->alpha); 183 | else 184 | negative_feature_value.at(index)->weight *= exp(tree_ptr->alpha); 185 | } 186 | 187 | } 188 | 189 | 190 | if (boot_number == NofBoot) 191 | break; 192 | 193 | 194 | //bootstrap strat in image pyramid 195 | printf("\nBootstrap start!!\n"); 196 | int initial_size = negative_feature_value.size(); 197 | for (; negative_feature_value.size() < initial_size + 5000;) 198 | { 199 | int file_index = rand() % 1218 + 1; 200 | int x, y; 201 | int width, height; 202 | char filename[100]; 203 | sprintf_s(filename, "neg_original/%d.jpg", file_index); 204 | Mat boot_image = imread(filename); 205 | Mat gray; 206 | cvtColor(boot_image, gray, CV_BGR2GRAY); 207 | printf("%dth bootstrapping... negative_feature_value vector size : %d\n", boot_number + 1, negative_feature_value.size()); 208 | 209 | while (gray.cols > 64 && gray.rows > 128) 210 | { 211 | 212 | 213 | HOGDescriptor boot_hog; 214 | vector boot_hog_value; 215 | vector boot_locations; 216 | 217 | width = gray.cols; 218 | height = gray.rows; 219 | 220 | 221 | while ((width - 16) % 8 != 0) 222 | width--; 223 | while ((height - 16) % 8 != 0) 224 | height--; 225 | 226 | 227 | boot_hog.winSize = Size(width, height); 228 | 229 | boot_hog.compute(gray, boot_hog_value, Size(0, 0), Size(0, 0), boot_locations); 230 | 231 | x = 0; 232 | y = 0; 233 | 234 | 235 | for (;; x = x + 8) 236 | { 237 | 238 | if (x + 64 > width) 239 | { 240 | x = 0; 241 | y = y + 8; 242 | } 243 | 244 | if (y + 128 > height) 245 | break; 246 | 247 | Mat sample_matrix(1, 15 * 7 * 9 * 4, CV_32FC1); 248 | 249 | 250 | int elem; 251 | int y_index = y / 8; 252 | 253 | for (int x_index = x / 8; x_index < x / 8 + 7; x_index++) 254 | { 255 | elem = (9 * 4 * (height / 8 - 1))*x_index + (9 * 4)*y_index; 256 | 257 | for (int c = (x_index - x / 8) * 15 * 4 * 9; c < (x_index - x / 8 + 1) * 15 * 4 * 9; c++) 258 | sample_matrix.at(0, c) = boot_hog_value.at(elem++); 259 | } 260 | 261 | 262 | double pedestrian_confidence = 0; 263 | for (int index = 0; index < tree_head.size(); index++) 264 | { 265 | 266 | tree_ptr = tree_head.at(index); 267 | double alpha = tree_ptr->alpha; 268 | 269 | for (;;) 270 | { 271 | 272 | if (tree_ptr->left_child == NULL && tree_ptr->right_child == NULL) 273 | break; 274 | 275 | else 276 | { 277 | 278 | if (sample_matrix.at(0, tree_ptr->index) < tree_ptr->tau) 279 | tree_ptr = tree_ptr->left_child; 280 | else 281 | tree_ptr = tree_ptr->right_child; 282 | 283 | } 284 | 285 | } 286 | if (tree_ptr->distribution_pedestrian > tree_ptr->distribution_negative) 287 | pedestrian_confidence += alpha; 288 | else 289 | pedestrian_confidence -= alpha; 290 | } 291 | 292 | pedestrian_confidence /= alpha_sum; 293 | 294 | 295 | if (pedestrian_confidence > 0.0) 296 | { 297 | struct feature_value_struct* tmp = new struct feature_value_struct(); 298 | tmp->hog_value = sample_matrix; 299 | negative_feature_value.push_back(tmp); 300 | } 301 | } 302 | 303 | Mat resized_image; 304 | resize(gray, resized_image, Size(floor((double)gray.cols / 1.05), floor((double)gray.rows / 1.05)), 0, 0, INTER_LINEAR); 305 | gray= resized_image; 306 | 307 | } 308 | 309 | } 310 | 311 | printf("\n\nBootstrap is done! re-training start!!\n"); 312 | 313 | //delete existing trees and build a new forest based on bootstrapped examples 314 | for (int index = 0; index < tree_head.size(); index++) 315 | delete_tree(tree_head.at(index)); 316 | 317 | tree_head.clear(); 318 | 319 | } 320 | 321 | //memory deallocation 322 | for (int index = 0; index < negative_feature_value.size(); index++) 323 | delete negative_feature_value.at(index); 324 | 325 | negative_feature_value.clear(); 326 | 327 | 328 | for (int index = 0; index < pedestrian_feature_value.size(); index++) 329 | delete pedestrian_feature_value.at(index); 330 | 331 | pedestrian_feature_value.clear(); 332 | 333 | 334 | //training tree complete 335 | printf("\nTraining complete!!\n"); 336 | 337 | end = clock(); 338 | clock_t training_time = end - begin; 339 | cout << (double)(end - begin) / CLOCKS_PER_SEC << "seconds for training" << endl << endl; 340 | 341 | 342 | save_tree(tree_head); 343 | */ 344 | load_tree(&tree_head); 345 | 346 | 347 | printf("\nTesting start!\n"); 348 | 349 | begin = clock(); 350 | 351 | int miss_pedestrian[100];//count missed pedestrians 352 | int false_positive[100];//count false positive bounding box 353 | int count_pedestrian = 0;//total number of pedestrian 354 | 355 | 356 | for (int i = 0; i < 100; i++) 357 | { 358 | miss_pedestrian[i] = 0; 359 | false_positive[i] = 0; 360 | } 361 | 362 | 363 | vector ground_truth_vector[100];//ground truth 364 | vector bounding_box[100];//bounding box 365 | double scale = pow(0.5, 0.125); 366 | double lamda = 0.21; 367 | int count_scale; 368 | 369 | for (int i = 0; i < 288; i++) 370 | { 371 | 372 | printf("%dth image is in testing...\n", i + 1); 373 | char filename[100]; 374 | 375 | sprintf_s(filename, "test/%d.jpg", i + 1); 376 | 377 | count_scale = 0; 378 | Mat test_image; 379 | test_image = imread(filename); 380 | Mat gray; 381 | cvtColor(test_image, gray, CV_BGR2GRAY); 382 | 383 | 384 | double pedestrian_confidence = 0; 385 | 386 | int x; 387 | int y; 388 | int width; 389 | int height; 390 | 391 | int original_width = test_image.cols; 392 | int original_height = test_image.rows; 393 | 394 | 395 | //modify width and height in order to calculate HOG feature 396 | while ((original_width - 16) % 8 != 0) 397 | original_width--; 398 | while ((original_height - 16) % 8 != 0) 399 | original_height--; 400 | 401 | 402 | int scaled_x; 403 | int scaled_y; 404 | int scaled_width; 405 | int scaled_height; 406 | 407 | 408 | for (int p = 0; p < 100; p++) 409 | { 410 | bounding_box[p].clear(); 411 | ground_truth_vector[p].clear(); 412 | } 413 | 414 | 415 | //groundtruth parsing 416 | FILE* fp_groundtruth; 417 | char filename_groundtruth[100]; 418 | sprintf_s(filename_groundtruth, "groundtruth/%d.txt", i + 1); 419 | fopen_s(&fp_groundtruth, filename_groundtruth, "r"); 420 | 421 | char cordinate[100]; 422 | 423 | while (fgets(cordinate, sizeof(cordinate), fp_groundtruth)) 424 | { 425 | count_pedestrian++; 426 | 427 | char* str = cordinate; 428 | int tmp; 429 | int x_min; 430 | int y_min; 431 | int x_max; 432 | int y_max; 433 | 434 | for (tmp = 0; tmp < 4; tmp++) 435 | { 436 | const char *begin = str; 437 | 438 | while (*str != ' ' && *str != '\n') 439 | str++; 440 | 441 | if (tmp == 0) 442 | x_min = atoi(string(begin, str).c_str()); 443 | if (tmp == 1) 444 | y_min = atoi(string(begin, str).c_str()); 445 | if (tmp == 2) 446 | x_max = atoi(string(begin, str).c_str()); 447 | if (tmp == 3) 448 | y_max = atoi(string(begin, str).c_str()); 449 | 450 | str++; 451 | } 452 | 453 | struct ground_truth tmp_struct; 454 | tmp_struct.is_detected = false; 455 | tmp_struct.x_max = x_max; 456 | tmp_struct.x_min = x_min; 457 | tmp_struct.y_max = y_max; 458 | tmp_struct.y_min = y_min; 459 | 460 | for (int p = 0; p < 100; p++) 461 | ground_truth_vector[p].push_back(tmp_struct); 462 | 463 | } 464 | 465 | fclose(fp_groundtruth); 466 | 467 | HOGDescriptor testing_hog; 468 | vector testing_hog_value; 469 | vector testing_locations; 470 | 471 | width = gray.cols; 472 | height = gray.rows; 473 | 474 | 475 | while ((width - 16) % 8 != 0) 476 | width--; 477 | while ((height - 16) % 8 != 0) 478 | height--; 479 | 480 | 481 | testing_hog.winSize = Size(width, height); 482 | 483 | testing_hog.compute(gray, testing_hog_value, Size(0, 0), Size(0, 0), testing_locations); 484 | 485 | float*** hog_value = get_hog(testing_hog_value, Size(width, height), Size(8, 8)); 486 | 487 | //image pyramid 488 | while (width > 64 && height > 128) 489 | { 490 | 491 | x = 0; 492 | y = 0; 493 | 494 | //sliding window. stride is 8 pixel in both of x and y cordinate 495 | for (;; x = x + 8) 496 | { 497 | 498 | if (x + 64 > width) 499 | { 500 | x = 0; 501 | y = y + 8; 502 | } 503 | 504 | if (y + 128 > height) 505 | break; 506 | 507 | 508 | 509 | //soft-cascade 510 | pedestrian_confidence = 0; 511 | double sub_alpha_sum = 0; 512 | for (int index = 0; index < soft_cascade_number; index++) 513 | { 514 | tree_ptr = tree_head.at(index); 515 | double alpha = tree_ptr->alpha; 516 | sub_alpha_sum += alpha; 517 | 518 | for (;;) 519 | { 520 | 521 | if (tree_ptr->left_child == NULL && tree_ptr->right_child == NULL) 522 | break; 523 | 524 | else 525 | { 526 | 527 | if (testing_hog_value.at((9 * 4 * (height / 8 - 1))*(x / 8 + tree_ptr->index / (15 * 4 * 9)) + (9 * 4)*(y / 8) + tree_ptr->index % (15 * 4 * 9)) < tree_ptr->tau) 528 | tree_ptr = tree_ptr->left_child; 529 | else 530 | tree_ptr = tree_ptr->right_child; 531 | } 532 | 533 | } 534 | 535 | 536 | if (tree_ptr->distribution_negative < tree_ptr->distribution_pedestrian) 537 | pedestrian_confidence += alpha; 538 | else 539 | pedestrian_confidence -= alpha; 540 | 541 | } 542 | 543 | pedestrian_confidence /= sub_alpha_sum; 544 | 545 | int t = soft_cascade_number; 546 | double old_alpha_sum; 547 | double sub_pedestrian_confidence = 0; 548 | 549 | while (pedestrian_confidence > -0.1 && t < NofTree) 550 | { 551 | old_alpha_sum = sub_alpha_sum; 552 | tree_ptr = tree_head.at(t); 553 | double alpha = tree_ptr->alpha; 554 | sub_alpha_sum += alpha; 555 | 556 | for (;;) 557 | { 558 | 559 | if (tree_ptr->left_child == NULL && tree_ptr->right_child == NULL) 560 | break; 561 | 562 | else 563 | { 564 | 565 | if (testing_hog_value.at((9 * 4 * (height / 8 - 1))*(x / 8 + tree_ptr->index / (15 * 4 * 9)) + (9 * 4)*(y / 8) + tree_ptr->index % (15 * 4 * 9)) < tree_ptr->tau) 566 | tree_ptr = tree_ptr->left_child; 567 | else 568 | tree_ptr = tree_ptr->right_child; 569 | 570 | } 571 | 572 | } 573 | 574 | 575 | if (tree_ptr->distribution_negative < tree_ptr->distribution_pedestrian) 576 | sub_pedestrian_confidence = alpha; 577 | else 578 | sub_pedestrian_confidence = -alpha; 579 | 580 | pedestrian_confidence = (pedestrian_confidence*old_alpha_sum + sub_pedestrian_confidence) / sub_alpha_sum; 581 | t++; 582 | } 583 | 584 | 585 | //make bounding box 586 | int bb_num = 0; 587 | for (double threshold = 0.0; threshold < 0.3; threshold += 0.003) 588 | { 589 | if (pedestrian_confidence > 0.0 + threshold) 590 | { 591 | scaled_y = (int)((double)original_height) * (((double)(y + 8)) / ((double)height)); 592 | 593 | scaled_height = (int)((0.75)*(((double)original_height) * (((double)(y + 8) + (double)128) / ((double)height)) - (double)scaled_y)); 594 | 595 | scaled_x = (int)(((double)original_width) * (((double)(x + 8)) / ((double)width)) + 0.05*(double)scaled_height); 596 | scaled_width = (int)(0.4*(double)scaled_height); 597 | 598 | struct bounding_box tmp; 599 | tmp.rect = Rect(scaled_x, scaled_y, scaled_width, scaled_height); 600 | tmp.confidence = pedestrian_confidence; 601 | tmp.is_false_positive = true; 602 | tmp.is_suppressed = false; 603 | 604 | bounding_box[bb_num].push_back(tmp); 605 | 606 | } 607 | bb_num++; 608 | } 609 | 610 | } 611 | //Fast feature pyramid! 612 | if ((count_scale + 1) % 4 == 0) 613 | { 614 | for (int y = 0; y suppressed_bounding_box[100]; 692 | 693 | //Non-Maximum-Suppreesion 694 | for (int p = 0; p < 100; p++) 695 | { 696 | int original_size = -1; 697 | int suppressed_size = 1; 698 | 699 | 700 | while (bounding_box[p].size()>1 && suppressed_size != original_size) 701 | { 702 | while (1) 703 | { 704 | suppressed_size = 0; 705 | vector::iterator loc; 706 | double maxValue = -1; 707 | 708 | 709 | for (vector::iterator it = bounding_box[p].begin(); it != bounding_box[p].end(); it++) 710 | { 711 | if (it->confidence > maxValue && it->is_suppressed == false) 712 | { 713 | maxValue = it->confidence; 714 | loc = it; 715 | } 716 | 717 | if (it->is_suppressed == false) 718 | suppressed_size++; 719 | } 720 | 721 | if (suppressed_size == 0) 722 | break; 723 | 724 | struct bounding_box NMS_bb; 725 | NMS_bb.confidence = loc->confidence; 726 | NMS_bb.is_false_positive = true; 727 | NMS_bb.is_suppressed = false; 728 | NMS_bb.rect = loc->rect; 729 | 730 | NMS(&bounding_box[p], *loc); 731 | 732 | suppressed_bounding_box[p].push_back(NMS_bb); 733 | 734 | } 735 | 736 | 737 | original_size = bounding_box[p].size(); 738 | bounding_box[p] = suppressed_bounding_box[p]; 739 | suppressed_bounding_box[p].clear(); 740 | suppressed_size = bounding_box[p].size(); 741 | 742 | } 743 | } 744 | 745 | 746 | 747 | //decide which pedestrian is detected and which bounding box is false positive 748 | for (int bb_num = 0; bb_num < 100; bb_num++) 749 | { 750 | for (vector ::iterator it = ground_truth_vector[bb_num].begin(); it != ground_truth_vector[bb_num].end(); it++) 751 | { 752 | for (vector::iterator it2 = bounding_box[bb_num].begin(); it2 != bounding_box[bb_num].end(); it2++) 753 | { 754 | int width_intersect = min(it->x_max, it2->rect.width + it2->rect.x) - max(it2->rect.x, it->x_min); 755 | int height_intersect = min(it->y_max, it2->rect.height + it2->rect.y) - max(it2->rect.y, it->y_min); 756 | int area_intersect = width_intersect * height_intersect; 757 | int area_union = it2->rect.height *it2->rect.width + (it->x_max - it->x_min)*(it->y_max - it->y_min) - area_intersect; 758 | double overlap_ratio = (double)(area_intersect) / (double)(area_union); 759 | 760 | if (width_intersect > 0 && height_intersect > 0 && overlap_ratio >= 0.5) 761 | { 762 | it->is_detected = true; 763 | it2->is_false_positive = false; 764 | } 765 | 766 | } 767 | 768 | } 769 | } 770 | 771 | 772 | 773 | for (int p = 0; p < 100; p++) 774 | { 775 | for (vector::iterator it = bounding_box[p].begin(); it != bounding_box[p].end(); it++) 776 | { 777 | 778 | if (it->is_false_positive == true) 779 | false_positive[p]++; 780 | } 781 | 782 | for (vector::iterator it2 = ground_truth_vector[p].begin(); it2 != ground_truth_vector[p].end(); it2++) 783 | { 784 | if (it2->is_detected == false) 785 | miss_pedestrian[p]++; 786 | } 787 | 788 | } 789 | 790 | char filename_result[100]; 791 | sprintf_s(filename_result, "result/%d.jpg", i + 1); 792 | 793 | //draw bounding box and write image. RED is false positive, BLUE is true positive, GREEN is groundtruth 794 | for (vector::iterator it = bounding_box[0].begin(); it != bounding_box[0].end(); it++) 795 | { 796 | if (it->is_false_positive == true) 797 | rectangle(test_image, it->rect, CV_RGB(255, 0, 0), 2); 798 | else 799 | rectangle(test_image, it->rect, CV_RGB(0, 0, 255), 2); 800 | } 801 | 802 | for (vector::iterator it = ground_truth_vector[0].begin(); it != ground_truth_vector[0].end(); it++) 803 | rectangle(test_image, Rect(it->x_min, it->y_min, it->x_max - it->x_min, it->y_max - it->y_min), CV_RGB(0, 255, 0), 2); 804 | 805 | imwrite(filename_result, test_image); 806 | 807 | } 808 | printf("Testing complete!!\n\n"); 809 | end = clock(); 810 | cout << (double)(end - begin) / CLOCKS_PER_SEC << "seconds for 288 test images" << endl << endl; 811 | //cout << (double)training_time / CLOCKS_PER_SEC << "seconds for training" << endl << endl; 812 | 813 | FILE* result; 814 | fopen_s(&result, "result.txt", "w"); 815 | for (int p = 0; p < 100; p++) 816 | fprintf_s(result, "%lf %lf\n", (double)miss_pedestrian[p] / (double)count_pedestrian, (double)false_positive[p] / (double)288); 817 | 818 | fclose(result); 819 | 820 | } 821 | --------------------------------------------------------------------------------