前言
前天,在群里看见有人发了这张表情包:
感觉女主有点好看,然后问室友是啥番剧(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小宝贝!!!
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
转载:https://blog.csdn.net/qq_42604176/article/details/105872874