dpstereo.cpp 18.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

/****************************************************************************************\
    The code below is some modification of Stan Birchfield's algorithm described in:

    Depth Discontinuities by Pixel-to-Pixel Stereo
    Stan Birchfield and Carlo Tomasi
    International Journal of Computer Vision,
    35(3): 269-293, December 1999.
51

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    This implementation uses different cost function that results in
    O(pixPerRow*maxDisparity) complexity of dynamic programming stage versus
    O(pixPerRow*log(pixPerRow)*maxDisparity) in the above paper.
\****************************************************************************************/

/****************************************************************************************\
*       Find stereo correspondence by dynamic programming algorithm                      *
\****************************************************************************************/
#define ICV_DP_STEP_LEFT  0
#define ICV_DP_STEP_UP    1
#define ICV_DP_STEP_DIAG  2

#define ICV_BIRCH_DIFF_LUM 5

#define ICV_MAX_DP_SUM_VAL (INT_MAX/4)

typedef struct _CvDPCell
{
    uchar  step; //local-optimal step
71
    int    sum;  //current sum
72 73 74 75 76 77 78
}_CvDPCell;

typedef struct _CvRightImData
{
    uchar min_val, max_val;
} _CvRightImData;

79 80
#define CV_IMAX3(a,b,c) (std::max(std::max((a), (b)), (c)))
#define CV_IMIN3(a,b,c) (std::min(std::min((a), (b)), (c)))
81

