C-API cleanup: inpaint algorithms in photo

This commit is contained in:
Maksim Shabunin 2024-10-01 20:02:03 +03:00
parent 658336b366
commit 807170d5c9

View File

@ -49,8 +49,8 @@
#include <type_traits> #include <type_traits>
#include "precomp.hpp" #include "precomp.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/photo/legacy/constants_c.h" using namespace cv;
#undef CV_MAT_ELEM_PTR_FAST #undef CV_MAT_ELEM_PTR_FAST
#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ #define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \
@ -74,7 +74,6 @@ min4( float a, float b, float c, float d )
return MIN(a,c); return MIN(a,c);
} }
#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c))
#define KNOWN 0 //known outside narrow band #define KNOWN 0 //known outside narrow band
#define BAND 1 //narrow band (known) #define BAND 1 //narrow band (known)
#define INSIDE 2 //unknown #define INSIDE 2 //unknown
@ -109,11 +108,11 @@ protected:
int next_order; int next_order;
public: public:
bool Add(const CvMat* f) { bool Add(const Mat &f) {
int i,j; int i,j;
for (i=0; i<f->rows; i++) { for (i=0; i<f.rows; i++) {
for (j=0; j<f->cols; j++) { for (j=0; j<f.cols; j++) {
if (CV_MAT_ELEM(*f,uchar,i,j)!=0) { if (f.at<uchar>(i, j)!=0) {
if (!Push(i,j,0)) return false; if (!Push(i,j,0)) return false;
} }
} }
@ -166,22 +165,22 @@ static inline float VectorLength(const cv::Point2f& v1)
//HEAP::iterator Heap_Iterator; //HEAP::iterator Heap_Iterator;
//HEAP Heap; //HEAP Heap;
static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t) static float FastMarching_solve(int i1,int j1,int i2,int j2, const Mat &f, const Mat &t)
{ {
double sol, a11, a22, m12; double sol, a11, a22, m12;
a11=CV_MAT_ELEM(*t,float,i1,j1); a11=t.at<float>(i1,j1);
a22=CV_MAT_ELEM(*t,float,i2,j2); a22=t.at<float>(i2,j2);
m12=MIN(a11,a22); m12=MIN(a11,a22);
if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE ) if( f.at<uchar>(i1,j1) != INSIDE )
if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) if( f.at<uchar>(i2,j2) != INSIDE )
if( fabs(a11-a22) >= 1.0 ) if( fabs(a11-a22) >= 1.0 )
sol = 1+m12; sol = 1+m12;
else else
sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5; sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5;
else else
sol = 1+a11; sol = 1+a11;
else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) else if( f.at<uchar>(i2,j2) != INSIDE )
sol = 1+a22; sol = 1+a22;
else else
sol = 1+m12; sol = 1+m12;
@ -193,14 +192,14 @@ static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, con
static void static void
icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) { icvCalcFMM(Mat &f, Mat &t, CvPriorityQueueFloat *Heap, bool negate) {
int i, j, ii = 0, jj = 0, q; int i, j, ii = 0, jj = 0, q;
float dist; float dist;
while (Heap->Pop(&ii,&jj)) { while (Heap->Pop(&ii,&jj)) {
unsigned known=(negate)?CHANGE:KNOWN; unsigned known=(negate)?CHANGE:KNOWN;
CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known; f.at<uchar>(ii,jj) = (uchar)known;
for (q=0; q<4; q++) { for (q=0; q<4; q++) {
i=0; j=0; i=0; j=0;
@ -208,26 +207,26 @@ icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
else if(q==1) {i=ii; j=jj-1;} else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;} else if(q==2) {i=ii+1; j=jj;}
else {i=ii; j=jj+1;} else {i=ii; j=jj+1;}
if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue; if ((i<=0)||(j<=0)||(i>f.rows)||(j>f.cols)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { if (f.at<uchar>(i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t), FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t), FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t)); FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist; t.at<float>(i,j) = dist;
CV_MAT_ELEM(*f,uchar,i,j) = BAND; f.at<uchar>(i,j) = BAND;
Heap->Push(i,j,dist); Heap->Push(i,j,dist);
} }
} }
} }
if (negate) { if (negate) {
for (i=0; i<f->rows; i++) { for (i=0; i<f.rows; i++) {
for(j=0; j<f->cols; j++) { for(j=0; j<f.cols; j++) {
if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) { if (f.at<uchar>(i,j) == CHANGE) {
CV_MAT_ELEM(*f,uchar,i,j) = KNOWN; f.at<uchar>(i,j) = KNOWN;
CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j); t.at<float>(i,j) = -t.at<float>(i,j);
} }
} }
} }
@ -236,53 +235,54 @@ icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
template <typename data_type> template <typename data_type>
static void static void
icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) { icvTeleaInpaintFMM(Mat &f, Mat &t, Mat &out, int range, CvPriorityQueueFloat *Heap ) {
int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
float dist; float dist;
if (CV_MAT_CN(out->type)==3) { if (out.channels()==3) {
typedef Vec<uchar, 3> PixelT;
while (Heap->Pop(&ii,&jj)) { while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; f.at<uchar>(ii,jj) = KNOWN;
for(q=0; q<4; q++) { for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;} if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;} else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;} else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;} else if(q==3) {i=ii; j=jj+1;}
if ((i<=0)||(j<=0)||(i>t->rows-1)||(j>t->cols-1)) continue; if ((i<=0)||(j<=0)||(i>t.rows-1)||(j>t.cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { if (f.at<uchar>(i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t), FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t), FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t)); FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist; t.at<float>(i,j) = dist;
cv::Point2f gradT[3]; cv::Point2f gradT[3];
for (color=0; color<=2; color++) { for (color=0; color<=2; color++) {
if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { if (f.at<uchar>(i,j+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { if (f.at<uchar>(i,j-1)!=INSIDE) {
gradT[color].x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; gradT[color].x=(float)((t.at<float>(i,j+1)-t.at<float>(i,j-1)))*0.5f;
} else { } else {
gradT[color].x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); gradT[color].x=(float)((t.at<float>(i,j+1)-t.at<float>(i,j)));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { if (f.at<uchar>(i,j-1)!=INSIDE) {
gradT[color].x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); gradT[color].x=(float)((t.at<float>(i,j)-t.at<float>(i,j-1)));
} else { } else {
gradT[color].x=0; gradT[color].x=0;
} }
} }
if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { if (f.at<uchar>(i+1,j)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { if (f.at<uchar>(i-1,j)!=INSIDE) {
gradT[color].y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; gradT[color].y=(float)((t.at<float>(i+1,j)-t.at<float>(i-1,j)))*0.5f;
} else { } else {
gradT[color].y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); gradT[color].y=(float)((t.at<float>(i+1,j)-t.at<float>(i,j)));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { if (f.at<uchar>(i-1,j)!=INSIDE) {
gradT[color].y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); gradT[color].y=(float)((t.at<float>(i,j)-t.at<float>(i-1,j)));
} else { } else {
gradT[color].y=0; gradT[color].y=0;
} }
@ -297,50 +297,50 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
float w,dst,lev,dir,sat; float w,dst,lev,dir,sat;
for (k=i-range; k<=i+range; k++) { for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==t->rows-2); int km=k-1+(k==1),kp=k-1-(k==t.rows-2);
for (l=j-range; l<=j+range; l++) { for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); int lm=l-1+(l==1),lp=l-1-(l==t.cols-2);
if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) { if (k>0&&l>0&&k<t.rows-1&&l<t.cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& if ((f.at<uchar>(k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
for (color=0; color<=2; color++) { for (color=0; color<=2; color++) {
r.y = (float)(i-k); r.y = (float)(i-k);
r.x = (float)(j-l); r.x = (float)(j-l);
dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r)))); dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r))));
lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); lev = (float)(1./(1+fabs(t.at<float>(k,l)-t.at<float>(i,j))));
dir=VectorScalMult(r,gradT[color]); dir=VectorScalMult(r,gradT[color]);
if (fabs(dir)<=0.01) dir=0.000001f; if (fabs(dir)<=0.01) dir=0.000001f;
w = (float)fabs(dst*lev*dir); w = (float)fabs(dst*lev*dir);
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { if (f.at<uchar>(k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
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; gradI.x=(float)((out.at<PixelT>(km,lp+1)[color]-out.at<PixelT>(km,lm-1)[color]))*2.0f;
} else { } else {
gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); gradI.x=(float)((out.at<PixelT>(km,lp+1)[color]-out.at<PixelT>(km,lm)[color]));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); gradI.x=(float)((out.at<PixelT>(km,lp)[color]-out.at<PixelT>(km,lm-1)[color]));
} else { } else {
gradI.x=0; gradI.x=0;
} }
} }
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { if (f.at<uchar>(k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
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; gradI.y=(float)((out.at<PixelT>(kp+1,lm)[color]-out.at<PixelT>(km-1,lm)[color]))*2.0f;
} else { } else {
gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); gradI.y=(float)((out.at<PixelT>(kp+1,lm)[color]-out.at<PixelT>(km,lm)[color]));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); gradI.y=(float)((out.at<PixelT>(kp,lm)[color]-out.at<PixelT>(km-1,lm)[color]));
} else { } else {
gradI.y=0; gradI.y=0;
} }
} }
Ia[color] += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,k-1,l-1,color)); Ia[color] += (float)w * (float)(out.at<PixelT>(k-1,l-1)[color]);
Jx[color] -= (float)w * (float)(gradI.x*r.x); Jx[color] -= (float)w * (float)(gradI.x*r.x);
Jy[color] -= (float)w * (float)(gradI.y*r.y); Jy[color] -= (float)w * (float)(gradI.y*r.y);
s[color] += w; s[color] += w;
@ -351,108 +351,108 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
} }
for (color=0; color<=2; color++) { for (color=0; color<=2; color++) {
sat = (float)(Ia[color]/s[color]+(Jx[color]+Jy[color])/(sqrt(Jx[color]*Jx[color]+Jy[color]*Jy[color])+1.0e-20f)); sat = (float)(Ia[color]/s[color]+(Jx[color]+Jy[color])/(sqrt(Jx[color]*Jx[color]+Jy[color]*Jy[color])+1.0e-20f));
CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = round_cast<uchar>(sat); out.at<PixelT>(i-1,j-1)[color] = round_cast<uchar>(sat);
} }
CV_MAT_ELEM(*f,uchar,i,j) = BAND; f.at<uchar>(i,j) = BAND;
Heap->Push(i,j,dist); Heap->Push(i,j,dist);
} }
} }
} }
} else if (CV_MAT_CN(out->type)==1) { } else if (out.channels()==1) {
while (Heap->Pop(&ii,&jj)) { while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; f.at<uchar>(ii,jj) = KNOWN;
for(q=0; q<4; q++) { for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;} if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;} else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;} else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;} else if(q==3) {i=ii; j=jj+1;}
if ((i<=0)||(j<=0)||(i>t->rows-1)||(j>t->cols-1)) continue; if ((i<=0)||(j<=0)||(i>t.rows-1)||(j>t.cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { if (f.at<uchar>(i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t), FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t), FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t)); FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist; t.at<float>(i,j) = dist;
for (color=0; color<=0; color++) { for (color=0; color<=0; color++) {
cv::Point2f gradI,gradT,r; cv::Point2f gradI,gradT,r;
float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { if (f.at<uchar>(i,j+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { if (f.at<uchar>(i,j-1)!=INSIDE) {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; gradT.x=(float)((t.at<float>(i,j+1)-t.at<float>(i,j-1)))*0.5f;
} else { } else {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); gradT.x=(float)((t.at<float>(i,j+1)-t.at<float>(i,j)));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { if (f.at<uchar>(i,j-1)!=INSIDE) {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); gradT.x=(float)((t.at<float>(i,j)-t.at<float>(i,j-1)));
} else { } else {
gradT.x=0; gradT.x=0;
} }
} }
if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { if (f.at<uchar>(i+1,j)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { if (f.at<uchar>(i-1,j)!=INSIDE) {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; gradT.y=(float)((t.at<float>(i+1,j)-t.at<float>(i-1,j)))*0.5f;
} else { } else {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); gradT.y=(float)((t.at<float>(i+1,j)-t.at<float>(i,j)));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { if (f.at<uchar>(i-1,j)!=INSIDE) {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); gradT.y=(float)((t.at<float>(i,j)-t.at<float>(i-1,j)));
} else { } else {
gradT.y=0; gradT.y=0;
} }
} }
for (k=i-range; k<=i+range; k++) { for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==t->rows-2); int km=k-1+(k==1),kp=k-1-(k==t.rows-2);
for (l=j-range; l<=j+range; l++) { for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); int lm=l-1+(l==1),lp=l-1-(l==t.cols-2);
if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) { if (k>0&&l>0&&k<t.rows-1&&l<t.cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& if ((f.at<uchar>(k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
r.y = (float)(i-k); r.y = (float)(i-k);
r.x = (float)(j-l); r.x = (float)(j-l);
dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r)))); dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r))));
lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); lev = (float)(1./(1+fabs(t.at<float>(k,l)-t.at<float>(i,j))));
dir=VectorScalMult(r,gradT); dir=VectorScalMult(r,gradT);
if (fabs(dir)<=0.01) dir=0.000001f; if (fabs(dir)<=0.01) dir=0.000001f;
w = (float)fabs(dst*lev*dir); w = (float)fabs(dst*lev*dir);
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { if (f.at<uchar>(k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm-1)))*2.0f; gradI.x=(float)((out.at<data_type>(km,lp+1)-out.at<data_type>(km,lm-1)))*2.0f;
} else { } else {
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm))); gradI.x=(float)((out.at<data_type>(km,lp+1)-out.at<data_type>(km,lm)));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp)-CV_MAT_ELEM(*out,data_type,km,lm-1))); gradI.x=(float)((out.at<data_type>(km,lp)-out.at<data_type>(km,lm-1)));
} else { } else {
gradI.x=0; gradI.x=0;
} }
} }
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { if (f.at<uchar>(k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)))*2.0f; gradI.y=(float)((out.at<data_type>(kp+1,lm)-out.at<data_type>(km-1,lm)))*2.0f;
} else { } else {
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,km,lm))); gradI.y=(float)((out.at<data_type>(kp+1,lm)-out.at<data_type>(km,lm)));
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm))); gradI.y=(float)((out.at<data_type>(kp,lm)-out.at<data_type>(km-1,lm)));
} else { } else {
gradI.y=0; gradI.y=0;
} }
} }
Ia += (float)w * (float)(CV_MAT_ELEM(*out,data_type,k-1,l-1)); Ia += (float)w * (float)(out.at<data_type>(k-1,l-1));
Jx -= (float)w * (float)(gradI.x*r.x); Jx -= (float)w * (float)(gradI.x*r.x);
Jy -= (float)w * (float)(gradI.y*r.y); Jy -= (float)w * (float)(gradI.y*r.y);
s += w; s += w;
@ -462,11 +462,11 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
} }
sat = (float)(Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)); sat = (float)(Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f));
{ {
CV_MAT_ELEM(*out,data_type,i-1,j-1) = round_cast<data_type>(sat); out.at<data_type>(i-1,j-1) = round_cast<data_type>(sat);
} }
} }
CV_MAT_ELEM(*f,uchar,i,j) = BAND; f.at<uchar>(i,j) = BAND;
Heap->Push(i,j,dist); Heap->Push(i,j,dist);
} }
} }
@ -476,28 +476,29 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
template <typename data_type> template <typename data_type>
static void static void
icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) { icvNSInpaintFMM(Mat &f, Mat &t, Mat &out, int range, CvPriorityQueueFloat *Heap) {
int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
float dist; float dist;
if (CV_MAT_CN(out->type)==3) { if (out.channels()==3) {
typedef Vec<uchar, 3> PixelT;
while (Heap->Pop(&ii,&jj)) { while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; f.at<uchar>(ii,jj) = KNOWN;
for(q=0; q<4; q++) { for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;} if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;} else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;} else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;} else if(q==3) {i=ii; j=jj+1;}
if ((i<=0)||(j<=0)||(i>t->rows-1)||(j>t->cols-1)) continue; if ((i<=0)||(j<=0)||(i>t.rows-1)||(j>t.cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { if (f.at<uchar>(i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t), FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t), FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t)); FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist; t.at<float>(i,j) = dist;
cv::Point2f gradI,r; cv::Point2f gradI,r;
float Ia[3]={0,0,0}; float Ia[3]={0,0,0};
@ -505,11 +506,11 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
float w,dst,dir; float w,dst,dir;
for (k=i-range; k<=i+range; k++) { for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==f->rows-2); int km=k-1+(k==1),kp=k-1-(k==f.rows-2);
for (l=j-range; l<=j+range; l++) { for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==f->cols-2); int lm=l-1+(l==1),lp=l-1-(l==f.cols-2);
if (k>0&&l>0&&k<f->rows-1&&l<f->cols-1) { if (k>0&&l>0&&k<f.rows-1&&l<f.cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& if ((f.at<uchar>(k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
for (color=0; color<=2; color++) { for (color=0; color<=2; color++) {
r.y=(float)(k-i); r.y=(float)(k-i);
@ -517,30 +518,30 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
dst = 1/(VectorLength(r)*VectorLength(r)+1); dst = 1/(VectorLength(r)*VectorLength(r)+1);
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { if (f.at<uchar>(k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+ gradI.x=(float)(abs(out.at<PixelT>(kp+1,lm)[color]-out.at<PixelT>(kp,lm)[color])+
abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); abs(out.at<PixelT>(kp,lm)[color]-out.at<PixelT>(km-1,lm)[color]));
} else { } else {
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; gradI.x=(float)(abs(out.at<PixelT>(kp+1,lm)[color]-out.at<PixelT>(kp,lm)[color]))*2.0f;
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
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; gradI.x=(float)(abs(out.at<PixelT>(kp,lm)[color]-out.at<PixelT>(km-1,lm)[color]))*2.0f;
} else { } else {
gradI.x=0; gradI.x=0;
} }
} }
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { if (f.at<uchar>(k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+ gradI.y=(float)(abs(out.at<PixelT>(km,lp+1)[color]-out.at<PixelT>(km,lm)[color])+
abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); abs(out.at<PixelT>(km,lm)[color]-out.at<PixelT>(km,lm-1)[color]));
} else { } else {
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; gradI.y=(float)(abs(out.at<PixelT>(km,lp+1)[color]-out.at<PixelT>(km,lm)[color]))*2.0f;
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
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; gradI.y=(float)(abs(out.at<PixelT>(km,lm)[color]-out.at<PixelT>(km,lm-1)[color]))*2.0f;
} else { } else {
gradI.y=0; gradI.y=0;
} }
@ -555,7 +556,7 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
} }
w = dst*dir; w = dst*dir;
Ia[color] += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,k-1,l-1,color)); Ia[color] += (float)w * (float)(out.at<PixelT>(k-1,l-1)[color]);
s[color] += w; s[color] += w;
} }
} }
@ -563,74 +564,74 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
} }
} }
for (color=0; color<=2; color++) { for (color=0; color<=2; color++) {
CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast<uchar>((double)Ia[color]/s[color]); out.at<PixelT>(i-1,j-1)[color] = cv::saturate_cast<uchar>((double)Ia[color]/s[color]);
} }
CV_MAT_ELEM(*f,uchar,i,j) = BAND; f.at<uchar>(i,j) = BAND;
Heap->Push(i,j,dist); Heap->Push(i,j,dist);
} }
} }
} }
} else if (CV_MAT_CN(out->type)==1) { } else if (out.channels()==1) {
while (Heap->Pop(&ii,&jj)) { while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; f.at<uchar>(ii,jj) = KNOWN;
for(q=0; q<4; q++) { for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;} if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;} else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;} else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;} else if(q==3) {i=ii; j=jj+1;}
if ((i<=0)||(j<=0)||(i>t->rows-1)||(j>t->cols-1)) continue; if ((i<=0)||(j<=0)||(i>t.rows-1)||(j>t.cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { if (f.at<uchar>(i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t), FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t), FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t)); FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist; t.at<float>(i,j) = dist;
{ {
cv::Point2f gradI,r; cv::Point2f gradI,r;
float Ia=0,s=1.0e-20f,w,dst,dir; float Ia=0,s=1.0e-20f,w,dst,dir;
for (k=i-range; k<=i+range; k++) { for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==t->rows-2); int km=k-1+(k==1),kp=k-1-(k==t.rows-2);
for (l=j-range; l<=j+range; l++) { for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); int lm=l-1+(l==1),lp=l-1-(l==t.cols-2);
if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) { if (k>0&&l>0&&k<t.rows-1&&l<t.cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& if ((f.at<uchar>(k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
r.y=(float)(i-k); r.y=(float)(i-k);
r.x=(float)(j-l); r.x=(float)(j-l);
dst = 1/(VectorLength(r)*VectorLength(r)+1); dst = 1/(VectorLength(r)*VectorLength(r)+1);
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { if (f.at<uchar>(k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
gradI.x=(float)(std::abs(CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,kp,lm))+ gradI.x=(float)(std::abs(out.at<data_type>(kp+1,lm)-out.at<data_type>(kp,lm))+
std::abs(CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm))); std::abs(out.at<data_type>(kp,lm)-out.at<data_type>(km-1,lm)));
} else { } else {
gradI.x=(float)(std::abs(CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,kp,lm)))*2.0f; gradI.x=(float)(std::abs(out.at<data_type>(kp+1,lm)-out.at<data_type>(kp,lm)))*2.0f;
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { if (f.at<uchar>(k-1,l)!=INSIDE) {
gradI.x=(float)(std::abs(CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)))*2.0f; gradI.x=(float)(std::abs(out.at<data_type>(kp,lm)-out.at<data_type>(km-1,lm)))*2.0f;
} else { } else {
gradI.x=0; gradI.x=0;
} }
} }
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { if (f.at<uchar>(k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
gradI.y=(float)(std::abs(CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm))+ gradI.y=(float)(std::abs(out.at<data_type>(km,lp+1)-out.at<data_type>(km,lm))+
std::abs(CV_MAT_ELEM(*out,data_type,km,lm)-CV_MAT_ELEM(*out,data_type,km,lm-1))); std::abs(out.at<data_type>(km,lm)-out.at<data_type>(km,lm-1)));
} else { } else {
gradI.y=(float)(std::abs(CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm)))*2.0f; gradI.y=(float)(std::abs(out.at<data_type>(km,lp+1)-out.at<data_type>(km,lm)))*2.0f;
} }
} else { } else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { if (f.at<uchar>(k,l-1)!=INSIDE) {
gradI.y=(float)(std::abs(CV_MAT_ELEM(*out,data_type,km,lm)-CV_MAT_ELEM(*out,data_type,km,lm-1)))*2.0f; gradI.y=(float)(std::abs(out.at<data_type>(km,lm)-out.at<data_type>(km,lm-1)))*2.0f;
} else { } else {
gradI.y=0; gradI.y=0;
} }
@ -645,16 +646,16 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
} }
w = dst*dir; w = dst*dir;
Ia += (float)w * (float)(CV_MAT_ELEM(*out,data_type,k-1,l-1)); Ia += (float)w * (float)(out.at<data_type>(k-1,l-1));
s += w; s += w;
} }
} }
} }
} }
CV_MAT_ELEM(*out,data_type,i-1,j-1) = cv::saturate_cast<data_type>((double)Ia/s); out.at<data_type>(i-1,j-1) = cv::saturate_cast<data_type>((double)Ia/s);
} }
CV_MAT_ELEM(*f,uchar,i,j) = BAND; f.at<uchar>(i,j) = BAND;
Heap->Push(i,j,dist); Heap->Push(i,j,dist);
} }
} }
@ -665,99 +666,94 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
#define SET_BORDER1_C1(image,type,value) {\ #define SET_BORDER1_C1(image,type,value) {\
int i,j;\ int i,j;\
for(j=0; j<image->cols; j++) {\ for(j=0; j<image.cols; j++) {\
CV_MAT_ELEM(*image,type,0,j) = value;\ image.at<type>(0,j) = value;\
}\ }\
for (i=1; i<image->rows-1; i++) {\ for (i=1; i<image.rows-1; i++) {\
CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\ image.at<type>(i,0) = image.at<type>(i,image.cols-1) = value;\
}\ }\
for(j=0; j<image->cols; j++) {\ for(j=0; j<image.cols; j++) {\
CV_MAT_ELEM(*image,type,erows-1,j) = value;\ image.at<type>(erows-1,j) = value;\
}\ }\
} }
#define COPY_MASK_BORDER1_C1(src,dst,type) {\ #define COPY_MASK_BORDER1_C1(src,dst,type) {\
int i,j;\ int i,j;\
for (i=0; i<src->rows; i++) {\ for (i=0; i<src.rows; i++) {\
for(j=0; j<src->cols; j++) {\ for(j=0; j<src.cols; j++) {\
if (CV_MAT_ELEM(*src,type,i,j)!=0)\ if (src.at<type>(i,j)!=0)\
CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\ dst.at<type>(i+1,j+1) = INSIDE;\
}\ }\
}\ }\
} }
static void static void
icvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img, icvInpaint( const Mat &input_img, const Mat &inpaint_mask, Mat &output_img,
double inpaintRange, int flags ) double inpaintRange, int flags )
{ {
cv::Ptr<CvMat> mask, band, f, t, out; cv::Mat mask, band, f, t, out;
cv::Ptr<CvPriorityQueueFloat> Heap, Out; cv::Ptr<CvPriorityQueueFloat> Heap, Out;
cv::Mat el_range, el_cross; // structuring elements for dilate cv::Mat el_range, el_cross; // structuring elements for dilate
CvMat input_hdr, mask_hdr, output_hdr;
CvMat* input_img, *inpaint_mask, *output_img;
int range=cvRound(inpaintRange); int range=cvRound(inpaintRange);
int erows, ecols; int erows, ecols;
input_img = cvGetMat( _input_img, &input_hdr ); if((input_img.size() != output_img.size()) || (input_img.size() != inpaint_mask.size()))
inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr );
output_img = cvGetMat( _output_img, &output_hdr );
if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask))
CV_Error( cv::Error::StsUnmatchedSizes, "All the input and output images must have the same size" ); CV_Error( cv::Error::StsUnmatchedSizes, "All the input and output images must have the same size" );
if( (CV_MAT_TYPE(input_img->type) != CV_8U && if( (input_img.type() != CV_8U &&
CV_MAT_TYPE(input_img->type) != CV_16U && input_img.type() != CV_16U &&
CV_MAT_TYPE(input_img->type) != CV_32F && input_img.type() != CV_32F &&
CV_MAT_TYPE(input_img->type) != CV_8UC3) || input_img.type() != CV_8UC3) ||
!CV_ARE_TYPES_EQ(input_img,output_img) ) (input_img.type() != output_img.type()) )
CV_Error( cv::Error::StsUnsupportedFormat, CV_Error( cv::Error::StsUnsupportedFormat,
"8-bit, 16-bit unsigned or 32-bit float 1-channel and 8-bit 3-channel input/output images are supported" ); "8-bit, 16-bit unsigned or 32-bit float 1-channel and 8-bit 3-channel input/output images are supported" );
if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 ) if( inpaint_mask.type() != CV_8UC1 )
CV_Error( cv::Error::StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" ); CV_Error( cv::Error::StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
range = MAX(range,1); range = MAX(range,1);
range = MIN(range,100); range = MIN(range,100);
ecols = input_img->cols + 2; ecols = input_img.cols + 2;
erows = input_img->rows + 2; erows = input_img.rows + 2;
f.reset(cvCreateMat(erows, ecols, CV_8UC1)); f.create(erows, ecols, CV_8UC1);
t.reset(cvCreateMat(erows, ecols, CV_32FC1)); t.create(erows, ecols, CV_32FC1);
band.reset(cvCreateMat(erows, ecols, CV_8UC1)); band.create(erows, ecols, CV_8UC1);
mask.reset(cvCreateMat(erows, ecols, CV_8UC1)); mask.create(erows, ecols, CV_8UC1);
el_cross = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3), cv::Point(1, 1)); el_cross = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3), cv::Point(1, 1));
cvCopy( input_img, output_img ); input_img.copyTo( output_img );
cvSet(mask,cvScalar(KNOWN,0,0,0)); mask.setTo(Scalar(KNOWN,0,0,0));
COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar); COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar);
SET_BORDER1_C1(mask,uchar,0); SET_BORDER1_C1(mask,uchar,0);
cvSet(f,cvScalar(KNOWN,0,0,0)); f.setTo(Scalar(KNOWN,0,0,0));
cvSet(t,cvScalar(1.0e6f,0,0,0)); t.setTo(Scalar(1.0e6f,0,0,0));
cv::dilate(cv::cvarrToMat(mask), cv::cvarrToMat(band), el_cross, cv::Point(1, 1)); cv::dilate(mask, band, el_cross, cv::Point(1, 1));
Heap=cv::makePtr<CvPriorityQueueFloat>(); Heap=cv::makePtr<CvPriorityQueueFloat>();
cvSub(band,mask,band,NULL); subtract(band, mask, band);
SET_BORDER1_C1(band,uchar,0); SET_BORDER1_C1(band,uchar,0);
if (!Heap->Add(band)) if (!Heap->Add(band))
return; return;
cvSet(f,cvScalar(BAND,0,0,0),band);
cvSet(f,cvScalar(INSIDE,0,0,0),mask); f.setTo(Scalar(BAND,0,0,0),band);
cvSet(t,cvScalar(0,0,0,0),band); f.setTo(Scalar(INSIDE,0,0,0),mask);
t.setTo(Scalar(0,0,0,0),band);
if( flags == cv::INPAINT_TELEA ) if( flags == cv::INPAINT_TELEA )
{ {
out.reset(cvCreateMat(erows, ecols, CV_8UC1)); out.create(erows, ecols, CV_8UC1);
el_range = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2 * range + 1, 2 * range + 1)); el_range = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2 * range + 1, 2 * range + 1));
cv::dilate(cv::cvarrToMat(mask), cv::cvarrToMat(out), el_range); cv::dilate(mask, out, el_range);
cvSub(out,mask,out,NULL); subtract(out, mask, out);
Out=cv::makePtr<CvPriorityQueueFloat>(); Out=cv::makePtr<CvPriorityQueueFloat>();
if (!Out->Add(band)) if (!Out->Add(band))
return; return;
cvSub(out,band,out,NULL); subtract(out, band, out);
SET_BORDER1_C1(out,uchar,0); SET_BORDER1_C1(out,uchar,0);
icvCalcFMM(out,t,Out,true); icvCalcFMM(out,t,Out,true);
switch(CV_MAT_DEPTH(output_img->type)) switch(output_img.depth())
{ {
case CV_8U: case CV_8U:
icvTeleaInpaintFMM<uchar>(mask,t,output_img,range,Heap); icvTeleaInpaintFMM<uchar>(mask,t,output_img,range,Heap);
@ -773,7 +769,7 @@ icvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_
} }
} }
else if (flags == cv::INPAINT_NS) { else if (flags == cv::INPAINT_NS) {
switch(CV_MAT_DEPTH(output_img->type)) switch(output_img.depth())
{ {
case CV_8U: case CV_8U:
icvNSInpaintFMM<uchar>(mask,t,output_img,range,Heap); icvNSInpaintFMM<uchar>(mask,t,output_img,range,Heap);
@ -788,7 +784,7 @@ icvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_
CV_Error( cv::Error::StsBadArg, "Unsupported format of the input image" ); CV_Error( cv::Error::StsBadArg, "Unsupported format of the input image" );
} }
} else { } else {
CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" ); CV_Error( cv::Error::StsBadArg, "The flags argument must be one of INPAINT_TELEA or INPAINT_NS" );
} }
} }
@ -800,6 +796,5 @@ void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst,
Mat src = _src.getMat(), mask = _mask.getMat(); Mat src = _src.getMat(), mask = _mask.getMat();
_dst.create( src.size(), src.type() ); _dst.create( src.size(), src.type() );
Mat dst = _dst.getMat(); Mat dst = _dst.getMat();
CvMat c_src = cvMat(src), c_mask = cvMat(mask), c_dst = cvMat(dst); icvInpaint( src, mask, dst, inpaintRange, flags );
icvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags );
} }