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

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