1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective icvers.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
42 /* ////////////////////////////////////////////////////////////////////
44 // Geometrical transforms on images and matrices: rotation, zoom etc.
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))
55 min4( float a, float b, float c, float d )
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
68 typedef struct CvHeapElem
72 struct CvHeapElem* prev;
73 struct CvHeapElem* next;
78 class CvPriorityQueueFloat
81 CvHeapElem *mem,*empty,*head,*tail;
85 bool Init( const CvMat* f )
88 for( i = num = 0; i < f->rows; i++ )
90 for( j = 0; j < f->cols; j++ )
91 num += CV_MAT_ELEM(*f,uchar,i,j)!=0;
93 if (num<=0) return false;
94 mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem));
95 if (mem==NULL) return false;
98 head->i = head->j = -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;
110 tail->i = tail->j = -1;
111 tail->prev = mem+i-1;
117 bool Add(const CvMat* f) {
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;
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;
134 add->prev->next = add->next;
135 add->next->prev = add->prev;
137 add->prev = tmp->prev;
139 add->prev->next = add;
140 add->next->prev = add;
148 // printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in);
152 bool Pop(int *i, int *j) {
153 CvHeapElem *tmp=head->next;
154 if (empty==tmp) return false;
157 tmp->prev->next = tmp->next;
158 tmp->next->prev = tmp->prev;
159 tmp->prev = empty->prev;
161 tmp->prev->next = tmp;
162 tmp->next->prev = tmp;
165 // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
169 bool Pop(int *i, int *j, float *T) {
170 CvHeapElem *tmp=head->next;
171 if (empty==tmp) return false;
175 tmp->prev->next = tmp->next;
176 tmp->next->prev = tmp->prev;
177 tmp->prev = empty->prev;
179 tmp->prev->next = tmp;
180 tmp->next->prev = tmp;
183 // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
187 CvPriorityQueueFloat(void) {
189 mem=empty=head=tail=NULL;
192 ~CvPriorityQueueFloat(void)
198 inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) {
199 return v1.x*v2.x+v1.y*v2.y;
202 inline float VectorLength(CvPoint2D32f v1) {
203 return v1.x*v1.x+v1.y*v1.y;
206 ///////////////////////////////////////////////////////////////////////////////////////////
207 //HEAP::iterator Heap_Iterator;
210 float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t)
212 double sol, a11, a22, m12;
213 a11=CV_MAT_ELEM(*t,float,i1,j1);
214 a22=CV_MAT_ELEM(*t,float,i2,j2);
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 )
222 sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5;
225 else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
233 /////////////////////////////////////////////////////////////////////////////////////
237 icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
238 int i, j, ii = 0, jj = 0, q;
241 while (Heap->Pop(&ii,&jj)) {
243 unsigned known=(negate)?CHANGE:KNOWN;
244 CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known;
246 for (q=0; q<4; q++) {
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;}
252 if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue;
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);
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);
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;
284 if (CV_MAT_CN(out->type)==3) {
286 while (Heap->Pop(&ii,&jj)) {
288 CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
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;
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;
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;
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;
311 gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
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)));
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;
324 gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
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)));
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)) {
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))));
346 dir=VectorScalMult(r,gradT);
347 if (fabs(dir)<=0.01) dir=0.000001f;
348 w = (float)fabs(dst*lev*dir);
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;
354 gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
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)));
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;
367 gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
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)));
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);
384 sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
386 int isat = cvRound(sat);
387 CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = CV_CAST_8U(isat);
391 CV_MAT_ELEM(*f,uchar,i,j) = BAND;
392 Heap->Push(i,j,dist);
397 } else if (CV_MAT_CN(out->type)==1) {
399 while (Heap->Pop(&ii,&jj)) {
401 CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
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;
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;
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;
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;
424 gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
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)));
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;
437 gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
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)));
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)) {
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))));
459 dir=VectorScalMult(r,gradT);
460 if (fabs(dir)<=0.01) dir=0.000001f;
461 w = (float)fabs(dst*lev*dir);
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;
467 gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)));
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)));
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;
480 gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm)));
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)));
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);
497 sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
499 int isat = cvRound(sat);
500 CV_MAT_ELEM(*out,uchar,i-1,j-1) = CV_CAST_8U(isat);
504 CV_MAT_ELEM(*f,uchar,i,j) = BAND;
505 Heap->Push(i,j,dist);
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;
518 if (CV_MAT_CN(out->type)==3) {
520 while (Heap->Pop(&ii,&jj)) {
522 CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
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;
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;
537 for (color=0; color<=2; color++) {
538 CvPoint2D32f gradI,r;
539 float Ia=0,s=1.0e-20f,w,dst,dir;
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)) {
551 dst = 1/(VectorLength(r)*VectorLength(r)+1);
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)));
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;
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;
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)));
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;
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;
583 dir=VectorScalMult(r,gradI);
585 if (fabs(dir)<=0.01) {
588 dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
591 Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
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);
603 CV_MAT_ELEM(*f,uchar,i,j) = BAND;
604 Heap->Push(i,j,dist);
609 } else if (CV_MAT_CN(out->type)==1) {
611 while (Heap->Pop(&ii,&jj)) {
613 CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
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;
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;
629 CvPoint2D32f gradI,r;
630 float Ia=0,s=1.0e-20f,w,dst,dir;
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)) {
642 dst = 1/(VectorLength(r)*VectorLength(r)+1);
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)));
649 gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f;
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;
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)));
663 gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f;
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;
674 dir=VectorScalMult(r,gradI);
676 if (fabs(dir)<=0.01) {
679 dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
682 Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
689 int out_val = cvRound((double)Ia/s);
690 CV_MAT_ELEM(*out,uchar,i-1,j-1) = CV_CAST_8U(out_val);
694 CV_MAT_ELEM(*f,uchar,i,j) = BAND;
695 Heap->Push(i,j,dist);
703 #define SET_BORDER1_C1(image,type,value) {\
705 for(j=0; j<image->cols; j++) {\
706 CV_MAT_ELEM(*image,type,0,j) = value;\
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;\
711 for(j=0; j<image->cols; j++) {\
712 CV_MAT_ELEM(*image,type,erows-1,j) = value;\
716 #define COPY_MASK_BORDER1_C1(src,dst,type) {\
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;\
728 cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img,
729 double inpaintRange, int flags )
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;
735 CV_FUNCNAME( "cvInpaint" );
739 CvMat input_hdr, mask_hdr, output_hdr;
740 CvMat* input_img, *inpaint_mask, *output_img;
741 int range=cvRound(inpaintRange);
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 ));
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" );
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" );
757 if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
758 CV_ERROR( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
760 range = MAX(range,1);
761 range = MIN(range,100);
763 ecols = input_img->cols + 2;
764 erows = input_img->rows + 2;
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));
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))
782 cvSub(band,mask,band,NULL);
783 SET_BORDER1_C1(band,uchar,0);
784 if (!Heap->Add(band))
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);
790 if( flags == CV_INPAINT_TELEA )
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;
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);
808 icvNSInpaintFMM(mask,t,output_img,range,Heap);
814 cvReleaseStructuringElement(&el_cross);
815 cvReleaseStructuringElement(&el_range);