Skip to content

Commit 2ddaaf6

Browse files
belgravitonsovrasov
authored andcommitted
Inpainting support for any 1-channel input images
1 parent 19464a3 commit 2ddaaf6

File tree

2 files changed

+37
-22
lines changed

2 files changed

+37
-22
lines changed

modules/photo/include/opencv2/photo.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ enum
8989

9090
/** @brief Restores the selected region in an image using the region neighborhood.
9191
92-
@param src Input 8-bit 1-channel or 3-channel image.
92+
@param src Input any 1-channel or 8-bit 3-channel image.
9393
@param inpaintMask Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that
9494
needs to be inpainted.
9595
@param dst Output image with the same size and type as src .

modules/photo/src/inpaint.cpp

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ min4( float a, float b, float c, float d )
6767
#define INSIDE 2 //unknown
6868
#define CHANGE 3 //servise
6969

70+
// Processing data types
71+
typedef double data_type;
72+
int data_type_cv = CV_64F;
73+
7074
typedef struct CvHeapElem
7175
{
7276
float T;
@@ -463,31 +467,31 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
463467

464468
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
465469
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
466-
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
470+
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm-1)))*2.0f;
467471
} else {
468-
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)));
472+
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm)));
469473
}
470474
} else {
471475
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
472-
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
476+
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp)-CV_MAT_ELEM(*out,data_type,km,lm-1)));
473477
} else {
474478
gradI.x=0;
475479
}
476480
}
477481
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
478482
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
479-
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
483+
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)))*2.0f;
480484
} else {
481-
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm)));
485+
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,km,lm)));
482486
}
483487
} else {
484488
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
485-
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
489+
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)));
486490
} else {
487491
gradI.y=0;
488492
}
489493
}
490-
Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
494+
Ia += (float)w * (float)(CV_MAT_ELEM(*out,data_type,km,lm));
491495
Jx -= (float)w * (float)(gradI.x*r.x);
492496
Jy -= (float)w * (float)(gradI.y*r.y);
493497
s += w;
@@ -497,7 +501,7 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
497501
}
498502
sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
499503
{
500-
CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast<uchar>(sat);
504+
CV_MAT_ELEM(*out,data_type,i-1,j-1) = cv::saturate_cast<data_type>(sat);
501505
}
502506
}
503507

@@ -640,28 +644,28 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
640644

641645
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
642646
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
643-
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+
644-
abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
647+
gradI.x=(float)(abs(CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,kp,lm))+
648+
abs(CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)));
645649
} else {
646-
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f;
650+
gradI.x=(float)(abs(CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,kp,lm)))*2.0f;
647651
}
648652
} else {
649653
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
650-
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
654+
gradI.x=(float)(abs(CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)))*2.0f;
651655
} else {
652656
gradI.x=0;
653657
}
654658
}
655659
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
656660
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
657-
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+
658-
abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
661+
gradI.y=(float)(abs(CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm))+
662+
abs(CV_MAT_ELEM(*out,data_type,km,lm)-CV_MAT_ELEM(*out,data_type,km,lm-1)));
659663
} else {
660-
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f;
664+
gradI.y=(float)(abs(CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm)))*2.0f;
661665
}
662666
} else {
663667
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
664-
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
668+
gradI.y=(float)(abs(CV_MAT_ELEM(*out,data_type,km,lm)-CV_MAT_ELEM(*out,data_type,km,lm-1)))*2.0f;
665669
} else {
666670
gradI.y=0;
667671
}
@@ -676,13 +680,13 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
676680
dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
677681
}
678682
w = dst*dir;
679-
Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
683+
Ia += (float)w * (float)(CV_MAT_ELEM(*out,data_type,km,lm));
680684
s += w;
681685
}
682686
}
683687
}
684688
}
685-
CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast<uchar>((double)Ia/s);
689+
CV_MAT_ELEM(*out,data_type,i-1,j-1) = cv::saturate_cast<data_type>((double)Ia/s);
686690
}
687691

688692
CV_MAT_ELEM(*f,uchar,i,j) = BAND;
@@ -744,11 +748,11 @@ cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_i
744748
if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask))
745749
CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" );
746750

747-
if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 &&
751+
if( (CV_MAT_CN(input_img->type) != 1 &&
748752
CV_MAT_TYPE(input_img->type) != CV_8UC3) ||
749753
!CV_ARE_TYPES_EQ(input_img,output_img) )
750754
CV_Error( CV_StsUnsupportedFormat,
751-
"Only 8-bit 1-channel and 3-channel input/output images are supported" );
755+
"Any 1-channel and 8-bit 3-channel input/output images are supported" );
752756

753757
if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
754758
CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
@@ -815,6 +819,17 @@ void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst,
815819
Mat src = _src.getMat(), mask = _mask.getMat();
816820
_dst.create( src.size(), src.type() );
817821
Mat dst = _dst.getMat();
818-
CvMat c_src = src, c_mask = mask, c_dst = dst;
822+
823+
Mat src_temp;
824+
if (src.channels() == 1) {
825+
src.convertTo(src_temp, data_type_cv);
826+
} else
827+
src_temp = src.clone();
828+
829+
Mat dst_temp = Mat::zeros(src_temp.size(), src_temp.type());
830+
CvMat c_src = src_temp, c_mask = mask, c_dst = dst_temp;
819831
cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags );
832+
833+
if (src.channels() == 1) dst_temp.convertTo(dst_temp, src.type());
834+
dst_temp.copyTo(dst);
820835
}

0 commit comments

Comments
 (0)