82
static void icvFindStereoCorrespondenceByBirchfieldDP( uchar* src1, uchar* src2,
83 84
                                                uchar* disparities,
                                                CvSize size, int widthStep,
85 86
                                                int    maxDisparity,
                                                float  _param1, float _param2,
87 88 89
                                                float  _param3, float _param4,
                                                float  _param5 )
{
90
    int     x, y, i, j;
91
    int     d, s;
92
    int     dispH =  maxDisparity + 3;
93 94 95 96 97 98 99 100 101 102 103 104 105
    uchar  *dispdata;
    int     imgW = size.width;
    int     imgH = size.height;
    uchar   val, prevval, prev, curr;
    int     min_val;
    uchar*  dest = disparities;
    int param1 = cvRound(_param1);
    int param2 = cvRound(_param2);
    int param3 = cvRound(_param3);
    int param4 = cvRound(_param4);
    int param5 = cvRound(_param5);

    #define CELL(d,x)   cells[(d)+(x)*dispH]
106

107 108 109 110 111
    uchar*              dsi = (uchar*)cvAlloc(sizeof(uchar)*imgW*dispH);
    uchar*              edges = (uchar*)cvAlloc(sizeof(uchar)*imgW*imgH);
    _CvDPCell*          cells = (_CvDPCell*)cvAlloc(sizeof(_CvDPCell)*imgW*MAX(dispH,(imgH+1)/2));
    _CvRightImData*     rData = (_CvRightImData*)cvAlloc(sizeof(_CvRightImData)*imgW);
    int*                reliabilities = (int*)cells;
112 113 114

    for( y = 0; y < imgH; y++ )
    {
115
        uchar* srcdata1 = src1 + widthStep * y;
116
        uchar* srcdata2 = src2 + widthStep * y;
117 118 119 120

        //init rData
        prevval = prev = srcdata2[0];
        for( j = 1; j < imgW; j++ )
121
        {
122 123 124 125 126 127 128 129 130 131 132
            curr = srcdata2[j];
            val = (uchar)((curr + prev)>>1);
            rData[j-1].max_val = (uchar)CV_IMAX3( val, prevval, prev );
            rData[j-1].min_val = (uchar)CV_IMIN3( val, prevval, prev );
            prevval = val;
            prev = curr;
        }
        rData[j-1] = rData[j-2];//last elem

        // fill dissimularity space image
        for( i = 1; i <= maxDisparity + 1; i++ )
133
        {
134 135 136
            dsi += imgW;
            rData--;
            for( j = i - 1; j < imgW - 1; j++ )
137 138
            {
                int t;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
                if( (t = srcdata1[j] - rData[j+1].max_val) >= 0 )
                {
                    dsi[j] = (uchar)t;
                }
                else if( (t = rData[j+1].min_val - srcdata1[j]) >= 0 )
                {
                    dsi[j] = (uchar)t;
                }
                else
                {
                    dsi[j] = 0;
                }
            }
        }
        dsi -= (maxDisparity+1)*imgW;
        rData += maxDisparity+1;

        //intensity gradients image construction
        //left row
        edges[y*imgW] = edges[y*imgW+1] = edges[y*imgW+2] = 2;
        edges[y*imgW+imgW-1] = edges[y*imgW+imgW-2] = edges[y*imgW+imgW-3] = 1;
        for( j = 3; j < imgW-4; j++ )
        {
            edges[y*imgW+j] = 0;
163 164

            if( ( CV_IMAX3( srcdata1[j-3], srcdata1[j-2], srcdata1[j-1] ) -
165 166 167 168
                  CV_IMIN3( srcdata1[j-3], srcdata1[j-2], srcdata1[j-1] ) ) >= ICV_BIRCH_DIFF_LUM )
            {
                edges[y*imgW+j] |= 1;
            }
169
            if( ( CV_IMAX3( srcdata2[j+3], srcdata2[j+2], srcdata2[j+1] ) -
170 171 172
                  CV_IMIN3( srcdata2[j+3], srcdata2[j+2], srcdata2[j+1] ) ) >= ICV_BIRCH_DIFF_LUM )
            {
                edges[y*imgW+j] |= 2;
173 174
            }
        }
175 176 177

        //find correspondence using dynamical programming
        //init DP table
178
        for( x = 0; x < imgW; x++ )
179 180 181 182
        {
            CELL(0,x).sum = CELL(dispH-1,x).sum = ICV_MAX_DP_SUM_VAL;
            CELL(0,x).step = CELL(dispH-1,x).step = ICV_DP_STEP_LEFT;
        }
183
        for( d = 2; d < dispH; d++ )
184 185 186
        {
            CELL(d,d-2).sum = ICV_MAX_DP_SUM_VAL;
            CELL(d,d-2).step = ICV_DP_STEP_UP;
187
        }
188 189 190 191
        CELL(1,0).sum  = 0;
        CELL(1,0).step = ICV_DP_STEP_LEFT;

        for( x = 1; x < imgW; x++ )
192 193
        {
            int dp = MIN( x + 1, maxDisparity + 1);
194 195 196 197 198 199
            uchar* _edges = edges + y*imgW + x;
            int e0 = _edges[0] & 1;
            _CvDPCell* _cell = cells + x*dispH;

            do
            {
200
                int _s = dsi[dp*imgW+x];
201 202 203
                int sum[3];

                //check left step
204
                sum[0] = _cell[dp-dispH].sum - param2;
205 206

                //check up step
207
                if( _cell[dp+1].step != ICV_DP_STEP_DIAG && e0 )
208
                {
209
                    sum[1] = _cell[dp+1].sum + param1;
210

211
                    if( _cell[dp-1-dispH].step != ICV_DP_STEP_UP && (_edges[1-dp] & 2) )
212 213
                    {
                        int t;
214 215

                        sum[2] = _cell[dp-1-dispH].sum + param1;
216 217 218 219 220 221

                        t = sum[1] < sum[0];

                        //choose local-optimal pass
                        if( sum[t] <= sum[2] )
                        {
222 223
                            _cell[dp].step = (uchar)t;
                            _cell[dp].sum = sum[t] + _s;
224 225
                        }
                        else
226 227 228
                        {
                            _cell[dp].step = ICV_DP_STEP_DIAG;
                            _cell[dp].sum = sum[2] + _s;
229 230 231 232 233 234
                        }
                    }
                    else
                    {
                        if( sum[0] <= sum[1] )
                        {
235 236
                            _cell[dp].step = ICV_DP_STEP_LEFT;
                            _cell[dp].sum = sum[0] + _s;
237 238 239
                        }
                        else
                        {
240 241
                            _cell[dp].step = ICV_DP_STEP_UP;
                            _cell[dp].sum = sum[1] + _s;
242 243 244
                        }
                    }
                }
245
                else if( _cell[dp-1-dispH].step != ICV_DP_STEP_UP && (_edges[1-dp] & 2) )
246
                {
247
                    sum[2] = _cell[dp-1-dispH].sum + param1;
248 249
                    if( sum[0] <= sum[2] )
                    {
250 251
                        _cell[dp].step = ICV_DP_STEP_LEFT;
                        _cell[dp].sum = sum[0] + _s;
252 253 254
                    }
                    else
                    {
255 256
                        _cell[dp].step = ICV_DP_STEP_DIAG;
                        _cell[dp].sum = sum[2] + _s;
257 258 259 260
                    }
                }
                else
                {
261 262
                    _cell[dp].step = ICV_DP_STEP_LEFT;
                    _cell[dp].sum = sum[0] + _s;
263 264
                }
            }
265
            while( --dp );
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
        }// for x

        //extract optimal way and fill disparity image
        dispdata = dest + widthStep * y;

        //find min_val
        min_val = ICV_MAX_DP_SUM_VAL;
        for( i = 1; i <= maxDisparity + 1; i++ )
        {
            if( min_val > CELL(i,imgW-1).sum )
            {
                d = i;
                min_val = CELL(i,imgW-1).sum;
            }
        }
281

282 283
        //track optimal pass
        for( x = imgW - 1; x > 0; x-- )
284
        {
285 286 287 288 289
            dispdata[x] = (uchar)(d - 1);
            while( CELL(d,x).step == ICV_DP_STEP_UP ) d++;
            if ( CELL(d,x).step == ICV_DP_STEP_DIAG )
            {
                s = x;
290
                while( CELL(d,x).step == ICV_DP_STEP_DIAG )
291
                {
292 293
                    d--;
                    x--;
294 295 296 297
                }
                for( i = x; i < s; i++ )
                {
                    dispdata[i] = (uchar)(d-1);
298 299
                }
            }
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
        }//for x
    }// for y

    //Postprocessing the Disparity Map

    //remove obvious errors in the disparity map
    for( x = 0; x < imgW; x++ )
    {
        for( y = 1; y < imgH - 1; y++ )
        {
            if( dest[(y-1)*widthStep+x] == dest[(y+1)*widthStep+x] )
            {
                dest[y*widthStep+x] = dest[(y-1)*widthStep+x];
            }
        }
    }

    //compute intensity Y-gradients
    for( x = 0; x < imgW; x++ )
    {
        for( y = 1; y < imgH - 1; y++ )
        {
322 323 324
            if( ( CV_IMAX3( src1[(y-1)*widthStep+x], src1[y*widthStep+x],
                        src1[(y+1)*widthStep+x] ) -
                  CV_IMIN3( src1[(y-1)*widthStep+x], src1[y*widthStep+x],
325 326 327 328 329 330 331 332 333 334
                        src1[(y+1)*widthStep+x] ) ) >= ICV_BIRCH_DIFF_LUM )
            {
                edges[y*imgW+x] |= 4;
                edges[(y+1)*imgW+x] |= 4;
                edges[(y-1)*imgW+x] |= 4;
                y++;
            }
        }
    }

335
    //remove along any particular row, every gradient
336 337 338 339 340 341
    //for which two adjacent columns do not agree.
    for( y = 0; y < imgH; y++ )
    {
        prev = edges[y*imgW];
        for( x = 1; x < imgW - 1; x++ )
        {
342
            curr = edges[y*imgW+x];
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
            if( (curr & 4) &&
                ( !( prev & 4 ) ||
                  !( edges[y*imgW+x+1] & 4 ) ) )
            {
                edges[y*imgW+x] -= 4;
            }
            prev = curr;
        }
    }

    // define reliability
    for( x = 0; x < imgW; x++ )
    {
        for( y = 1; y < imgH; y++ )
        {
            i = y - 1;
            for( ; y < imgH && dest[y*widthStep+x] == dest[(y-1)*widthStep+x]; y++ )
                ;
            s = y - i;
            for( ; i < y; i++ )
363
            {
364
                reliabilities[i*imgW+x] = s;
365
            }
366
        }
367 368 369
    }

    //Y - propagate reliable regions
370
    for( x = 0; x < imgW; x++ )
371
    {
372
        for( y = 0; y < imgH; y++ )
373
        {
374 375 376
            d = dest[y*widthStep+x];
            if( reliabilities[y*imgW+x] >= param4 && !(edges[y*imgW+x] & 4) &&
                d > 0 )//highly || moderately
377
            {
378 379 380 381 382
                disparities[y*widthStep+x] = (uchar)d;
                //up propagation
                for( i = y - 1; i >= 0; i-- )
                {
                    if(  ( edges[i*imgW+x] & 4 ) ||
383
                         ( dest[i*widthStep+x] < d &&
384
                           reliabilities[i*imgW+x] >= param3 ) ||
385
                         ( reliabilities[y*imgW+x] < param5 &&
386 387
                           dest[i*widthStep+x] - 1 == d ) ) break;

388 389 390
                    disparities[i*widthStep+x] = (uchar)d;
                }

391 392 393 394
                //down propagation
                for( i = y + 1; i < imgH; i++ )
                {
                    if(  ( edges[i*imgW+x] & 4 ) ||
395
                         ( dest[i*widthStep+x] < d &&
396
                           reliabilities[i*imgW+x] >= param3 ) ||
397
                         ( reliabilities[y*imgW+x] < param5 &&
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
                           dest[i*widthStep+x] - 1 == d ) ) break;

                    disparities[i*widthStep+x] = (uchar)d;
                }
                y = i - 1;
            }
            else
            {
                disparities[y*widthStep+x] = (uchar)d;
            }
        }
    }

    // define reliability along X
    for( y = 0; y < imgH; y++ )
    {
        for( x = 1; x < imgW; x++ )
        {
            i = x - 1;
Andrey Kamaev's avatar
Andrey Kamaev committed
417
            for( ; x < imgW && dest[y*widthStep+x] == dest[y*widthStep+x-1]; x++ ) {}
418 419
            s = x - i;
            for( ; i < x; i++ )
420
            {
421
                reliabilities[y*imgW+i] = s;
422
            }
423
        }
424 425 426 427 428
    }

    //X - propagate reliable regions
    for( y = 0; y < imgH; y++ )
    {
429
        for( x = 0; x < imgW; x++ )
430
        {
431 432 433
            d = dest[y*widthStep+x];
            if( reliabilities[y*imgW+x] >= param4 && !(edges[y*imgW+x] & 1) &&
                d > 0 )//highly || moderately
434
            {
435 436 437 438 439
                disparities[y*widthStep+x] = (uchar)d;
                //up propagation
                for( i = x - 1; i >= 0; i-- )
                {
                    if(  (edges[y*imgW+i] & 1) ||
440
                         ( dest[y*widthStep+i] < d &&
441
                           reliabilities[y*imgW+i] >= param3 ) ||
442
                         ( reliabilities[y*imgW+x] < param5 &&
443 444 445
                           dest[y*widthStep+i] - 1 == d ) ) break;

                    disparities[y*widthStep+i] = (uchar)d;
446 447
                }

448 449 450 451
                //down propagation
                for( i = x + 1; i < imgW; i++ )
                {
                    if(  (edges[y*imgW+i] & 1) ||
452
                         ( dest[y*widthStep+i] < d &&
453
                           reliabilities[y*imgW+i] >= param3 ) ||
454
                         ( reliabilities[y*imgW+x] < param5 &&
455 456 457 458 459 460 461 462 463 464 465 466 467 468
                           dest[y*widthStep+i] - 1 == d ) ) break;

                    disparities[y*widthStep+i] = (uchar)d;
                }
                x = i - 1;
            }
            else
            {
                disparities[y*widthStep+x] = (uchar)d;
            }
        }
    }

    //release resources
469 470 471 472
    cvFree( &dsi );
    cvFree( &edges );
    cvFree( &cells );
    cvFree( &rData );
473 474 475 476 477 478 479 480 481 482 483 484 485
}


