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