前言
前天,在羣裏看見有人發了這張表情包:
感覺女主有點好看,然後問室友是啥番劇(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