/*F///////////////////////////////////////////////////////////////////////////
//
//    Name:    cvFindStereoCorrespondence
//    Purpose: find stereo correspondence on stereo-pair
//    Context:
//    Parameters:
//      leftImage - left image of stereo-pair (format 8uC1).
//      rightImage - right image of stereo-pair (format 8uC1).
//      mode -mode of correspondance retrieval (now CV_RETR_DP_BIRCHFIELD only)
//      dispImage - destination disparity image
486
//      maxDisparity - maximal disparity
487 488 489 490 491 492 493
//      param1, param2, param3, param4, param5 - parameters of algorithm
//    Returns:
//    Notes:
//      Images must be rectified.
//      All images must have format 8uC1.
//F*/
CV_IMPL void
494
cvFindStereoCorrespondence(
495 496 497
                   const  CvArr* leftImage, const  CvArr* rightImage,
                   int     mode,
                   CvArr*  depthImage,
498 499
                   int     maxDisparity,
                   double  param1, double  param2, double  param3,
500
                   double  param4, double  param5  )
501
{
502 503 504 505
    CV_FUNCNAME( "cvFindStereoCorrespondence" );

    __BEGIN__;

506
    CvMat  *src1, *src2;
507 508
    CvMat  *dst;
    CvMat  src1_stub, src2_stub, dst_stub;
509
    int    coi;
510 511 512 513

    CV_CALL( src1 = cvGetMat( leftImage, &src1_stub, &coi ));
    if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
    CV_CALL( src2 = cvGetMat( rightImage, &src2_stub, &coi ));
514
    if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
515 516 517
    CV_CALL( dst = cvGetMat( depthImage, &dst_stub, &coi ));
    if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported by the function" );

518 519 520
    // check args
    if( CV_MAT_TYPE( src1->type ) != CV_8UC1 ||
        CV_MAT_TYPE( src2->type ) != CV_8UC1 ||
521
        CV_MAT_TYPE( dst->type ) != CV_8UC1) CV_ERROR(CV_StsUnsupportedFormat,
522
                        "All images must be single-channel and have 8u" );
523 524 525

    if( !CV_ARE_SIZES_EQ( src1, src2 ) || !CV_ARE_SIZES_EQ( src1, dst ) )
            CV_ERROR( CV_StsUnmatchedSizes, "" );
526

527
    if( maxDisparity <= 0 || maxDisparity >= src1->width || maxDisparity > 255 )
528
        CV_ERROR(CV_StsOutOfRange,
529
                 "parameter /maxDisparity/ is out of range");
530

531 532 533 534 535 536 537 538
    if( mode == CV_DISPARITY_BIRCHFIELD )
    {
        if( param1 == CV_UNDEF_SC_PARAM ) param1 = CV_IDP_BIRCHFIELD_PARAM1;
        if( param2 == CV_UNDEF_SC_PARAM ) param2 = CV_IDP_BIRCHFIELD_PARAM2;
        if( param3 == CV_UNDEF_SC_PARAM ) param3 = CV_IDP_BIRCHFIELD_PARAM3;
        if( param4 == CV_UNDEF_SC_PARAM ) param4 = CV_IDP_BIRCHFIELD_PARAM4;
        if( param5 == CV_UNDEF_SC_PARAM ) param5 = CV_IDP_BIRCHFIELD_PARAM5;

539 540
        CV_CALL( icvFindStereoCorrespondenceByBirchfieldDP( src1->data.ptr,
            src2->data.ptr, dst->data.ptr,
541
            cvGetMatSize( src1 ), src1->step,
542
            maxDisparity, (float)param1, (float)param2, (float)param3,
543 544 545 546 547 548 549
            (float)param4, (float)param5 ) );
    }
    else
    {
        CV_ERROR( CV_StsBadArg, "Unsupported mode of function" );
    }

550
    __END__;
551 552 553
}

/* End of file. */