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 = -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 } 822