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