├── .gitignore ├── BinaryStereo.cpp ├── BinaryStereo.h ├── CommonFunc.cpp ├── CommonFunc.h ├── IStereoAlg.cpp ├── IStereoAlg.h ├── LICENSE ├── Makefile ├── README.md └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | -------------------------------------------------------------------------------- /BinaryStereo.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************/ 2 | /* File: BinaryStereo.cpp */ 3 | /* Usage: implement BinaryStereo Class */ 4 | /* Author: Zhang Kang */ 5 | /* Date: */ 6 | /***************************************************************/ 7 | #include "BinaryStereo.h" 8 | #include "CommonFunc.h" 9 | 10 | /***************************************************************/ 11 | /* Function: BinaryStereo */ 12 | /* Usage: initial class member variables */ 13 | /* In: */ 14 | /* const int pS - patch size */ 15 | /* const int mD - disparity levels */ 16 | /* const int dS - disparity scale */ 17 | /* Out: */ 18 | /***************************************************************/ 19 | BinaryStereo::BinaryStereo(const int pS, const int mD, const int dS) 20 | : patchSz(pS), IStereoAlg(mD,dS) 21 | { 22 | descLen = DESC_LEN; 23 | pairDistr = new int[4*DESC_LEN]; 24 | gStd = 4.0f; 25 | lCode = NULL; 26 | rCode = NULL; 27 | lUsed = NULL; 28 | rUsed = NULL; 29 | l_r = NULL; 30 | l_g = NULL; 31 | l_b = NULL; 32 | r_r = NULL; 33 | r_g = NULL; 34 | r_b = NULL; 35 | lL = NULL; 36 | lA = NULL; 37 | lB = NULL; 38 | rL = NULL; 39 | rA = NULL; 40 | rB = NULL; 41 | } 42 | /***************************************************************/ 43 | /* Function: ~BinaryStereo */ 44 | /* Usage: free class member variables */ 45 | /* In: */ 46 | /* Out: */ 47 | /***************************************************************/ 48 | BinaryStereo::~BinaryStereo(void) 49 | { 50 | if( pairDistr ) { 51 | delete [] pairDistr; 52 | } 53 | if( lCode ) { 54 | delete [] lCode; 55 | } 56 | if( rCode ) { 57 | delete [] rCode; 58 | } 59 | if( lUsed ) { 60 | delete [] lUsed; 61 | } 62 | if( rUsed ) { 63 | delete [] rUsed; 64 | } 65 | if( l_r ) { 66 | delete [] l_r; 67 | } 68 | if( l_g ) { 69 | delete [] l_g; 70 | } 71 | if( l_b ) { 72 | delete [] l_b; 73 | } 74 | if( r_r ) { 75 | delete [] r_r; 76 | } 77 | if( r_g ) { 78 | delete [] r_g; 79 | } 80 | if( r_b ) { 81 | delete [] r_b; 82 | } 83 | if( lL ) { 84 | delete [] lL; 85 | } 86 | if( lA ) { 87 | delete [] lA; 88 | } 89 | if( lB ) { 90 | delete [] lB; 91 | } 92 | if( rL ) { 93 | delete [] rL; 94 | } 95 | if( rA ) { 96 | delete [] rA; 97 | } 98 | if( rB ) { 99 | delete [] rB; 100 | } 101 | if( lIsEdge ) { 102 | delete [] lIsEdge; 103 | } 104 | if( rIsEdge ) { 105 | delete [] rIsEdge; 106 | } 107 | } 108 | /***************************************************************/ 109 | /* Function: BinaryStereo */ 110 | /* Usage: set image color data */ 111 | /* In: */ 112 | /* Out: */ 113 | /***************************************************************/ 114 | void BinaryStereo::setClrData() 115 | { 116 | 117 | l_b = new int[ imgSize ]; 118 | l_g = new int[ imgSize ]; 119 | l_r = new int[ imgSize ]; 120 | r_b = new int[ imgSize ]; 121 | r_g = new int[ imgSize ]; 122 | r_r = new int[ imgSize ]; 123 | l_gray = new int[ imgSize ]; 124 | r_gray = new int[ imgSize ]; 125 | lL = new double[ imgSize ]; 126 | lA = new double[ imgSize ]; 127 | lB = new double[ imgSize ]; 128 | rL = new double[ imgSize ]; 129 | rA = new double[ imgSize ]; 130 | rB = new double[ imgSize ]; 131 | 132 | 133 | double *plL, *plA, *plB, *prL, *prA, *prB; 134 | int *pl_b, *pl_g, *pl_r, *pr_b, *pr_g, *pr_r; 135 | int *pl_gray, *pr_gray; 136 | 137 | plL = lL; 138 | plA = lA; 139 | plB = lB; 140 | prL = rL; 141 | prA = rA; 142 | prB = rB; 143 | 144 | pl_b = l_b; 145 | pl_g = l_g; 146 | pl_r = l_r; 147 | pr_b = r_b; 148 | pr_g = r_g; 149 | pr_r = r_r; 150 | 151 | pl_gray = l_gray; 152 | pr_gray = r_gray; 153 | IplImage* lGray; 154 | IplImage* rGray; 155 | lGray = cvCreateImage( cvSize( width,height ), IPL_DEPTH_8U, 1 ); 156 | cvCvtColor( lClr, lGray, CV_BGR2GRAY ); 157 | rGray = cvCreateImage( cvSize( width, height ), IPL_DEPTH_8U, 1 ); 158 | cvCvtColor( rClr, rGray, CV_BGR2GRAY ); 159 | for( int y = 0; y < height; y ++ ) { 160 | uchar* gray1 = ( uchar* ) ( lGray->imageData 161 | + y * lGray->widthStep ); 162 | uchar* gray2 = ( uchar* ) ( rGray->imageData 163 | + y * rGray->widthStep ); 164 | 165 | for( int x = 0; x < width; x ++ ) { 166 | uchar* bgr1 = ( uchar* ) lClr->imageData 167 | + y * lClr->widthStep + 3 * x; 168 | 169 | uchar* bgr2 = ( uchar* ) rClr->imageData 170 | + y * rClr->widthStep + 3 * x; 171 | 172 | // BGR 173 | *pl_b = ( int ) ( bgr1[ 0 ] ); 174 | *pl_g = ( int ) ( bgr1[ 1 ] ); 175 | *pl_r = ( int ) ( bgr1[ 2 ] ); 176 | 177 | *pr_b = ( int ) ( bgr2[ 0 ] ); 178 | *pr_g = ( int ) ( bgr2[ 1 ] ); 179 | *pr_r = ( int ) ( bgr2[ 2 ] ); 180 | 181 | // GRAY 182 | *pl_gray = ( int ) ( gray1[ x ] ); 183 | *pr_gray = ( int ) ( gray2[ x ] ); 184 | 185 | // LAB 186 | // !!!!! computer use BGR NOT RGB !!!! 187 | RGBtoLab( *pl_b, *pl_g, *pl_r, 188 | *plL, *plA, *plB ); 189 | RGBtoLab( *pr_b, *pr_g, *pr_r, 190 | *prL, *prA, *prB ); 191 | 192 | // BGR 193 | pl_b ++; 194 | pl_g ++; 195 | pl_r ++; 196 | pr_b ++; 197 | pr_g ++; 198 | pr_r ++; 199 | //GRAY 200 | pl_gray ++; 201 | pr_gray ++; 202 | //LAB 203 | plL ++; 204 | plA ++; 205 | plB ++; 206 | prL ++; 207 | prA ++; 208 | prB ++; 209 | 210 | } 211 | } 212 | cvReleaseImage(&lGray); 213 | cvReleaseImage(&rGray); 214 | } 215 | /***************************************************************/ 216 | /* Function: setPairDistr */ 217 | /* Usage: set pixel pair distribution */ 218 | /* In: */ 219 | /* Out: */ 220 | /***************************************************************/ 221 | void BinaryStereo::setPairDistr() 222 | { 223 | srand( ( unsigned int )time( NULL ) ); 224 | 225 | int trial; 226 | int brd = patchSz /2; 227 | for (int i=0; i< 4 * descLen; i ++ ) { 228 | do { 229 | trial = int( RandNormal(gStd) ); 230 | } while ( trial < ( -brd ) || trial > ( brd ) ); 231 | pairDistr[i]=trial; 232 | } 233 | 234 | } 235 | /***************************************************************/ 236 | /* Function: setEdgeData */ 237 | /* Usage: set edge labels */ 238 | /* In: */ 239 | /* Out: */ 240 | /***************************************************************/ 241 | void BinaryStereo::setEdgeData() 242 | { 243 | IplImage* lGray = cvCreateImage( cvSize( width,height ), IPL_DEPTH_8U, 1 ); 244 | cvCvtColor( lClr, lGray, CV_BGR2GRAY ); 245 | IplImage* rGray = cvCreateImage( cvSize( width, height ), IPL_DEPTH_8U, 1 ); 246 | cvCvtColor( rClr, rGray, CV_BGR2GRAY ); 247 | double low, high; 248 | IplImage* lEdge = cvCreateImage( cvGetSize( lGray ), IPL_DEPTH_8U, 1 ); // edge image 249 | IplImage* rEdge = cvCreateImage( cvGetSize( rGray ), IPL_DEPTH_8U, 1 ); 250 | CvMat* dx = cvCreateMat( height, width, CV_16SC1 ); 251 | CvMat* dy = cvCreateMat( height, width, CV_16SC1 ); 252 | cvSobel( lGray, dx, 1, 0 ); 253 | cvSobel( lGray, dy, 0, 1 ); 254 | AdaptiveFindThreshold( dx, dy, &low, &high); 255 | cvCanny( lGray, lEdge, low, high ); // canny edge detection 256 | cvSobel( rGray, dx, 1, 0 ); 257 | cvSobel( rGray, dy, 0, 1 ); 258 | AdaptiveFindThreshold( dx, dy, &low, &high); 259 | cvCanny( rGray, rEdge, low, high ); 260 | cvReleaseMat( &dx ); 261 | cvReleaseMat( &dy ); 262 | 263 | // set edge data 264 | lIsEdge = new int[ imgSize ]; 265 | rIsEdge = new int[ imgSize ]; 266 | int ereaRadius = maxDis; 267 | // set left edge erea 268 | memset( lIsEdge, 0, imgSize * sizeof( int ) ); 269 | for( int y = 0; y < height; y ++ ) { 270 | uchar* lEdgeData = ( uchar* ) ( lEdge->imageData + y * lEdge->widthStep ); 271 | int* tempIsEdge = lIsEdge + y * width; 272 | for( int x = 0; x < width; x ++ ) { 273 | if( lEdgeData[ x ] == 255 ) { 274 | // just on the edge 275 | tempIsEdge[ x ] = 1; 276 | continue; 277 | } else { 278 | // if [ -e, e ] has edge define as edge erea 279 | for( int r = - ereaRadius; r <= ereaRadius; r++ ) { 280 | if( x + r < 0 || x + r >= width ) { 281 | // close to image edge 282 | tempIsEdge[ x ] = 1; 283 | break; 284 | } 285 | if( lEdgeData[ x + r ] == 255 ) { 286 | tempIsEdge[ x ] = 1; 287 | break; 288 | } 289 | } 290 | } 291 | if( tempIsEdge[ x ] == 1 ) { 292 | lEdgeData[ x ] = 128; 293 | } 294 | } 295 | } 296 | 297 | // set right edge erea 298 | memset( rIsEdge, 0, imgSize * sizeof( int ) ); 299 | for( int y = 0; y < height; y ++ ) { 300 | uchar* rEdgeData = ( uchar* ) ( rEdge->imageData + y * rEdge->widthStep ); 301 | int* tempIsEdge = rIsEdge + y * width; 302 | for( int x = 0; x < width; x ++ ) { 303 | if( rEdgeData[ x ] == 255 ) { 304 | // just on the edge 305 | tempIsEdge[ x ] = 1; 306 | continue; 307 | } else { 308 | // if [ -e, e ] has edge define as edge erea 309 | for( int r = - ereaRadius; r <= ereaRadius; r++ ) { 310 | if( x + r < 0 || x + r >= width ) { 311 | // close to image edge 312 | tempIsEdge[ x ] = 1; 313 | break; 314 | } 315 | if( rEdgeData[ x + r ] == 255 ) { 316 | tempIsEdge[ x ] = 1; 317 | break; 318 | } 319 | } 320 | } 321 | if( tempIsEdge[ x ] == 1 ) { 322 | rEdgeData[ x ] = 128; 323 | } 324 | } 325 | } 326 | cvReleaseImage(&lGray); 327 | cvReleaseImage(&rGray); 328 | cvReleaseImage(&lEdge); 329 | cvReleaseImage(&rEdge); 330 | } 331 | /***************************************************************/ 332 | /* Function: prepareUsed */ 333 | /* Usage: set binary mask */ 334 | /* In: */ 335 | /* Out: */ 336 | /***************************************************************/ 337 | void BinaryStereo::prepareUsed() 338 | { 339 | #ifdef OUTPUT_USED_WGT 340 | FILE* fp = fopen( "wgt.txt", "w" ); 341 | double sum = 0.0f; 342 | #endif 343 | int mask = patchSz / 2; 344 | lUsed = new bitset[ imgSize ]; 345 | rUsed = new bitset[ imgSize ]; 346 | int* testsLWgt = new int[ DESC_LEN ]; 347 | int* testsRWgt = new int[ DESC_LEN ]; 348 | int topMax = WGT_CNT; 349 | 350 | int lWgtCount[ WGT_CNT ]; 351 | int rWgtCount[ WGT_CNT ]; 352 | 353 | bitset* tempLUsed = lUsed; 354 | bitset* tempRUsed = rUsed; 355 | for( int y = 0; y < height; y ++ ) { 356 | for( int x = 0; x < width; x ++ ) { 357 | int index = y * width + x; 358 | memset( testsLWgt, 0, sizeof( int ) * DESC_LEN ); 359 | memset( testsRWgt, 0, sizeof( int ) * DESC_LEN ); 360 | 361 | memset( lWgtCount, 0, sizeof( int ) * WGT_CNT ); 362 | memset( rWgtCount, 0, sizeof( int ) * WGT_CNT ); 363 | int* xd1 = pairDistr; 364 | int* yd1 = pairDistr + 1; 365 | int* xd2 = pairDistr + 2; 366 | int* yd2 = pairDistr + 3; 367 | 368 | for( int i = 0; i < DESC_LEN; i ++ ) { 369 | int x1 = x + (*xd1); 370 | int y1 = y + (*yd1); 371 | int x2 = x + (*xd2); 372 | int y2 = y + (*yd2); 373 | 374 | if( x1 < 0 || x1 >= width ) { 375 | xd1 += 4; 376 | yd1 += 4; 377 | xd2 += 4; 378 | yd2 += 4; 379 | continue; 380 | } 381 | if( y1 < 0 || y1 >= height ) { 382 | xd1 += 4; 383 | yd1 += 4; 384 | xd2 += 4; 385 | yd2 += 4; 386 | continue; 387 | } 388 | if( x2 < 0 || x2 >= width ) { 389 | xd1 += 4; 390 | yd1 += 4; 391 | xd2 += 4; 392 | yd2 += 4; 393 | continue; 394 | } 395 | if( y2 < 0 || y2 >= height ) { 396 | xd1 += 4; 397 | yd1 += 4; 398 | xd2 += 4; 399 | yd2 += 4; 400 | continue; 401 | } 402 | 403 | int tempL, tempR; 404 | int index1 = y1 * width + x1; 405 | int index2 = y2 * width + x2; 406 | tempL = MAX( abs( lL[ index1 ] - lL[ index ] ) + 407 | abs( lA[ index1 ] - lA[ index ] ) + 408 | abs( lB[ index1 ] - lB[ index ] ), 409 | 410 | abs( lL[ index2 ] - lL[ index ] ) + 411 | abs( lA[ index2 ] - lA[ index ] ) + 412 | abs( lB[ index2 ] - lB[ index ] ) 413 | ); 414 | tempR = MAX( abs( rL[ index1 ] - rL[ index ] ) + 415 | abs( rA[ index1 ] - rA[ index ] ) + 416 | abs( rB[ index1 ] - rB[ index ] ), 417 | 418 | abs( rL[ index2 ] - rL[ index ] ) + 419 | abs( rA[ index2 ] - rA[ index ] ) + 420 | abs( rB[ index2 ] - rB[ index ] ) 421 | ); 422 | 423 | testsLWgt[ i ] = tempL; 424 | testsRWgt[ i ] = tempR; 425 | lWgtCount[ tempL ] ++; 426 | rWgtCount[ tempR ] ++; 427 | 428 | xd1 += 4; 429 | yd1 += 4; 430 | xd2 += 4; 431 | yd2 += 4; 432 | } 433 | int lMid = MyGetCutVal( lWgtCount ); 434 | #ifdef OUTPUT_USED_WGT 435 | sum += lMid; 436 | fprintf( fp, "%d\n", lMid ); 437 | #endif 438 | int rMid = MyGetCutVal( rWgtCount ); 439 | for( int i = 0; i < DESC_LEN; i ++ ) { 440 | if( testsLWgt[ i ] <= lMid ) { 441 | ( *tempLUsed )[ i ] = 1; 442 | } else { 443 | ( *tempLUsed )[ i ] = 0; 444 | } 445 | if( testsRWgt[ i ] <= rMid ) { 446 | ( *tempRUsed )[ i ] = 1; 447 | } else { 448 | ( *tempRUsed )[ i ] = 0; 449 | } 450 | 451 | } 452 | tempLUsed ++; 453 | tempRUsed ++; 454 | } 455 | } 456 | delete [] testsLWgt; 457 | delete [] testsRWgt; 458 | #ifdef OUTPUT_USED_WGT 459 | fprintf( fp, "\n%.4f\n", sum / imgSize ); 460 | fclose( fp ); 461 | #endif 462 | } 463 | /***************************************************************/ 464 | /* Function: prepareCode */ 465 | /* Usage: set descriptor */ 466 | /* In: */ 467 | /* Out: */ 468 | /***************************************************************/ 469 | void BinaryStereo::prepareCode() 470 | { 471 | int mask = patchSz / 2; 472 | int x1, y1, x2, y2; 473 | int index1, index2; 474 | lCode = new bitset[ imgSize ]; 475 | rCode = new bitset[ imgSize ]; 476 | bitset* tempLCode = lCode; 477 | bitset* tempRCode = rCode; 478 | for( int y = 0; y < height; y ++ ) { 479 | for( int x = 0; x < width; x ++ ) { 480 | int* xd1 = pairDistr; 481 | int* yd1 = pairDistr + 1; 482 | int* xd2 = pairDistr + 2; 483 | int* yd2 = pairDistr + 3; 484 | for( int i = 0; i < DESC_LEN; i ++ ) { 485 | x1 = x + (*xd1); 486 | y1 = y + (*yd1); 487 | x2 = x + (*xd2); 488 | y2 = y + (*yd2); 489 | 490 | // border check 491 | if( x1 < 0 || x1 >= width ) { 492 | ( *tempLCode )[ i ] = 0; 493 | ( *tempRCode )[ i ] = 1; 494 | xd1 += 4; 495 | yd1 += 4; 496 | xd2 += 4; 497 | yd2 += 4; 498 | continue; 499 | } 500 | if( y1 < 0 || y1 >= height ) { 501 | ( *tempLCode )[ i ] = 0; 502 | ( *tempRCode )[ i ] = 1; 503 | xd1 += 4; 504 | yd1 += 4; 505 | xd2 += 4; 506 | yd2 += 4; 507 | continue; 508 | } 509 | if( x2 < 0 || x2 >= width ) { 510 | ( *tempLCode )[ i ] = 0; 511 | ( *tempRCode )[ i ] = 1; 512 | xd1 += 4; 513 | yd1 += 4; 514 | xd2 += 4; 515 | yd2 += 4; 516 | continue; 517 | } 518 | if( y2 < 0 || y2 >= height ) { 519 | ( *tempLCode )[ i ] = 0; 520 | ( *tempRCode )[ i ] = 1; 521 | xd1 += 4; 522 | yd1 += 4; 523 | xd2 += 4; 524 | yd2 += 4; 525 | continue; 526 | } 527 | index1 = y1 * width + x1; 528 | index2 = y2 * width + x2; 529 | (*tempLCode)[ i ] = ( l_gray[ index1 ] > l_gray[ index2 ] ); 530 | (*tempRCode)[ i ] = ( r_gray[ index1 ] > r_gray[ index2 ] ); 531 | xd1 += 4; 532 | yd1 += 4; 533 | xd2 += 4; 534 | yd2 += 4; 535 | } 536 | tempLCode ++; 537 | tempRCode ++; 538 | } 539 | } 540 | } 541 | /***************************************************************/ 542 | /* Function: PreProcess */ 543 | /* Usage: prepare data for stereo matching */ 544 | /* In: */ 545 | /* Out: */ 546 | /***************************************************************/ 547 | void BinaryStereo::PreProcess() 548 | { 549 | setClrData(); 550 | setPairDistr(); 551 | setEdgeData(); 552 | prepareUsed(); 553 | prepareCode(); 554 | } 555 | /***************************************************************/ 556 | /* Function: Match */ 557 | /* Usage: binary stereo matching */ 558 | /* In: */ 559 | /* Out: */ 560 | /***************************************************************/ 561 | void BinaryStereo::Match() 562 | { 563 | bitset lB; 564 | bitset rB; 565 | bitset lU; 566 | bitset rU; 567 | bitset allUsed; 568 | bitset* tempLCode = lCode; 569 | bitset* tempRCode = rCode; 570 | bitset* tempLUsed = lUsed; 571 | bitset* tempRUsed = rUsed; 572 | 573 | int isUseful = descLen / 16; 574 | 575 | int xST = 0; 576 | int xED = width; 577 | int yST = 0; 578 | int yED = height; 579 | #ifdef MATCH_SMALL 580 | xST = X_START; 581 | xED = X_END; 582 | yST = Y_START; 583 | yED = Y_END; 584 | #endif 585 | // calc left depth 586 | for( int y = yST; y < yED; y ++ ) { 587 | uchar* dData = ( uchar* )lDis->imageData + y * lDis->widthStep; 588 | int index = y * width; 589 | for( int x = xST; x < xED; x ++ ) { 590 | int minDiff = descLen; 591 | int minDiffCount = -1; 592 | int matchDis = 0; 593 | int isEdge = lIsEdge[ index + x ]; 594 | 595 | lU = ( *tempLUsed ); 596 | lB = ( *tempLCode ); 597 | 598 | for( int d = 0; d < maxDis; d ++ ) { 599 | if( x - d >= 0 ) { 600 | rB = rCode[ index + x - d ]; 601 | rU = rUsed[ index + x - d ]; 602 | int diff = 0; 603 | int diffCount = 0; 604 | 605 | if( isEdge ){ 606 | // use binary mask only for edge 607 | diff = ( lU & ( lB ^ rB ) ).count( ); 608 | diffCount = lU.count(); 609 | } else { 610 | diff = ( lB ^ rB ).count(); 611 | diffCount = DESC_LEN; 612 | } 613 | 614 | if( diffCount > isUseful ) { 615 | if( diff < minDiff ) { 616 | // record top min diff 617 | minDiff = diff; 618 | minDiffCount = diffCount; 619 | matchDis = d; 620 | } 621 | } 622 | } 623 | } 624 | dData[ x ] = matchDis * disScale; 625 | tempLCode ++; 626 | tempLUsed ++; 627 | } 628 | } 629 | // calc right depth 630 | for( int y = yST; y < yED; y ++ ) { 631 | uchar* dData = ( uchar* )rDis->imageData + y * rDis->widthStep; 632 | int index = y * width; 633 | for( int x = xST; x < xED; x ++ ) { 634 | int minDiff = descLen; 635 | int minDiffCount = -1; 636 | int matchDis = 0; 637 | int isEdge = rIsEdge[ index + x ]; 638 | 639 | rU = ( *tempRUsed ); 640 | rB = ( *tempRCode ); 641 | for( int d = 0; d < maxDis; d ++ ) { 642 | if( x + d < width ) { 643 | // match distribution 644 | lB = lCode[ index + x + d ]; 645 | lU = lUsed[ index + x + d ]; 646 | 647 | int diff = 0; 648 | int diffCount = 0; 649 | 650 | 651 | if( isEdge ){ 652 | diff = ( rU & ( lB ^ rB ) ).count( ); 653 | diffCount = rU.count(); 654 | } else { 655 | diff = ( lB ^ rB ).count(); 656 | diffCount = DESC_LEN; 657 | } 658 | 659 | if( diffCount > isUseful ) { 660 | if( diff < minDiff ) { 661 | // record top min diff 662 | minDiff = diff; 663 | minDiffCount = diffCount; 664 | matchDis = d; 665 | } 666 | } 667 | } 668 | } 669 | dData[ x ] = matchDis * disScale; 670 | tempRCode ++; 671 | tempRUsed ++; 672 | } 673 | } 674 | 675 | } 676 | /***************************************************************/ 677 | /* Function: PostProcess */ 678 | /* Usage: currently implement by Weidong Hu */ 679 | /* In: */ 680 | /* Out: */ 681 | /***************************************************************/ 682 | void BinaryStereo::PostProcess() 683 | { 684 | // using post processing program 685 | } -------------------------------------------------------------------------------- /BinaryStereo.h: -------------------------------------------------------------------------------- 1 | /***************************************************************/ 2 | /* File: BinaryStereo.h */ 3 | /* Usage: header file for BinaryStereo Class */ 4 | /* Author: Zhang Kang */ 5 | /* Date: */ 6 | /***************************************************************/ 7 | #pragma once 8 | #include "IStereoAlg.h" 9 | #include 10 | using namespace std; 11 | 12 | #define DESC_LEN 4096 // descriptor length 13 | #define PATCH_SZ 26 // patch size for descriptor 14 | 15 | class BinaryStereo : public IStereoAlg 16 | { 17 | public: 18 | int descLen; // descriptor length 19 | int patchSz; // patch size for descriptor 20 | int* pairDistr; // pixel pairs [x1,y1,x2,y2,...xn,yn,xn+1,yn+1] 21 | double gStd; // gaussian standard for sampling pixel pairs 22 | 23 | bitset* lCode; // descriptor for left&right images 24 | bitset* rCode; 25 | bitset* lUsed; // binary mask for left&right images 26 | bitset* rUsed; 27 | int* l_r; // image data 28 | int* l_g; 29 | int* l_b; 30 | int* r_r; 31 | int* r_g; 32 | int* r_b; 33 | int* l_gray; 34 | int* r_gray; 35 | double* lL; 36 | double* lA; 37 | double* lB; 38 | double* rL; 39 | double* rA; 40 | double* rB; 41 | 42 | int* lIsEdge; // edge detecting label 43 | int* rIsEdge; 44 | public: 45 | BinaryStereo(const int pS, const int mD, const int dS); 46 | ~BinaryStereo(void); 47 | public: 48 | // initial member variables 49 | void setClrData(); 50 | void setPairDistr(); 51 | void setEdgeData(); 52 | void prepareUsed(); 53 | void prepareCode(); 54 | public : 55 | // implement IStereoAlg interface 56 | virtual void PreProcess(); 57 | virtual void Match(); 58 | virtual void PostProcess(); 59 | }; 60 | -------------------------------------------------------------------------------- /CommonFunc.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************/ 2 | /* File: CommonFunc.cpp */ 3 | /* Usage: implement common functions */ 4 | /* Author: Zhang Kang */ 5 | /* Date: */ 6 | /***************************************************************/ 7 | #include 8 | #include 9 | #include "BinaryStereo.h" 10 | #include "CommonFunc.h" 11 | #include 12 | 13 | double F(double input) 14 | { 15 | if(input>0.008856) 16 | return (pow(input, 0.333333333)); 17 | else 18 | return (7.787*input+0.137931034); 19 | } 20 | 21 | 22 | // RGB -> XYZ 23 | void RGBtoXYZ(double R, double G, double B, double &X, double &Y, double &Z) 24 | { 25 | X=0.412453*R+0.357580*G+0.189423*B; 26 | Y=0.212671*R+0.715160*G+0.072169*B; 27 | Z=0.019334*R+0.119193*G+0.950227*B; 28 | } 29 | 30 | 31 | // XYZ -> CIELab 32 | void XYZtoLab(double X, double Y, double Z, double &L, double &a, double &b) 33 | { 34 | const double Xo=244.66128; 35 | const double Yo=255.0; 36 | const double Zo=277.63227; 37 | L=116*F(Y/Yo)-16; 38 | a=500*(F(X/Xo)-F(Y/Yo)); 39 | b=200*(F(Y/Yo)-F(Z/Zo)); 40 | } 41 | 42 | // RGB -> CIELab 43 | void RGBtoLab(double R, double G, double B, double &L, double &a, double &b) 44 | { 45 | double X, Y, Z; 46 | RGBtoXYZ(R, G, B, X, Y, Z); 47 | XYZtoLab(X, Y, Z, L, a, b); 48 | } 49 | 50 | // generate gaussian distribution 51 | CvRNG rngSeed = cvRNG( 23 ); // 23 52 | double RandNormal( const double std, const double mu ) 53 | { 54 | double x1, x2, w, y1; 55 | static double y2; 56 | static bool use_last = false; 57 | 58 | if (use_last) /* use value from previous call */ 59 | { 60 | y1 = y2; 61 | use_last = false; 62 | } 63 | else 64 | { 65 | do { 66 | //double t1 = ( double )rand( ) / RAND_MAX; 67 | //double t2 = ( double )rand( ) / RAND_MAX; 68 | x1 = 2.0 * cvRandReal( &rngSeed ) - 1.0; 69 | x2 = 2.0 * cvRandReal( &rngSeed ) - 1.0; 70 | //x1 = 2.0 * t1 - 1.0; 71 | //x2 = 2.0 * t2 - 1.0; 72 | w = x1 * x1 + x2 * x2; 73 | } while ( w >= 1.0 ); 74 | 75 | w = sqrt( (-2.0 * log( w ) ) / w ); 76 | y1 = x1 * w; 77 | y2 = x2 * w; 78 | use_last = true; 79 | } 80 | 81 | return mu + y1 * std; 82 | } 83 | 84 | 85 | // get 1 / 4 value 86 | int MyGetCutVal(int* wgtCnt) 87 | { 88 | int perLen = DESC_LEN / 4; 89 | int count = 0; 90 | for( int i = 0; i < WGT_CNT; i ++ ) { 91 | count += wgtCnt[ i ]; 92 | if( count > perLen ) { 93 | //if( i > CLR_WGT_THRES ) { 94 | // return i; 95 | //} else { 96 | // return CLR_WGT_THRES; 97 | //} 98 | return i; 99 | } 100 | } 101 | // return CLR_WGT_THRES; 102 | } 103 | // adaptive threshold for canny edge detecotr 104 | void AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high) 105 | { 106 | CvSize size; 107 | IplImage *imge=0; 108 | int i,j; 109 | CvHistogram *hist; 110 | int hist_size = 255; 111 | float range_0[]={0,256}; 112 | float* ranges[] = { range_0 }; 113 | double PercentOfPixelsNotEdges = 0.7; 114 | size = cvGetSize(dx); 115 | imge = cvCreateImage(size, IPL_DEPTH_32F, 1); 116 | float maxv = 0; 117 | for(i = 0; i < size.height; i++ ) 118 | { 119 | const short* _dx = (short*)(dx->data.ptr + dx->step*i); 120 | const short* _dy = (short*)(dy->data.ptr + dy->step*i); 121 | float* _image = (float *)(imge->imageData + imge->widthStep*i); 122 | for(j = 0; j < size.width; j++) 123 | { 124 | _image[j] = (float)(abs(_dx[j]) + abs(_dy[j])); 125 | maxv = maxv < _image[j] ? _image[j]: maxv; 126 | } 127 | } 128 | 129 | range_0[1] = maxv; 130 | hist_size = (int)(hist_size > maxv ? maxv:hist_size); 131 | hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1); 132 | cvCalcHist( &imge, hist, 0, NULL ); 133 | int total = (int)(size.height * size.width * PercentOfPixelsNotEdges); 134 | float sum=0; 135 | int icount = hist->mat.dim[0].size; 136 | 137 | float *h = (float*)cvPtr1D( hist->bins, 0 ); 138 | for(i = 0; i < icount; i++) 139 | { 140 | sum += h[i]; 141 | if( sum > total ) 142 | break; 143 | } 144 | 145 | *high = (i+1) * maxv / hist_size ; 146 | *low = *high * 0.4; 147 | cvReleaseImage( &imge ); 148 | cvReleaseHist(&hist); 149 | } -------------------------------------------------------------------------------- /CommonFunc.h: -------------------------------------------------------------------------------- 1 | /***************************************************************/ 2 | /* File: CommonFunc.h */ 3 | /* Usage: header file for common functions */ 4 | /* Author: Zhang Kang */ 5 | /* Date: */ 6 | /***************************************************************/ 7 | #pragma once 8 | 9 | // RGB->LAB 10 | inline double F(double input); 11 | void RGBtoXYZ(double R, double G, double B, double &X, double &Y, double &Z); 12 | void XYZtoLab(double X, double Y, double Z, double &L, double &a, double &b); 13 | void RGBtoLab(double R, double G, double B, double &L, double &a, double &b); 14 | 15 | // generate gaussian distribution 16 | double RandNormal( const double std, const double mu = 0.0f ); 17 | // get 1 / 4 value 18 | #define WGT_CNT 768 19 | #define CLR_WGT_THRES 768 20 | int MyGetCutVal( int* wgtCnt ); 21 | // adaptive threshold for canny edge detecotr 22 | void AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high); -------------------------------------------------------------------------------- /IStereoAlg.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************/ 2 | /* File: IStereoAlg.cpp */ 3 | /* Usage: basic methods for stereo matching */ 4 | /* Author: Zhang Kang */ 5 | /* Date: */ 6 | /***************************************************************/ 7 | #include "IStereoAlg.h" 8 | 9 | /***************************************************************/ 10 | /* Function: IStereoAlg */ 11 | /* Usage: initial class member variables */ 12 | /* In: */ 13 | /* const int mD - disparity levels */ 14 | /* const int dS - disparity scale */ 15 | /* Out: */ 16 | /***************************************************************/ 17 | IStereoAlg::IStereoAlg(const int mD, const int dS) 18 | { 19 | width = 0; 20 | height = 0; 21 | imgSize = 0; 22 | lClr = NULL; 23 | rClr = NULL; 24 | lDis = NULL; 25 | rDis = NULL; 26 | maxDis = mD; 27 | disScale = dS; 28 | } 29 | /***************************************************************/ 30 | /* Function: ~IStereoAlg */ 31 | /* Usage: free class member variables */ 32 | /* In: */ 33 | /* Out: */ 34 | /***************************************************************/ 35 | IStereoAlg::~IStereoAlg(void) 36 | { 37 | if( lClr ) { 38 | cvReleaseImage(&lClr); 39 | } 40 | if( rClr ) { 41 | cvReleaseImage(&rClr); 42 | } 43 | if( lDis ) { 44 | cvReleaseImage(&lDis); 45 | } 46 | if( rDis ) { 47 | cvReleaseImage(&rDis); 48 | } 49 | } 50 | 51 | /***************************************************************/ 52 | /* Function: LoadImage */ 53 | /* Usage: loading left&right images */ 54 | /* In: */ 55 | /* const char *lFn - left image file name */ 56 | /* const char *rFn - right image file name */ 57 | /* Out: */ 58 | /***************************************************************/ 59 | void IStereoAlg::LoadImg(const char *lFn, const char *rFn) 60 | { 61 | lClr = cvLoadImage( lFn, CV_LOAD_IMAGE_COLOR ); 62 | rClr = cvLoadImage( rFn, CV_LOAD_IMAGE_COLOR ); 63 | 64 | width = lClr->width; 65 | height = lClr->height; 66 | imgSize = width * height; 67 | 68 | // create depth map 69 | lDis = cvCreateImage( cvSize( width, height ), IPL_DEPTH_8U, 1 ); 70 | cvZero( lDis ); 71 | rDis = cvCreateImage( cvSize( width, height ), IPL_DEPTH_8U, 1 ); 72 | cvZero( rDis ); 73 | } 74 | /***************************************************************/ 75 | /* Function: SaveDep */ 76 | /* Usage: save left&right depth maps */ 77 | /* In: */ 78 | /* const char *lFn - left depth file name */ 79 | /* const char *rFn - right depth file name */ 80 | /* Out: */ 81 | /***************************************************************/ 82 | void IStereoAlg::SaveDep(const char* lFn, const char* rFn) 83 | { 84 | cvSaveImage(lFn,lDis); 85 | cvSaveImage(rFn,rDis); 86 | } -------------------------------------------------------------------------------- /IStereoAlg.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rookiepig/BinaryStereo/86aced75fb9ffbb6c7c63d6006a31feb1f6451f4/IStereoAlg.h -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Zhang Kang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ########LIBRAIRIES 2 | LIBS_ffmpeg = -lm -lz -lpthread -lavformat -lavcodec -lavutil 3 | 4 | LIBS_opencv = -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_video -lopencv_objdetect 5 | 6 | LIBS_autres = -lpthread -ldl -lm 7 | 8 | LIBS = $(LIBS_autres) $(LIBS_ffmpeg) $(LIBS_opencv) 9 | 10 | ########CONSTANTES 11 | CXXFLAGS = -O2 -g -Wall -fmessage-length=0 -D__STDC_CONSTANT_MACROS 12 | OBJS = main.o CommonFunc.o IStereoAlg.o BinaryStereo.o 13 | TARGET = main 14 | 15 | ########REGLES 16 | $(TARGET): $(OBJS) 17 | $(CXX) -o $(TARGET) $(OBJS) $(LIBS) 18 | 19 | %.o: %.cpp 20 | $(CXX) -o $@ -c $< $(CXXFLAGS) $(LIBS) 21 | 22 | all: $(TARGET) 23 | 24 | clean: 25 | rm -f $(OBJS) $(TARGET) 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BinaryStereo 2 | ============ 3 | 4 | Binary Stereo Matching ICPR 2012 5 | 6 | A fast binary stereo matching algorithm. To run the code, put all files into a single project or makefile. The only 3rd-party dependency is [OpenCV](http://opencv.org/). 7 | 8 | **Note: a simple Makefile has been added so that you can compile the project by make once OpenCV is configured on Linux/Unix platform.** 9 | 10 | If you utilize the code, please cite the original paper: 11 | 12 | **Kang Zhang**, Jiyang Li, Yijing Li, Weidong Hu, Lifeng Sun, Shiqiang Yang. _"Binary Stereo Matching"_, 21st International Conference on Pattern Recognition (ICPR). 2012 13 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************/ 2 | /* File: main.cpp */ 3 | /* Usage: mian entrance for stereo matching benchmark */ 4 | /* Author: Zhang Kang */ 5 | /* Date: */ 6 | /***************************************************************/ 7 | #ifdef _WDINDOWS_ 8 | #include 9 | #elif _linux_ 10 | #include 11 | #endif 12 | #include 13 | #include "IStereoAlg.h" 14 | #include "BinaryStereo.h" 15 | #include 16 | #include 17 | using namespace std; 18 | 19 | enum StereoAlg{ 20 | BSM, 21 | AdaptWgt 22 | }; 23 | 24 | map algMap; // algorithm name mapping 25 | 26 | 27 | 28 | void InitAlgMap() 29 | { 30 | algMap[string("BSM")]=BSM; 31 | algMap[string("AdaptWgt")]=AdaptWgt; 32 | } 33 | 34 | // Usage: [lImg] [rImg] [lDis] [rDis] [method] [maxDis] [disScale] 35 | int main( int argc, char** argv ) 36 | { 37 | if( argc != 8 ) { 38 | printf( "Usage: [lImg] [rImg] [lDis] [rDis] [method] [maxDis] [disScale]\n"); 39 | return -1; 40 | } 41 | 42 | string lImg(argv[1]), rImg(argv[2]); 43 | string lDis(argv[3]), rDis(argv[4]); 44 | string method(argv[5]); 45 | int maxDis = atoi(argv[6]); 46 | int disScale = atoi(argv[7]); 47 | 48 | InitAlgMap(); 49 | // decide algorithm 50 | map::iterator p = algMap.find(method); 51 | if( p != algMap.end() ) { 52 | IStereoAlg* matcher = NULL; 53 | switch(p->second) { 54 | case BSM : 55 | matcher = new BinaryStereo(PATCH_SZ,maxDis,disScale); 56 | break; 57 | case AdaptWgt : 58 | break; 59 | } 60 | 61 | #ifdef _WDINDOWS_ 62 | DWORD st,ed; 63 | st=GetTickCount(); 64 | #elif _linux_ 65 | struct timespec ts; 66 | if(clock_gettime(CLOCK_MONOTONIC,&ts) != 0) { 67 | //error 68 | printf( "Error: get time!\n" ); 69 | return - 1; 70 | } 71 | #endif 72 | // print info 73 | printf("\n--------------------------------------\n"); 74 | printf( "Files:\n%s\n%s\n", lImg.c_str(),rImg.c_str()); 75 | printf( "Method: %s\n", method.c_str()); 76 | 77 | matcher->LoadImg(lImg.c_str(),rImg.c_str()); 78 | printf("Load-->"); 79 | 80 | matcher->PreProcess(); 81 | printf("PreProcss-->"); 82 | 83 | matcher->Match(); 84 | printf("Match-->"); 85 | 86 | matcher->SaveDep(lDis.c_str(),rDis.c_str()); 87 | printf("Save\n"); 88 | #ifdef _WDINDOWS_ 89 | ed=GetTickCount(); 90 | printf("Total Time : %ld ms\n", ed - st); 91 | #elif _linux_ 92 | struct timespec te; 93 | if(clock_gettime(CLOCK_MONOTONIC,&te) != 0) { 94 | //error 95 | printf( "Error: get time!\n" ); 96 | return - 1; 97 | } 98 | long tmp = ts.tv_sec * 1000 + ts.tv_nsec / 1000000 99 | - te.tv_sec * 1000 - te.tv_nsec / 1000000; 100 | printf("Total Time : %lds\n", tmp / 1000 ); 101 | #endif 102 | printf("--------------------------------------\n"); 103 | } else { 104 | printf( "Algorithm not implented!\n" ); 105 | return -1; 106 | } 107 | return 0; 108 | } 109 | --------------------------------------------------------------------------------