Opencv实战【3】——图像修复与图像锐化(darling in the franxx)

前言

前天,在群里看见有人发了这张表情包:
表情包
感觉女主有点好看,然后问室友是啥番剧(darling in the franxx),然后就去补番了,然后从晚上十二点看到早上五点多,睡了一觉下午接着看,看完脑子里面全是02,啊啊啊啊,这种番这的太对我的胃口了,墙裂推荐!!!
在网站上截了几张图准备做壁纸的,但是这几张图片有几个缺点:
1、有两张手速不快,截图上有字
2、由于图像经过处理有点模糊,细节不够明显
于是查了查Opencv有没有相关的函数可以解决这种问题,发现是有的。
上述的两种问题分别对应着两种图像处理效果:1、图像修复 2、图像锐化

图像修复

图像修复,指对受到损坏的图像进行修复重建或者去除图像中的多余物体。
去除文字,是图像修复的一种应用。
Opencv自带inpaint函数:

CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask,
                           OutputArray dst, double inpaintRadius, int flags );

其中
InputArray src 表示要修复的图像,
InputArray inpaintMask表示修复模板,
OutputArray dst 表示修复后的图像,
double inpaintRadius 表示修复的半径,
int flags 表示修复使用的算法 。 opencv提供了两种选择 CV_INPAINT_TELEA 和 CV_INPAINT_NS。
这里不详细讲解修复原理,百度或知乎都有相关的原理讲解的。

调用inpaint()函数一个关键的点:确定修复掩膜。
修复掩膜只能为8位单通道的图像,其中非零像素表示需要修补的区域。
所以,用阈值法提取的文字图像作为修复掩膜。虽然阈值法的处理结果可能会导致一些误检点或者误检区域,但这些误检都在可容忍的错误范围之内。而且可用形态学方法中膨胀操作对阈值法提取的结果进行膨胀,膨胀操作的结果再作为修复掩膜。

代码:
1、确定修复掩膜图像,观察像素发现,文字为白色

Mat GetRedComponet(Mat srcImg)
{
    //如果直接对srcImg处理会改变main()函数中的实参
    Mat dstImg = srcImg.clone();
    Mat_<Vec3b>::iterator it = dstImg.begin<Vec3b>();
    Mat_<Vec3b>::iterator itend = dstImg.end<Vec3b>();
    for (; it != itend; it++)
    {
        if ((*it)[2] > 230 && (*it)[1] > 230 && (*it)[2] > 230)
        {
            (*it)[0] = 255;
            (*it)[1] = 255;
            (*it)[2] = 255;//红色分量保持不变
        }

        else
        {
            (*it)[0] = 0;
            (*it)[1] = 0;
            (*it)[2] = 0;
        }
    }
    return dstImg;
}

2、确定膨胀参数以及修复半径

void Inpainting(Mat oriImg, Mat maskImg,Mat& inpaintedImage)
{
    Mat grayMaskImg;
    Mat element = getStructuringElement(MORPH_ELLIPSE, Size(15, 15));//MORPH_RECT MORPH_CROSS;MORPH_ELLIPSE;
    dilate(maskImg, maskImg, element);//膨胀后结果作为修复掩膜
    //将彩色图转换为单通道灰度图,最后一个参数为通道数
    cvtColor(maskImg, grayMaskImg, COLOR_BGR2GRAY, 1);
    //修复图像的掩膜必须为8位单通道图像
    inpaintedImage.create(oriImg.size(), oriImg.type());
    inpaint(oriImg, grayMaskImg, inpaintedImage, 3, INPAINT_NS);     //INPAINT_NS   INPAINT_TELEA
}

3、传入图片,展示图片

int main(int argc, char* argv[])
{
    Mat srcImg;
    srcImg=imread("D:\\opencv_picture_test\\darling in the franxx\\02字.png", 1);
    //获取掩膜大概区域,之后需要进行膨胀处理,扩大掩膜区域
    Mat imgComponet = GetRedComponet(srcImg);
    Mat inpaintedImage;
    Mat result;
    //修复
    Inpainting(srcImg, imgComponet, inpaintedImage);
    //namedWindow("原图", WINDOW_NORMAL);   
    //imshow("原图", srcImg);
    namedWindow("图像复原结果图", WINDOW_NORMAL);
    imshow("图像复原结果图", inpaintedImage);
    waitKey(0);
    return 0;
}

效果:
原图:
原图
复原结果
感觉效果还行,不过效果没有达到做壁纸的效果,唉。。。

图像锐化

图像锐化,是使图像边缘更清晰的一种图像处理方法,细节增强(detail enhancement)。
常用的做法是提取图像的高频分量,将其叠加到原图上。
图像高频分量的提取有两种做法,一种是用高通滤波器,得到高频分量,另一种是通过低通滤波,用原图减低频得以高频。
直接提取高频的方法有sobel算法、laplcian算子,sobel算子是图像的一阶导数,提取的是梯度信息,分水平和垂直两种,常常用来做边缘检测、方向判别,sobel算子在斜坡处不为0,因此会产生较粗的边缘。laplcian算子是图像的二阶导,在图像开始变化和结束变化的地方值不为0,渐变时结果为0,因此laplacian比sobel算子更适合做sharpen。
除了直接提取高频的方法外,我们也可以先提取低频,原图减去低频得到高频。这种方法称为非锐化掩模(unsharpen
mask),我们常使用低通滤波器(高斯、双边)对图像进行滤波,这种方法滤波器很好控制(包括大小和强弱),从而可以控制高频分量的强弱。

高频分量提取(滤波)

void sharpenImage( cv::Mat& image, cv::Mat& result)
{
    //创建并初始化滤波模板,这里使用拉普拉斯模板
    cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0));
    kernel.at<float>(1, 1) = 5.0;
    kernel.at<float>(0, 1) = -1.0;
    kernel.at<float>(1, 0) = -1.0;
    kernel.at<float>(1, 2) = -1.0;
    kernel.at<float>(2, 1) = -1.0;
    result.create(image.size(), image.type());
    //对图像进行滤波
    cv::filter2D(image, result, image.depth(), kernel);
}

效果:
效果

darling in the franxx图片

锐化:
02
海滩
夕阳
修复:
莓
02
轮廓或边缘:
轮廓
边缘

总结

莓的那张由于字在树林背景那边,看起来效果还行。02的那张由于涉及到身体轮廓,以后还需要进行改进。
另外以后手速还是需要练,尽量截到不带字的图。
大爱02小宝贝!!!

Reference:

https://www.cnblogs.com/hellowooorld/p/7048614.html
https://blog.csdn.net/zx249388847/article/details/79325385/
https://blog.csdn.net/helimin12345/article/details/82634355
https://blog.csdn.net/hankerbit/article/details/80838241

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章