Skip to content

Commit 37b1bc9

Browse files
committed
Merge pull request opencv#8776 from sovrasov:inpaint_adv_formats
2 parents 27649de + d9ffc4c commit 37b1bc9

File tree

3 files changed

+76
-25
lines changed

3 files changed

+76
-25
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 8-bit, 16-bit unsigned or 32-bit float 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: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
277277
}
278278
}
279279

280-
280+
template <typename data_type>
281281
static void
282282
icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) {
283283
int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
@@ -463,31 +463,31 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
463463

464464
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
465465
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;
466+
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm-1)))*2.0f;
467467
} else {
468-
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)));
468+
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm)));
469469
}
470470
} else {
471471
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)));
472+
gradI.x=(float)((CV_MAT_ELEM(*out,data_type,km,lp)-CV_MAT_ELEM(*out,data_type,km,lm-1)));
473473
} else {
474474
gradI.x=0;
475475
}
476476
}
477477
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
478478
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;
479+
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)))*2.0f;
480480
} else {
481-
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm)));
481+
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,km,lm)));
482482
}
483483
} else {
484484
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)));
485+
gradI.y=(float)((CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)));
486486
} else {
487487
gradI.y=0;
488488
}
489489
}
490-
Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
490+
Ia += (float)w * (float)(CV_MAT_ELEM(*out,data_type,km,lm));
491491
Jx -= (float)w * (float)(gradI.x*r.x);
492492
Jy -= (float)w * (float)(gradI.y*r.y);
493493
s += w;
@@ -497,7 +497,7 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
497497
}
498498
sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
499499
{
500-
CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast<uchar>(sat);
500+
CV_MAT_ELEM(*out,data_type,i-1,j-1) = cv::saturate_cast<data_type>(sat);
501501
}
502502
}
503503

@@ -509,7 +509,7 @@ icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQu
509509
}
510510
}
511511

512-
512+
template <typename data_type>
513513
static void
514514
icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) {
515515
int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
@@ -640,28 +640,28 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
640640

641641
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
642642
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)));
643+
gradI.x=(float)(std::abs(CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,kp,lm))+
644+
std::abs(CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)));
645645
} else {
646-
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f;
646+
gradI.x=(float)(std::abs(CV_MAT_ELEM(*out,data_type,kp+1,lm)-CV_MAT_ELEM(*out,data_type,kp,lm)))*2.0f;
647647
}
648648
} else {
649649
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;
650+
gradI.x=(float)(std::abs(CV_MAT_ELEM(*out,data_type,kp,lm)-CV_MAT_ELEM(*out,data_type,km-1,lm)))*2.0f;
651651
} else {
652652
gradI.x=0;
653653
}
654654
}
655655
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
656656
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)));
657+
gradI.y=(float)(std::abs(CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm))+
658+
std::abs(CV_MAT_ELEM(*out,data_type,km,lm)-CV_MAT_ELEM(*out,data_type,km,lm-1)));
659659
} else {
660-
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f;
660+
gradI.y=(float)(std::abs(CV_MAT_ELEM(*out,data_type,km,lp+1)-CV_MAT_ELEM(*out,data_type,km,lm)))*2.0f;
661661
}
662662
} else {
663663
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;
664+
gradI.y=(float)(std::abs(CV_MAT_ELEM(*out,data_type,km,lm)-CV_MAT_ELEM(*out,data_type,km,lm-1)))*2.0f;
665665
} else {
666666
gradI.y=0;
667667
}
@@ -676,13 +676,13 @@ icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueue
676676
dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
677677
}
678678
w = dst*dir;
679-
Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
679+
Ia += (float)w * (float)(CV_MAT_ELEM(*out,data_type,km,lm));
680680
s += w;
681681
}
682682
}
683683
}
684684
}
685-
CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast<uchar>((double)Ia/s);
685+
CV_MAT_ELEM(*out,data_type,i-1,j-1) = cv::saturate_cast<data_type>((double)Ia/s);
686686
}
687687

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

