【第二部分 图像处理】第4章 Opencv图像处理高阶【3图像修复】
2018-03-25 08:28
1116 查看
3.1图像修复概述
在实际应用中,我们的图像常常会被噪声腐蚀,这些噪声或是镜头上的灰尘或水滴,或是旧照片的划痕,或者是图像遭到人为的涂画(比如马赛克)或者图像的部分本身已经损坏。如果我们想让这些受到破坏的额图片尽可能恢复到原样,Opencv能帮我们做到吗?OpenCV真的有这个妙手回春的功能!别以为图像修补的工作只能用PS或者美图秀秀那些软件去做,其实由程序员自己写代码去做更加高效!
图像修复技术的原理是什么呢?简而言之,就是利用那些已经被破坏的区域的边缘, 即边缘的颜色和结构,根据这些图像留下的信息去推断被破坏的信息区的信息内容,然后对破坏区进行填补 ,以达到图像修补的目的。
3.2图像修复API:inpaint()函数
inpaint()函数讲解c++: void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags)
【参数】
第一个参数,src,输入的单通道或三通道图像;
第二个参数,inpaintMask,图像的掩码,单通道图像,大小跟原图像一致,inpaintMask图像上除了需要修复的部分之外其他部分的像素值全部为0;
第三个参数,dst,输出的经过修复的图像;
第四个参数,inpaintRadius,修复算法取的邻域半径,用于计算当前像素点的差值;
第五个参数,flags ,修复算法,有两种:INPAINT_NS 和I NPAINT_TELEA;
INPAINT_NS Navier-Stokes based method.
INPAINT_TELEA Method by Alexandru Telea [Telea04].
inpaint()函数源代码
/*【inpaint()源代码】******************************************* 4000 ********************* * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下) * @源码路径:…\opencv\sources\modules\photo\src\inpaint.cpp * @起始行数:810行 ********************************************************************************/ void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst, double inpaintRange, int flags ) { Mat src = _src.getMat(), mask = _mask.getMat(); _dst.create( src.size(), src.type() ); CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat(); cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags ); }
可以看出inpaint源码中调用的是cvInpaint()函数,其源代码如下。
/*【inpaint()源代码】**************************************************************** * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下) * @源码路径:…\opencv\sources\modules\photo\src\inpaint.cpp * @起始行数:727行 ********************************************************************************/ Void cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img, double inpaintRange, int flags ) { cv::Ptr<CvMat> mask, band, f, t, out; cv::Ptr<CvPriorityQueueFloat> Heap, Out; cv::Ptr<IplConvKernel> el_cross, el_range; CvMat input_hdr, mask_hdr, output_hdr; CvMat* input_img, *inpaint_mask, *output_img; int range=cvRound(inpaintRange); int erows, ecols; input_img = cvGetMat( _input_img, &input_hdr ); 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_StsUnmatchedSizes, "All the input and output images must have the same size" ); if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 && CV_MAT_TYPE(input_img->type) != CV_8UC3) || !CV_ARE_TYPES_EQ(input_img,output_img) ) CV_Error( CV_StsUnsupportedFormat, "Only 8-bit 1-channel and 3-channel input/output images are supported" ); if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 ) CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" ); range = MAX(range,1); range = MIN(range,100); ecols = input_img->cols + 2; erows = input_img->rows + 2; f.reset(cvCreateMat(erows, ecols, CV_8UC1)); t.reset(cvCreateMat(erows, ecols, CV_32FC1)); band.reset(cvCreateMat(erows, ecols, CV_8UC1)); mask.reset(cvCreateMat(erows, ecols, CV_8UC1)); el_cross.reset(cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL)); cvCopy( input_img, output_img ); cvSet(mask,cvScalar(KNOWN,0,0,0)); COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar); SET_BORDER1_C1(mask,uchar,0); cvSet(f,cvScalar(KNOWN,0,0,0)); cvSet(t,cvScalar(1.0e6f,0,0,0)); cvDilate(mask,band,el_cross,1); // image with narrow band Heap=cv::makePtr<CvPriorityQueueFloat>(); if (!Heap->Init(band)) return; cvSub(band,mask,band,NULL); SET_BORDER1_C1(band,uchar,0); if (!Heap->Add(band)) return; cvSet(f,cvScalar(BAND,0,0,0),band); cvSet(f,cvScalar(INSIDE,0,0,0),mask); cvSet(t,cvScalar(0,0,0,0),band); if( flags == cv::INPAINT_TELEA ) { out.reset(cvCreateMat(erows, ecols, CV_8UC1)); el_range.reset(cvCreateStructuringElementEx(2*range+1,2*range+1, range,range,CV_SHAPE_RECT,NULL)); cvDilate(mask,out,el_range,1); cvSub(out,mask,out,NULL); Out=cv::makePtr<CvPriorityQueueFloat>(); if (!Out->Init(out)) return; if (!Out->Add(band)) return; cvSub(out,band,out,NULL); SET_BORDER1_C1(out,uchar,0); icvCalcFMM(out,t,Out,true); icvTeleaInpaintFMM(mask,t,output_img,range,Heap); } else if (flags == cv::INPAINT_NS) { icvNSInpaintFMM(mask,t,output_img,range,Heap); } else { CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" ); } }
3.3图像修复实例
全区域阈值处理+Mask膨胀处理代码参看附件【demo1】。
图1
由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。
鼠标框选区域+阈值处理+Mask膨胀处理
代码参看附件【demo2】。
图2
可以看到,选定区域之外的图像不受修复影响,没有额外的损伤。
鼠标划定整个区域作为修复对象
这个方法选定一个矩形区域,把整个矩形区域作为要修复的对象,该方法适用于图像结构比较简单,特别是纯色图像,并且选定区域面积占比不大的情况,效果较好。
代码参看附件【demo3】。
图3
图像修复综合实例
代码参看附件【demo4】。
图4
本章参考附件
点击进入相关文章推荐
- 【第二部分 图像处理】第4章 Opencv图像处理高阶【2毛玻璃滤镜】
- 【第二部分 图像处理】第4章 Opencv图像处理高阶【1马赛克】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【2 图像变换C-重影射】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 B】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 E】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 C】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【4 图像轮廓C】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 B】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【4 图像轮廓A】
- 【第二部分-图像处理】第3章 Opencv图像处理进阶-【1 图像处理A-滤波】(imgproc组件、feature2D组件)
- 【第二部分 图像处理】第3章 Opencv图像处理进阶-【1 图像处理E-阈值化】(imgproc组件、feature2D组件)
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 D】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 D】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 C】
- 【第二部分-图像处理】第1章 Opencv图像处理入门
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【4 图像轮廓D】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 A】
- 【第二部分-图像处理】第2章 Opencv图像处理初阶(core组件)
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【2 图像变换B-霍夫变换】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 A】