【从零学习OpenCV 4】图像修复
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。 |
在实际应用或者工程中,图像常常会收到噪声的干扰,例如在拍照时镜头上存在灰尘或者飞行的小动物,这些干扰会导致拍摄到的图像出现部分内容被遮挡的情况。对于较为久远的图像,可能只有实体图像而没有数字存储形式的底板,因此相片在保存和运输过程中可能产生划痕,导致图像中信息的损坏和丢失。
图像修复技术就是利用图像中损坏区域边缘的像素,根据像素值的大小以及像素间的结构关系,估计出损坏区域可能的像素排列,从而去除图像中受污染的区域。图像修复不仅可以去除图像中得“划痕”,还可以去除图像中得水印、日期等。
OpenCV 4提供了能够对含有较少污染或者水印的图像进行修复的inpaint()函数,该函数的函数原型在代码清单8-26中给出。
代码清单8-26 inpaint()函数清单
void cv::inpaint(InputArray src,
InputArray inpaintMask,
OutputArray dst,
double inpaintRadius,
int flags
)
src:输入待修复图像,当图像为单通道时,数据类型可以是CV_8U、CV_16U或者CV_32F,当图像为三通道时数据类型必须是CV_8U。 inpaintMask:修复掩模,数据类型为CV_8U的单通道图像,与待修复图像具有相同的尺寸。 dst:修复后输出图像,与输入图像具有相同的大小和数据类型。 inpaintRadius:算法考虑的每个像素点的圆形邻域半径。 flags:修复方法标志,可以选择的参数及含义在表8-7给出
该函数利用图像修复算法对图像中指定的区域进行修复,函数无法判定哪些区域需要修复,因此在使用过程中需要明确指出需要修复的区域。函数的第一个参数是需要修复的图像,该函数可以对灰度图像和彩色图像进行修复。修复灰度图像时,图像的数据类型可以为CV_8U、CV_16U或者CV_32F;修复彩色图像时,图像的数据类型只能为CV_8U。第二个参数是修复掩码,即指定图像中需要修复的区域,该参数输入量是一个与图像具有相同尺寸的数据类型为CV_8U的单通道图像,图像中非0像素表示需要修复的区域。函数的第三个 参数是修复后的输出图像,与输入图像具有相同的大小和数据类型。第四个参数表示修复算法考虑的每个像素点的圆形邻域半径。最后一个参数表示修复图像方法标志,可以选择的参数及含义在表8-7给出。
该函数虽然可以对图像受污染区域进行修复,但是需要借助污染边缘区域的像素信息,离边缘区域越远的像素估计出的准确性越低,因此如果受污染区域较大,修复的效果就会降低。
表8-7 inpaint()函数修复图像算法可选择标志
标志参数 | 简记 | 含义 |
---|---|---|
INPAINT_NS | 0 | 基于Navier-Stokes算法修复图像 |
INPAINT_TELEA | 1 | 基于Alexandru Telea算法修复图像 |
为了了解函数的使用方法以及图像修复的效果,在代码清单8-27中给出了图像修复的示例程序。程序中分别对污染较轻和较严重的两张图像进行修复,首先计算每张图像需要修复的掩码图像,之后利用inpaint()函数对图像进行修复,程序输出结果如图8-18和图8-19所示,通过结果可以看出污染区域较细并且较为稀疏的情况下图像修复效果较好,污染区域较为密集时修复效果较差。
代码清单8-27 myInpaint.cpp图像修复
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat img1 = imread("inpaint1.png");
Mat img2 = imread("inpaint2.png");
if (img1.empty() || img2.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
imshow("img1", img1);
imshow("img2", img2);
//转换为灰度图
Mat img1Gray, img2Gray;
cvtColor(img1, img1Gray, COLOR_RGB2GRAY, 0);
cvtColor(img2, img2Gray, COLOR_RGB2GRAY, 0);
//通过阈值处理生成Mask掩模
Mat img1Mask, img2Mask;
threshold(img1Gray, img1Mask, 245, 255, THRESH_BINARY);
threshold(img2Gray, img2Mask, 245, 255, THRESH_BINARY);
//对Mask膨胀处理,增加Mask面积
Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(img1Mask, img1Mask, Kernel);
dilate(img2Mask, img2Mask, Kernel);
//图像修复
Mat img1Inpaint, img2Inpaint;
inpaint(img1, img1Mask, img1Inpaint, 5, INPAINT_NS);
inpaint(img2, img2Mask, img2Inpaint, 5, INPAINT_NS);
//显示处理结果
imshow("img1Mask", img1Mask);
imshow("img1修复后", img1Inpaint);
imshow("img2Mask", img2Mask);
imshow("img2修复后", img2Inpaint);
waitKey();
return 0;
}
图8-18 myInpaint.cpp程序中污染条纹较细较稀疏时修复结果
图8-19 myInpaint.cpp程序中污染条纹较稠密时修复结果