747-
if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 &&
747+
if( (CV_MAT_TYPE(input_img->type) != CV_8U &&
748+
CV_MAT_TYPE(input_img->type) != CV_16U &&
749+
CV_MAT_TYPE(input_img->type) != CV_32F &&
748750
CV_MAT_TYPE(input_img->type) != CV_8UC3) ||
749751
!CV_ARE_TYPES_EQ(input_img,output_img) )
750752
CV_Error( CV_StsUnsupportedFormat,
751-
"Only 8-bit 1-channel and 3-channel input/output images are supported" );
753+
"8-bit, 16-bit unsigned or 32-bit float 1-channel and 8-bit 3-channel input/output images are supported" );
752754

753755
if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
754756
CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
@@ -798,10 +800,36 @@ cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_i
798800
cvSub(out,band,out,NULL);
799801
SET_BORDER1_C1(out,uchar,0);
800802
icvCalcFMM(out,t,Out,true);
801-
icvTeleaInpaintFMM(mask,t,output_img,range,Heap);
803+
switch(CV_MAT_DEPTH(output_img->type))
804+
{
805+
case CV_8U:
806+
icvTeleaInpaintFMM<uchar>(mask,t,output_img,range,Heap);
807+
break;
808+
case CV_16U:
809+
icvTeleaInpaintFMM<ushort>(mask,t,output_img,range,Heap);
810+
break;
811+
case CV_32F:
812+
icvTeleaInpaintFMM<float>(mask,t,output_img,range,Heap);
813+
break;
814+
default:
815+
CV_Error( cv::Error::StsBadArg, "Unsupportedformat of the input image" );
816+
}
802817
}
803818
else if (flags == cv::INPAINT_NS) {
804-
icvNSInpaintFMM(mask,t,output_img,range,Heap);
819+
switch(CV_MAT_DEPTH(output_img->type))
820+
{
821+
case CV_8U:
822+
icvNSInpaintFMM<uchar>(mask,t,output_img,range,Heap);
823+
break;
824+
case CV_16U:
825+
icvNSInpaintFMM<ushort>(mask,t,output_img,range,Heap);
826+
break;
827+
case CV_32F:
828+
icvNSInpaintFMM<float>(mask,t,output_img,range,Heap);
829+
break;
830+
default:
831+
CV_Error( cv::Error::StsBadArg, "Unsupported format of the input image" );
832+
}
805833
} else {
806834
CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" );
807835
}

modules/photo/test/test_inpaint.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,26 @@ void CV_InpaintTest::run( int )
117117
}
118118

119119
TEST(Photo_Inpaint, regression) { CV_InpaintTest test; test.safe_run(); }
120+
121+
typedef testing::TestWithParam<std::tr1::tuple<int> > formats;
122+
123+
TEST_P(formats, 1c)
124+
{
125+
const int type = std::tr1::get<0>(GetParam());
126+
Mat src(100, 100, type);
127+
src.setTo(Scalar::all(128));
128+
Mat ref = src.clone();
129+
Mat dst, mask = Mat::zeros(src.size(), CV_8U);
130+
131+
circle(src, Point(50, 50), 5, Scalar(200), 6);
132+
circle(mask, Point(50, 50), 5, Scalar(200), 6);
133+
inpaint(src, mask, dst, 10, INPAINT_NS);
134+
135+
Mat dst2;
136+
inpaint(src, mask, dst2, 10, INPAINT_TELEA);
137+
138+
ASSERT_LE(cv::norm(dst, ref, NORM_INF), 3.);
139+
ASSERT_LE(cv::norm(dst2, ref, NORM_INF), 3.);
140+
}
141+
142+
INSTANTIATE_TEST_CASE_P(Photo_Inpaint, formats, testing::Values(CV_32F, CV_16U, CV_8U));

0 commit comments

Comments
 (0)