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 icvers.
     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 /* ////////////////////////////////////////////////////////////////////
     43 //
     44 //  Geometrical transforms on images and matrices: rotation, zoom etc.
     45 //
     46 // */
     47 
     48 #include "precomp.hpp"
     49 #include "opencv2/imgproc/imgproc_c.h"
     50 #include "opencv2/photo/photo_c.h"
     51 
     52 #undef CV_MAT_ELEM_PTR_FAST
     53 #define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size )  \
     54      ((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col))
     55 
     56 inline float
     57 min4( float a, float b, float c, float d )
     58 {
     59     a = MIN(a,b);
     60     c = MIN(c,d);
     61     return MIN(a,c);
     62 }
     63 
     64 #define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c))
     65 #define KNOWN  0  //known outside narrow band
     66 #define BAND   1  //narrow band (known)
     67 #define INSIDE 2  //unknown
     68 #define CHANGE 3  //servise
     69 
     70 typedef struct CvHeapElem
     71 {
     72     float T;
     73     int i,j;
     74     struct CvHeapElem* prev;
     75     struct CvHeapElem* next;
     76 }
     77 CvHeapElem;
     78 
     79 
     80 class CvPriorityQueueFloat
     81 {
     82 protected:
     83     CvHeapElem *mem,*empty,*head,*tail;
     84     int num,in;
     85 
     86 public:
     87     bool Init( const CvMat* f )
     88     {
     89         int i,j;
     90         for( i = num = 0; i < f->rows; i++ )
     91         {
     92             for( j = 0; j < f->cols; j++ )
     93                 num += CV_MAT_ELEM(*f,uchar,i,j)!=0;
     94         }
     95         if (num<=0) return false;
     96         mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem));
     97         if (mem==NULL) return false;
     98 
     99         head       = mem;
    100         head->i    = head->j = -1;
    101         head->prev = NULL;
    102         head->next = mem+1;
    103         head->T    = -FLT_MAX;
    104         empty      = mem+1;
    105         for (i=1; i<=num; i++) {
    106             mem[i].prev   = mem+i-1;
    107             mem[i].next   = mem+i+1;
    108             mem[i].i      = -1;
    109             mem[i].T      = FLT_MAX;
    110         }
    111         tail       = mem+i;
    112         tail->i    = tail->j = -1;
    113         tail->prev = mem+i-1;
    114         tail->next = NULL;
    115         tail->T    = FLT_MAX;
    116         return true;
    117     }
    118 
    119     bool Add(const CvMat* f) {
    120         int i,j;
    121         for (i=0; i<f->rows; i++) {
    122             for (j=0; j<f->cols; j++) {
    123                 if (CV_MAT_ELEM(*f,uchar,i,j)!=0) {
    124                     if (!Push(i,j,0)) return false;
    125                 }
    126             }
    127         }
    128         return true;
    129     }
    130 
    131     bool Push(int i, int j, float T) {
    132         CvHeapElem *tmp=empty,*add=empty;
    133         if (empty==tail) return false;
    134         while (tmp->prev->T>T) tmp = tmp->prev;
    135         if (tmp!=empty) {
    136             add->prev->next = add->next;
    137             add->next->prev = add->prev;
    138             empty = add->next;
    139             add->prev = tmp->prev;
    140             add->next = tmp;
    141             add->prev->next = add;
    142             add->next->prev = add;
    143         } else {
    144             empty = empty->next;
    145         }
    146         add->i = i;
    147         add->j = j;
    148         add->T = T;
    149         in++;
    150         //      printf("push i %3d  j %3d  T %12.4e  in %4d\n",i,j,T,in);
    151         return true;
    152     }
    153 
    154     bool Pop(int *i, int *j) {
    155         CvHeapElem *tmp=head->next;
    156         if (empty==tmp) return false;
    157         *i = tmp->i;
    158         *j = tmp->j;
    159         tmp->prev->next = tmp->next;
    160         tmp->next->prev = tmp->prev;
    161         tmp->prev = empty->prev;
    162         tmp->next = empty;
    163         tmp->prev->next = tmp;
    164         tmp->next->prev = tmp;
    165         empty = tmp;
    166         in--;
    167         //      printf("pop  i %3d  j %3d  T %12.4e  in %4d\n",tmp->i,tmp->j,tmp->T,in);
    168         return true;
    169     }
    170 
    171     bool Pop(int *i, int *j, float *T) {
    172         CvHeapElem *tmp=head->next;
    173         if (empty==tmp) return false;
    174         *i = tmp->i;
    175         *j = tmp->j;
    176         *T = tmp->T;
    177         tmp->prev->next = tmp->next;
    178         tmp->next->prev = tmp->prev;
    179         tmp->prev = empty->prev;
    180         tmp->next = empty;
    181         tmp->prev->next = tmp;
    182         tmp->next->prev = tmp;
    183         empty = tmp;
    184         in--;
    185         //      printf("pop  i %3d  j %3d  T %12.4e  in %4d\n",tmp->i,tmp->j,tmp->T,in);
    186         return true;
    187     }
    188 
    189     CvPriorityQueueFloat(void) {
    190         num=in=0;
    191         mem=empty=head=tail=NULL;
    192     }
    193 
    194     ~CvPriorityQueueFloat(void)
    195     {
    196         cvFree( &mem );
    197     }
    198 };
    199 
    200 inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) {
    201    return v1.x*v2.x+v1.y*v2.y;
    202 }
    203 
    204 inline float VectorLength(CvPoint2D32f v1) {
    205    return v1.x*v1.x+v1.y*v1.y;
    206 }
    207 
    208 ///////////////////////////////////////////////////////////////////////////////////////////
    209 //HEAP::iterator Heap_Iterator;
    210 //HEAP Heap;
    211 
    212 static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t)
    213 {
    214     double sol, a11, a22, m12;
    215     a11=CV_MAT_ELEM(*t,float,i1,j1);
    216     a22=CV_MAT_ELEM(*t,float,i2,j2);
    217     m12=MIN(a11,a22);
    218 
    219     if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE )
    220         if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
    221             if( fabs(a11-a22) >= 1.0 )
    222                 sol = 1+m12;
    223             else
    224                 sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5;
    225         else
    226             sol = 1+a11;
    227     else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
    228         sol = 1+a22;
    229     else
    230         sol = 1+m12;
    231 
    232     return (float)sol;
    233 }
    234 
    235 /////////////////////////////////////////////////////////////////////////////////////
    236 
    237 
    238 static void
    239 icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
    240    int i, j, ii = 0, jj = 0, q;
    241    float dist;
    242 
    243    while (Heap->Pop(&ii,&jj)) {
    244 
    245       unsigned known=(negate)?CHANGE:KNOWN;
    246       CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known;
    247 
    248       for (q=0; q<4; q++) {
    249          i=0; j=0;
    250          if     (q==0) {i=ii-1; j=jj;}
    251          else if(q==1) {i=ii;   j=jj-1;}
    252          else if(q==2) {i=ii+1; j=jj;}
    253          else {i=ii;   j=jj+1;}
    254          if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue;
    255 
    256          if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
    257             dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
    258                         FastMarching_solve(i+1,j,i,j-1,f,t),
    259                         FastMarching_solve(i-1,j,i,j+1,f,t),
    260                         FastMarching_solve(i+1,j,i,j+1,f,t));
    261             CV_MAT_ELEM(*t,float,i,j) = dist;
    262             CV_MAT_ELEM(*f,uchar,i,j) = BAND;
    263             Heap->Push(i,j,dist);
    264          }
    265       }
    266    }
    267 
    268    if (negate) {
    269       for (i=0; i<f->rows; i++) {
    270          for(j=0; j<f->cols; j++) {
    271             if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) {
    272                CV_MAT_ELEM(*f,uchar,i,j) = KNOWN;
    273                CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j);
    274             }
    275          }
    276       }
    277    }
    278 }
    279 
    280 
    281 static void
    282 icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) {
    283    int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
    284    float dist;
    285 
    286    if (CV_MAT_CN(out->type)==3) {
    287 
    288       while (Heap->Pop(&ii,&jj)) {
    289 
    290          CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
    291          for(q=0; q<4; q++) {
    292             if     (q==0) {i=ii-1; j=jj;}
    293             else if(q==1) {i=ii;   j=jj-1;}
    294             else if(q==2) {i=ii+1; j=jj;}
    295             else if(q==3) {i=ii;   j=jj+1;}
    296             if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
    297 
    298             if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
    299                dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
    300                            FastMarching_solve(i+1,j,i,j-1,f,t),
    301                            FastMarching_solve(i-1,j,i,j+1,f,t),
    302                            FastMarching_solve(i+1,j,i,j+1,f,t));
    303                CV_MAT_ELEM(*t,float,i,j) = dist;
    304 
    305                for (color=0; color<=2; color++) {
    306                   CvPoint2D32f gradI,gradT,r;
    307                   float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
    308 
    309                   if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) {
    310                      if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
    311                         gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f;
    312                      } else {
    313                         gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
    314                      }
    315                   } else {
    316                      if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
    317                         gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1)));
    318                      } else {
    319                         gradT.x=0;
    320                      }
    321                   }
    322                   if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) {
    323                      if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
    324                         gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f;
    325                      } else {
    326                         gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
    327                      }
    328                   } else {
    329                      if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
    330                         gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j)));
    331                      } else {
    332                         gradT.y=0;
    333                      }
    334                   }
    335                   for (k=i-range; k<=i+range; k++) {
    336                      int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
    337                      for (l=j-range; l<=j+range; l++) {
    338                         int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
    339                         if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
    340                            if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
    341                                ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
    342                               r.y     = (float)(i-k);
    343                               r.x     = (float)(j-l);
    344 
    345                               dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r))));
    346                               lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j))));
    347 
    348                               dir=VectorScalMult(r,gradT);
    349                               if (fabs(dir)<=0.01) dir=0.000001f;
    350                               w = (float)fabs(dst*lev*dir);
    351 
    352                               if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
    353                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    354                                     gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f;
    355                                  } else {
    356                                     gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
    357                                  }
    358                               } else {
    359                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    360                                     gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)));
    361                                  } else {
    362                                     gradI.x=0;
    363                                  }
    364                               }
    365                               if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
    366                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    367                                     gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f;
    368                                  } else {
    369                                     gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
    370                                  }
    371                               } else {
    372                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    373                                     gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)));
    374                                  } else {
    375                                     gradI.y=0;
    376                                  }
    377                               }
    378                               Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
    379                               Jx -= (float)w * (float)(gradI.x*r.x);
    380                               Jy -= (float)w * (float)(gradI.y*r.y);
    381                               s  += w;
    382                            }
    383                         }
    384                      }
    385                   }
    386                   sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
    387                   {
    388                   CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast<uchar>(sat);
    389                   }
    390                }
    391 
    392                CV_MAT_ELEM(*f,uchar,i,j) = BAND;
    393                Heap->Push(i,j,dist);
    394             }
    395          }
    396       }
    397 
    398    } else if (CV_MAT_CN(out->type)==1) {
    399 
    400       while (Heap->Pop(&ii,&jj)) {
    401 
    402          CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
    403          for(q=0; q<4; q++) {
    404             if     (q==0) {i=ii-1; j=jj;}
    405             else if(q==1) {i=ii;   j=jj-1;}
    406             else if(q==2) {i=ii+1; j=jj;}
    407             else if(q==3) {i=ii;   j=jj+1;}
    408             if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
    409 
    410             if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
    411                dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
    412                            FastMarching_solve(i+1,j,i,j-1,f,t),
    413                            FastMarching_solve(i-1,j,i,j+1,f,t),
    414                            FastMarching_solve(i+1,j,i,j+1,f,t));
    415                CV_MAT_ELEM(*t,float,i,j) = dist;
    416 
    417                for (color=0; color<=0; color++) {
    418                   CvPoint2D32f gradI,gradT,r;
    419                   float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
    420 
    421                   if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) {
    422                      if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
    423                         gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f;
    424                      } else {
    425                         gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
    426                      }
    427                   } else {
    428                      if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
    429                         gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1)));
    430                      } else {
    431                         gradT.x=0;
    432                      }
    433                   }
    434                   if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) {
    435                      if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
    436                         gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f;
    437                      } else {
    438                         gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
    439                      }
    440                   } else {
    441                      if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
    442                         gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j)));
    443                      } else {
    444                         gradT.y=0;
    445                      }
    446                   }
    447                   for (k=i-range; k<=i+range; k++) {
    448                      int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
    449                      for (l=j-range; l<=j+range; l++) {
    450                         int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
    451                         if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
    452                            if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
    453                                ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
    454                               r.y     = (float)(i-k);
    455                               r.x     = (float)(j-l);
    456 
    457                               dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r))));
    458                               lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j))));
    459 
    460                               dir=VectorScalMult(r,gradT);
    461                               if (fabs(dir)<=0.01) dir=0.000001f;
    462                               w = (float)fabs(dst*lev*dir);
    463 
    464                               if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
    465                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    466                                     gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
    467                                  } else {
    468                                     gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)));
    469                                  }
    470                               } else {
    471                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    472                                     gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
    473                                  } else {
    474                                     gradI.x=0;
    475                                  }
    476                               }
    477                               if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
    478                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    479                                     gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
    480                                  } else {
    481                                     gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm)));
    482                                  }
    483                               } else {
    484                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    485                                     gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
    486                                  } else {
    487                                     gradI.y=0;
    488                                  }
    489                               }
    490                               Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
    491                               Jx -= (float)w * (float)(gradI.x*r.x);
    492                               Jy -= (float)w * (float)(gradI.y*r.y);
    493                               s  += w;
    494                            }
    495                         }
    496                      }
    497                   }
    498                   sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
    499                   {
    500                   CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast<uchar>(sat);
    501                   }
    502                }
    503 
    504                CV_MAT_ELEM(*f,uchar,i,j) = BAND;
    505                Heap->Push(i,j,dist);
    506             }
    507          }
    508       }
    509    }
    510 }
    511 
    512 
    513 static void
    514 icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) {
    515    int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
    516    float dist;
    517 
    518    if (CV_MAT_CN(out->type)==3) {
    519 
    520       while (Heap->Pop(&ii,&jj)) {
    521 
    522          CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
    523          for(q=0; q<4; q++) {
    524             if     (q==0) {i=ii-1; j=jj;}
    525             else if(q==1) {i=ii;   j=jj-1;}
    526             else if(q==2) {i=ii+1; j=jj;}
    527             else if(q==3) {i=ii;   j=jj+1;}
    528             if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
    529 
    530             if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
    531                dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
    532                            FastMarching_solve(i+1,j,i,j-1,f,t),
    533                            FastMarching_solve(i-1,j,i,j+1,f,t),
    534                            FastMarching_solve(i+1,j,i,j+1,f,t));
    535                CV_MAT_ELEM(*t,float,i,j) = dist;
    536 
    537                for (color=0; color<=2; color++) {
    538                   CvPoint2D32f gradI,r;
    539                   float Ia=0,s=1.0e-20f,w,dst,dir;
    540 
    541                   for (k=i-range; k<=i+range; k++) {
    542                      int km=k-1+(k==1),kp=k-1-(k==f->rows-2);
    543                      for (l=j-range; l<=j+range; l++) {
    544                         int lm=l-1+(l==1),lp=l-1-(l==f->cols-2);
    545                         if (k>0&&l>0&&k<f->rows-1&&l<f->cols-1) {
    546                            if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
    547                                ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
    548                               r.y=(float)(k-i);
    549                               r.x=(float)(l-j);
    550 
    551                               dst = 1/(VectorLength(r)*VectorLength(r)+1);
    552 
    553                               if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
    554                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    555                                     gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+
    556                                                     abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)));
    557                                  } else {
    558                                     gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f;
    559                                  }
    560                               } else {
    561                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    562                                     gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f;
    563                                  } else {
    564                                     gradI.x=0;
    565                                  }
    566                               }
    567                               if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
    568                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    569                                     gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+
    570                                                     abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)));
    571                                  } else {
    572                                     gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f;
    573                                  }
    574                               } else {
    575                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    576                                     gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f;
    577                                  } else {
    578                                     gradI.y=0;
    579                                  }
    580                               }
    581 
    582                               gradI.x=-gradI.x;
    583                               dir=VectorScalMult(r,gradI);
    584 
    585                               if (fabs(dir)<=0.01) {
    586                                  dir=0.000001f;
    587                               } else {
    588                                  dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
    589                               }
    590                               w = dst*dir;
    591                               Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
    592                               s  += w;
    593                            }
    594                         }
    595                      }
    596                   }
    597                   CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast<uchar>((double)Ia/s);
    598                }
    599 
    600                CV_MAT_ELEM(*f,uchar,i,j) = BAND;
    601                Heap->Push(i,j,dist);
    602             }
    603          }
    604       }
    605 
    606    } else if (CV_MAT_CN(out->type)==1) {
    607 
    608       while (Heap->Pop(&ii,&jj)) {
    609 
    610          CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
    611          for(q=0; q<4; q++) {
    612             if     (q==0) {i=ii-1; j=jj;}
    613             else if(q==1) {i=ii;   j=jj-1;}
    614             else if(q==2) {i=ii+1; j=jj;}
    615             else if(q==3) {i=ii;   j=jj+1;}
    616             if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
    617 
    618             if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
    619                dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
    620                            FastMarching_solve(i+1,j,i,j-1,f,t),
    621                            FastMarching_solve(i-1,j,i,j+1,f,t),
    622                            FastMarching_solve(i+1,j,i,j+1,f,t));
    623                CV_MAT_ELEM(*t,float,i,j) = dist;
    624 
    625                {
    626                   CvPoint2D32f gradI,r;
    627                   float Ia=0,s=1.0e-20f,w,dst,dir;
    628 
    629                   for (k=i-range; k<=i+range; k++) {
    630                      int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
    631                      for (l=j-range; l<=j+range; l++) {
    632                         int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
    633                         if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
    634                            if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
    635                                ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
    636                               r.y=(float)(i-k);
    637                               r.x=(float)(j-l);
    638 
    639                               dst = 1/(VectorLength(r)*VectorLength(r)+1);
    640 
    641                               if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
    642                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    643                                     gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+
    644                                                     abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
    645                                  } else {
    646                                     gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f;
    647                                  }
    648                               } else {
    649                                  if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
    650                                     gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
    651                                  } else {
    652                                     gradI.x=0;
    653                                  }
    654                               }
    655                               if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
    656                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    657                                     gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+
    658                                                     abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
    659                                  } else {
    660                                     gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f;
    661                                  }
    662                               } else {
    663                                  if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
    664                                     gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
    665                                  } else {
    666                                     gradI.y=0;
    667                                  }
    668                               }
    669 
    670                               gradI.x=-gradI.x;
    671                               dir=VectorScalMult(r,gradI);
    672 
    673                               if (fabs(dir)<=0.01) {
    674                                  dir=0.000001f;
    675                               } else {
    676                                  dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
    677                               }
    678                               w = dst*dir;
    679                               Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
    680                               s  += w;
    681                            }
    682                         }
    683                      }
    684                   }
    685                   CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast<uchar>((double)Ia/s);
    686                }
    687 
    688                CV_MAT_ELEM(*f,uchar,i,j) = BAND;
    689                Heap->Push(i,j,dist);
    690             }
    691          }
    692       }
    693 
    694    }
    695 }
    696 
    697 #define SET_BORDER1_C1(image,type,value) {\
    698       int i,j;\
    699       for(j=0; j<image->cols; j++) {\
    700          CV_MAT_ELEM(*image,type,0,j) = value;\
    701       }\
    702       for (i=1; i<image->rows-1; i++) {\
    703          CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\
    704       }\
    705       for(j=0; j<image->cols; j++) {\
    706          CV_MAT_ELEM(*image,type,erows-1,j) = value;\
    707       }\
    708    }
    709 
    710 #define COPY_MASK_BORDER1_C1(src,dst,type) {\
    711       int i,j;\
    712       for (i=0; i<src->rows; i++) {\
    713          for(j=0; j<src->cols; j++) {\
    714             if (CV_MAT_ELEM(*src,type,i,j)!=0)\
    715                CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\
    716          }\
    717       }\
    718    }
    719 
    720 namespace cv {
    721 template<> void cv::DefaultDeleter<IplConvKernel>::operator ()(IplConvKernel* obj) const
    722 {
    723   cvReleaseStructuringElement(&obj);
    724 }
    725 }
    726 
    727 void
    728 cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img,
    729            double inpaintRange, int flags )
    730 {
    731     cv::Ptr<CvMat> mask, band, f, t, out;
    732     cv::Ptr<CvPriorityQueueFloat> Heap, Out;
    733     cv::Ptr<IplConvKernel> el_cross, el_range;
    734 
    735     CvMat input_hdr, mask_hdr, output_hdr;
    736     CvMat* input_img, *inpaint_mask, *output_img;
    737     int range=cvRound(inpaintRange);
    738     int erows, ecols;
    739 
    740     input_img = cvGetMat( _input_img, &input_hdr );
    741     inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr );
    742     output_img = cvGetMat( _output_img, &output_hdr );
    743 
    744     if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask))
    745         CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" );
    746 
    747     if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 &&
    748         CV_MAT_TYPE(input_img->type) != CV_8UC3) ||
    749         !CV_ARE_TYPES_EQ(input_img,output_img) )
    750         CV_Error( CV_StsUnsupportedFormat,
    751         "Only 8-bit 1-channel and 3-channel input/output images are supported" );
    752 
    753     if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
    754         CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
    755 
    756     range = MAX(range,1);
    757     range = MIN(range,100);
    758 
    759     ecols = input_img->cols + 2;
    760     erows = input_img->rows + 2;
    761 
    762     f.reset(cvCreateMat(erows, ecols, CV_8UC1));
    763     t.reset(cvCreateMat(erows, ecols, CV_32FC1));
    764     band.reset(cvCreateMat(erows, ecols, CV_8UC1));
    765     mask.reset(cvCreateMat(erows, ecols, CV_8UC1));
    766     el_cross.reset(cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL));
    767 
    768     cvCopy( input_img, output_img );
    769     cvSet(mask,cvScalar(KNOWN,0,0,0));
    770     COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar);
    771     SET_BORDER1_C1(mask,uchar,0);
    772     cvSet(f,cvScalar(KNOWN,0,0,0));
    773     cvSet(t,cvScalar(1.0e6f,0,0,0));
    774     cvDilate(mask,band,el_cross,1);   // image with narrow band
    775     Heap=cv::makePtr<CvPriorityQueueFloat>();
    776     if (!Heap->Init(band))
    777         return;
    778     cvSub(band,mask,band,NULL);
    779     SET_BORDER1_C1(band,uchar,0);
    780     if (!Heap->Add(band))
    781         return;
    782     cvSet(f,cvScalar(BAND,0,0,0),band);
    783     cvSet(f,cvScalar(INSIDE,0,0,0),mask);
    784     cvSet(t,cvScalar(0,0,0,0),band);
    785 
    786     if( flags == cv::INPAINT_TELEA )
    787     {
    788         out.reset(cvCreateMat(erows, ecols, CV_8UC1));
    789         el_range.reset(cvCreateStructuringElementEx(2*range+1,2*range+1,
    790             range,range,CV_SHAPE_RECT,NULL));
    791         cvDilate(mask,out,el_range,1);
    792         cvSub(out,mask,out,NULL);
    793         Out=cv::makePtr<CvPriorityQueueFloat>();
    794         if (!Out->Init(out))
    795             return;
    796         if (!Out->Add(band))
    797             return;
    798         cvSub(out,band,out,NULL);
    799         SET_BORDER1_C1(out,uchar,0);
    800         icvCalcFMM(out,t,Out,true);
    801         icvTeleaInpaintFMM(mask,t,output_img,range,Heap);
    802     }
    803     else if (flags == cv::INPAINT_NS) {
    804         icvNSInpaintFMM(mask,t,output_img,range,Heap);
    805     } else {
    806         CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" );
    807     }
    808 }
    809 
    810 void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst,
    811                   double inpaintRange, int flags )
    812 {
    813     Mat src = _src.getMat(), mask = _mask.getMat();
    814     _dst.create( src.size(), src.type() );
    815     CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat();
    816     cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags );
    817 }
    818