Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "_cvaux.h"
     43 
     44 typedef struct Seg
     45 {
     46     ushort y;
     47     ushort l;
     48     ushort r;
     49     ushort Prevl;
     50     ushort Prevr;
     51     short  fl;
     52 }
     53 Seg;
     54 
     55 #define UP 1
     56 #define DOWN -1
     57 
     58 #define PUSH(Y,IL,IR,IPL,IPR,FL) {  stack[StIn].y=(ushort)(Y); \
     59                                     stack[StIn].l=(ushort)(IL); \
     60                                     stack[StIn].r=(ushort)(IR); \
     61                                     stack[StIn].Prevl=(ushort)(IPL); \
     62                                     stack[StIn].Prevr=(ushort)(IPR); \
     63                                     stack[StIn].fl=(short)(FL); \
     64                                     StIn++; }
     65 
     66 #define POP(Y,IL,IR,IPL,IPR,FL)  {  StIn--; \
     67                                     Y=stack[StIn].y; \
     68                                     IL=stack[StIn].l; \
     69                                     IR=stack[StIn].r;\
     70                                     IPL=stack[StIn].Prevl; \
     71                                     IPR=stack[StIn].Prevr; \
     72                                     FL=stack[StIn].fl; }
     73 
     74 
     75 #define DIFF(p1,p2) ((unsigned)((p1)[0] - (p2)[0] + d_lw)<=Interval && \
     76                      (unsigned)((p1)[1] - (p2)[1] + d_lw)<=Interval && \
     77                      (unsigned)((p1)[2] - (p2)[2] + d_lw)<=Interval)
     78 
     79 /*#define DIFF(p1,p2) (CV_IABS((p1)[0] - (p2)[0]) + \
     80                      CV_IABS((p1)[1] - (p2)[1]) + \
     81                      CV_IABS((p1)[2] - (p2)[2]) <=Interval )*/
     82 
     83 static CvStatus
     84 icvSegmFloodFill_Stage1( uchar* pImage, int step,
     85                          uchar* pMask, int maskStep,
     86                          CvSize /*roi*/, CvPoint seed,
     87                          int* newVal, int d_lw, int d_up,
     88                          CvConnectedComp * region,
     89                          void *pStack )
     90 {
     91     uchar* img = pImage + step * seed.y;
     92     uchar* mask = pMask + maskStep * (seed.y + 1);
     93     unsigned Interval = (unsigned) (d_up + d_lw);
     94     Seg *stack = (Seg*)pStack;
     95     int StIn = 0;
     96     int i, L, R;
     97     int area = 0;
     98     int sum[] = { 0, 0, 0 };
     99     int XMin, XMax, YMin = seed.y, YMax = seed.y;
    100     int val0[3];
    101 
    102     L = R = seed.x;
    103     img = pImage + seed.y*step;
    104     mask = pMask + seed.y*maskStep;
    105     mask[L] = 1;
    106 
    107     val0[0] = img[seed.x*3];
    108     val0[1] = img[seed.x*3 + 1];
    109     val0[2] = img[seed.x*3 + 2];
    110 
    111     while( DIFF( img + (R+1)*3, /*img + R*3*/val0 ) && !mask[R + 1] )
    112         mask[++R] = 2;
    113 
    114     while( DIFF( img + (L-1)*3, /*img + L*3*/val0 ) && !mask[L - 1] )
    115         mask[--L] = 2;
    116 
    117     XMax = R;
    118     XMin = L;
    119     PUSH( seed.y, L, R, R + 1, R, UP );
    120 
    121     while( StIn )
    122     {
    123         int k, YC, PL, PR, flag/*, curstep*/;
    124 
    125         POP( YC, L, R, PL, PR, flag );
    126 
    127         int data[][3] = { {-flag, L, R}, {flag, L, PL-1}, {flag,PR+1,R}};
    128 
    129         if( XMax < R )
    130             XMax = R;
    131 
    132         if( XMin > L )
    133             XMin = L;
    134 
    135         if( YMax < YC )
    136             YMax = YC;
    137 
    138         if( YMin > YC )
    139             YMin = YC;
    140 
    141         for( k = 0; k < 3; k++ )
    142         {
    143             flag = data[k][0];
    144             /*curstep = flag * step;*/
    145             img = pImage + (YC + flag) * step;
    146             mask = pMask + (YC + flag) * maskStep;
    147             int left = data[k][1];
    148             int right = data[k][2];
    149 
    150             for( i = left; i <= right; i++ )
    151             {
    152                 if( !mask[i] && DIFF( img + i*3, /*img - curstep + i*3*/val0 ))
    153                 {
    154                     int j = i;
    155                     mask[i] = 2;
    156                     while( !mask[j - 1] && DIFF( img + (j - 1)*3, /*img + j*3*/val0 ))
    157                         mask[--j] = 2;
    158 
    159                     while( !mask[i + 1] &&
    160                            (DIFF( img + (i+1)*3, /*img + i*3*/val0 ) ||
    161                            (DIFF( img + (i+1)*3, /*img + (i+1)*3 - curstep*/val0) && i < R)))
    162                         mask[++i] = 2;
    163 
    164                     PUSH( YC + flag, j, i, L, R, -flag );
    165                     i++;
    166                 }
    167             }
    168         }
    169 
    170         img = pImage + YC * step;
    171 
    172         for( i = L; i <= R; i++ )
    173         {
    174             sum[0] += img[i*3];
    175             sum[1] += img[i*3 + 1];
    176             sum[2] += img[i*3 + 2];
    177         }
    178 
    179         area += R - L + 1;
    180     }
    181 
    182     region->area = area;
    183     region->rect.x = XMin;
    184     region->rect.y = YMin;
    185     region->rect.width = XMax - XMin + 1;
    186     region->rect.height = YMax - YMin + 1;
    187     region->value = cvScalarAll(0);
    188 
    189     {
    190         double inv_area = area ? 1./area : 0;
    191         newVal[0] = cvRound( sum[0] * inv_area );
    192         newVal[1] = cvRound( sum[1] * inv_area );
    193         newVal[2] = cvRound( sum[2] * inv_area );
    194     }
    195 
    196     return CV_NO_ERR;
    197 }
    198 
    199 
    200 #undef PUSH
    201 #undef POP
    202 #undef DIFF
    203 
    204 
    205 static CvStatus
    206 icvSegmFloodFill_Stage2( uchar* pImage, int step,
    207                          uchar* pMask, int maskStep,
    208                          CvSize /*roi*/, int* newVal,
    209                          CvRect rect )
    210 {
    211     uchar* img = pImage + step * rect.y + rect.x * 3;
    212     uchar* mask = pMask + maskStep * rect.y + rect.x;
    213     uchar uv[] = { (uchar)newVal[0], (uchar)newVal[1], (uchar)newVal[2] };
    214     int x, y;
    215 
    216     for( y = 0; y < rect.height; y++, img += step, mask += maskStep )
    217         for( x = 0; x < rect.width; x++ )
    218             if( mask[x] == 2 )
    219             {
    220                 mask[x] = 1;
    221                 img[x*3] = uv[0];
    222                 img[x*3+1] = uv[1];
    223                 img[x*3+2] = uv[2];
    224             }
    225 
    226     return CV_OK;
    227 }
    228 
    229 #if 0
    230 static void color_derv( const CvArr* srcArr, CvArr* dstArr, int thresh )
    231 {
    232     static int tab[] = { 0, 2, 2, 1 };
    233 
    234     uchar *src = 0, *dst = 0;
    235     int dst_step, src_step;
    236     int x, y;
    237     CvSize size;
    238 
    239     cvGetRawData( srcArr, (uchar**)&src, &src_step, &size );
    240     cvGetRawData( dstArr, (uchar**)&dst, &dst_step, 0 );
    241 
    242     memset( dst, 0, size.width*sizeof(dst[0]));
    243     memset( (uchar*)dst + dst_step*(size.height-1), 0, size.width*sizeof(dst[0]));
    244     src += 3;
    245 
    246     #define  CV_IABS(a)     (((a) ^ ((a) < 0 ? -1 : 0)) - ((a) < 0 ? -1 : 0))
    247 
    248     for( y = 1; y < size.height - 1; y++ )
    249     {
    250         src += src_step;
    251         dst += dst_step;
    252         uchar* src0 = src;
    253 
    254         dst[0] = dst[size.width - 1] = 0;
    255 
    256         for( x = 1; x < size.width - 1; x++, src += 3 )
    257         {
    258             /*int d[3];
    259             int ad[3];
    260             int f0, f1;
    261             int val;*/
    262             int m[3];
    263             double val;
    264             //double xx, yy;
    265             int dh[3];
    266             int dv[3];
    267             dh[0] = src[0] - src[-3];
    268             dv[0] = src[0] - src[-src_step];
    269             dh[1] = src[1] - src[-2];
    270             dv[1] = src[1] - src[1-src_step];
    271             dh[2] = src[2] - src[-1];
    272             dv[2] = src[2] - src[2-src_step];
    273 
    274             m[0] = dh[0]*dh[0] + dh[1]*dh[1] + dh[2]*dh[2];
    275             m[2] = dh[0]*dv[0] + dh[1]*dv[1] + dh[2]*dv[2];
    276             m[1] = dv[0]*dv[0] + dv[1]*dv[1] + dh[2]*dh[2];
    277 
    278             val = (m[0] + m[2]) +
    279                 sqrt(((double)((double)m[0] - m[2]))*(m[0] - m[2]) + (4.*m[1])*m[1]);
    280 
    281             /*
    282 
    283             xx = m[1];
    284             yy = v - m[0];
    285             v /= sqrt(xx*xx + yy*yy) + 1e-7;
    286             xx *= v;
    287             yy *= v;
    288 
    289             dx[x] = (short)cvRound(xx);
    290             dy[x] = (short)cvRound(yy);
    291 
    292             //dx[x] = (short)cvRound(v);
    293 
    294             //dx[x] = dy[x] = (short)v;
    295             d[0] = src[0] - src[-3];
    296             ad[0] = CV_IABS(d[0]);
    297 
    298             d[1] = src[1] - src[-2];
    299             ad[1] = CV_IABS(d[1]);
    300 
    301             d[2] = src[2] - src[-1];
    302             ad[2] = CV_IABS(d[2]);
    303 
    304             f0 = ad[1] > ad[0];
    305             f1 = ad[2] > ad[f0];
    306 
    307             val = d[tab[f0*2 + f1]];
    308 
    309             d[0] = src[0] - src[-src_step];
    310             ad[0] = CV_IABS(d[0]);
    311 
    312             d[1] = src[1] - src[1-src_step];
    313             ad[1] = CV_IABS(d[1]);
    314 
    315             d[2] = src[2] - src[2-src_step];
    316             ad[2] = CV_IABS(d[2]);
    317 
    318             f0 = ad[1] > ad[0];
    319             f1 = ad[2] > ad[f0];
    320 
    321             dst[x] = (uchar)(val + d[tab[f0*2 + f1]] > thresh ? 255 : 0);*/
    322             dst[x] = (uchar)(val > thresh);
    323         }
    324 
    325         src = src0;
    326     }
    327 
    328 }
    329 #endif
    330 
    331 const CvPoint icvCodeDeltas[8] =
    332     { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
    333 
    334 static CvSeq*
    335 icvGetComponent( uchar* img, int step, CvRect rect,
    336                  CvMemStorage* storage )
    337 {
    338     const char nbd = 4;
    339     int  deltas[16];
    340     int  x, y;
    341     CvSeq* exterior = 0;
    342     char* ptr;
    343 
    344     /* initialize local state */
    345     CV_INIT_3X3_DELTAS( deltas, step, 1 );
    346     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
    347 
    348     ptr = (char*)(img + step*rect.y);
    349     rect.width += rect.x;
    350     rect.height += rect.y;
    351 
    352     for( y = rect.y; y < rect.height; y++, ptr += step )
    353     {
    354         int prev = ptr[rect.x - 1] & -2;
    355 
    356         for( x = rect.x; x < rect.width; x++ )
    357         {
    358             int p = ptr[x] & -2;
    359 
    360             //assert( exterior || ((p | prev) & -4) == 0 );
    361 
    362             if( p != prev )
    363             {
    364                 CvSeq *seq = 0;
    365                 int is_hole = 0;
    366                 CvSeqWriter  writer;
    367                 char  *i0, *i1, *i3, *i4 = 0;
    368                 int  prev_s = -1, s, s_end;
    369                 CvPoint pt = { x, y };
    370 
    371                 if( !(prev == 0 && p == 2) )    /* if not external contour */
    372                 {
    373                     /* check hole */
    374                     if( p != 0 || prev < 1 )
    375                     {
    376                         prev = p;
    377                         continue;
    378                     }
    379 
    380                     is_hole = 1;
    381                     if( !exterior )
    382                     {
    383                         assert(0);
    384                         return 0;
    385                     }
    386                 }
    387 
    388                 cvStartWriteSeq( CV_SEQ_CONTOUR | (is_hole ? CV_SEQ_FLAG_HOLE : 0),
    389                                  sizeof(CvContour), sizeof(CvPoint), storage, &writer );
    390                 s_end = s = is_hole ? 0 : 4;
    391                 i0 = ptr + x - is_hole;
    392 
    393                 do
    394                 {
    395                     s = (s - 1) & 7;
    396                     i1 = i0 + deltas[s];
    397                     if( (*i1 & -2) != 0 )
    398                         break;
    399                 }
    400                 while( s != s_end );
    401 
    402                 if( s == s_end )            /* single pixel domain */
    403                 {
    404                     *i0 = (char) (nbd | -128);
    405                     CV_WRITE_SEQ_ELEM( pt, writer );
    406                 }
    407                 else
    408                 {
    409                     i3 = i0;
    410                     prev_s = s ^ 4;
    411 
    412                     /* follow border */
    413                     for( ;; )
    414                     {
    415                         s_end = s;
    416 
    417                         for( ;; )
    418                         {
    419                             i4 = i3 + deltas[++s];
    420                             if( (*i4 & -2) != 0 )
    421                                 break;
    422                         }
    423                         s &= 7;
    424 
    425                         /* check "right" bound */
    426                         if( (unsigned) (s - 1) < (unsigned) s_end )
    427                         {
    428                             *i3 = (char) (nbd | -128);
    429                         }
    430                         else if( *i3 > 0 )
    431                         {
    432                             *i3 = nbd;
    433                         }
    434 
    435                         if( s != prev_s )
    436                         {
    437                             CV_WRITE_SEQ_ELEM( pt, writer );
    438                             prev_s = s;
    439                         }
    440 
    441                         pt.x += icvCodeDeltas[s].x;
    442                         pt.y += icvCodeDeltas[s].y;
    443 
    444                         if( i4 == i0 && i3 == i1 )
    445                             break;
    446 
    447                         i3 = i4;
    448                         s = (s + 4) & 7;
    449                     }                       /* end of border following loop */
    450                 }
    451 
    452                 seq = cvEndWriteSeq( &writer );
    453                 cvContourBoundingRect( seq, 1 );
    454 
    455                 if( !is_hole )
    456                     exterior = seq;
    457                 else
    458                 {
    459                     seq->v_prev = exterior;
    460                     seq->h_next = exterior->v_next;
    461                     if( seq->h_next )
    462                         seq->h_next->h_prev = seq;
    463                     exterior->v_next = seq;
    464                 }
    465 
    466                 prev = ptr[x] & -2;
    467             }
    468         }
    469     }
    470 
    471     return exterior;
    472 }
    473 
    474 
    475 
    476 CV_IMPL CvSeq*
    477 cvSegmentImage( const CvArr* srcarr, CvArr* dstarr,
    478                 double canny_threshold,
    479                 double ffill_threshold,
    480                 CvMemStorage* storage )
    481 {
    482     CvSeq* root = 0;
    483     CvMat* gray = 0;
    484     CvMat* canny = 0;
    485     //CvMat* temp = 0;
    486     void* stack = 0;
    487 
    488     CV_FUNCNAME( "cvSegmentImage" );
    489 
    490     __BEGIN__;
    491 
    492     CvMat srcstub, *src;
    493     CvMat dststub, *dst;
    494     CvMat* mask;
    495     CvSize size;
    496     CvPoint pt;
    497     int ffill_lw_up = cvRound( fabs(ffill_threshold) );
    498     CvSeq* prev_seq = 0;
    499 
    500     CV_CALL( src = cvGetMat( srcarr, &srcstub ));
    501     CV_CALL( dst = cvGetMat( dstarr, &dststub ));
    502 
    503     size = cvGetSize( src );
    504 
    505     CV_CALL( gray = cvCreateMat( size.height, size.width, CV_8UC1 ));
    506     CV_CALL( canny = cvCreateMat( size.height, size.width, CV_8UC1 ));
    507     //CV_CALL( temp = cvCreateMat( size.height/2, size.width/2, CV_8UC3 ));
    508 
    509     CV_CALL( stack = cvAlloc( size.width * size.height * sizeof(Seg)));
    510 
    511     cvCvtColor( src, gray, CV_BGR2GRAY );
    512     cvCanny( gray, canny, 0/*canny_threshold*0.4*/, canny_threshold, 3 );
    513     cvThreshold( canny, canny, 1, 1, CV_THRESH_BINARY );
    514     //cvZero( canny );
    515     //color_derv( src, canny, canny_threshold );
    516 
    517     //cvPyrDown( src, temp );
    518     //cvPyrUp( temp, dst );
    519 
    520     //src = dst;
    521     mask = canny; // a new name for new role
    522 
    523     // make a non-zero border.
    524     cvRectangle( mask, cvPoint(0,0), cvPoint(size.width-1,size.height-1), cvScalarAll(1), 1 );
    525 
    526     for( pt.y = 0; pt.y < size.height; pt.y++ )
    527     {
    528         for( pt.x = 0; pt.x < size.width; pt.x++ )
    529         {
    530             if( mask->data.ptr[mask->step*pt.y + pt.x] == 0 )
    531             {
    532                 CvConnectedComp region;
    533                 int avgVal[3] = { 0, 0, 0 };
    534 
    535                 icvSegmFloodFill_Stage1( src->data.ptr, src->step,
    536                                          mask->data.ptr, mask->step,
    537                                          size, pt, avgVal,
    538                                          ffill_lw_up, ffill_lw_up,
    539                                          &region, stack );
    540 
    541                 /*avgVal[0] = (avgVal[0] + 15) & -32;
    542                 if( avgVal[0] > 255 )
    543                     avgVal[0] = 255;
    544                 avgVal[1] = (avgVal[1] + 15) & -32;
    545                 if( avgVal[1] > 255 )
    546                     avgVal[1] = 255;
    547                 avgVal[2] = (avgVal[2] + 15) & -32;
    548                 if( avgVal[2] > 255 )
    549                     avgVal[2] = 255;*/
    550 
    551                 if( storage )
    552                 {
    553                     CvSeq* tmpseq = icvGetComponent( mask->data.ptr, mask->step,
    554                                                      region.rect, storage );
    555                     if( tmpseq != 0 )
    556                     {
    557                         ((CvContour*)tmpseq)->color = avgVal[0] + (avgVal[1] << 8) + (avgVal[2] << 16);
    558                         tmpseq->h_prev = prev_seq;
    559                         if( prev_seq )
    560                             prev_seq->h_next = tmpseq;
    561                         else
    562                             root = tmpseq;
    563                         prev_seq = tmpseq;
    564                     }
    565                 }
    566 
    567                 icvSegmFloodFill_Stage2( dst->data.ptr, dst->step,
    568                                          mask->data.ptr, mask->step,
    569                                          size, avgVal,
    570                                          region.rect );
    571             }
    572         }
    573     }
    574 
    575     __END__;
    576 
    577     //cvReleaseMat( &temp );
    578     cvReleaseMat( &gray );
    579     cvReleaseMat( &canny );
    580     cvFree( &stack );
    581 
    582     return root;
    583 }
    584 
    585 /* End of file. */
    586