1. 程式人生 > >0029-在OpenCV環境下做導向濾波的程式碼

0029-在OpenCV環境下做導向濾波的程式碼

前邊提到的均值濾波、中值濾波和高斯濾波,都屬於各向同性濾波,它們對待噪聲和影象的邊緣資訊都採取一樣的態度,結果,噪聲被磨平的同時,影象中具有重要地位的邊緣、紋理和細節也同時被抹平了,這是我們所不希望看到的。為了解決這個問題,人們陸續提出了一些演算法來把影象邊緣和噪聲區別對待,比如雙邊濾波和導向濾波,本文介紹如何使用opencv做影象的導向濾波。

先來說下導向濾波的大致思路。在導向濾波中,要對影象p進行濾波而得到影象q,需要一個引導影象I,類似的原理有點像直方圖匹配,直方圖匹配詳見博文https://blog.csdn.net/lehuoziyuan/article/details/84066102,其實就是根據引導影象I的特徵去設定濾波器。導向濾波在影象增強、HDR壓縮、影象摳圖及影象去霧等場景中都有應用。

具體的導向濾波的原理大家可參見博文http://blog.csdn.net/baimafujinji/article/details/74750283,我這裡就不多敘述了。

導向濾波的程式碼如下

影象處理開發資料、影象處理開發需求、影象處理接私活掙零花錢,可以搜尋公眾號"qxsf321",並關注!
程式碼中用到的影象下載連結:http://pan.baidu.com/s/1c2IrDZy 密碼:dqbl

//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <time.h>  
#include <iostream>

using namespace cv;
using namespace std;

//導向濾波器  
Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps);

int main()
{
        Mat srcImage = imread("Gauss_noise.jpg");
        if (srcImage.empty())
        {
                cout << "讀入圖片錯誤!" << endl;
                system("pause");
                return -1;
        }
        //進行通道分離  
        vector<Mat>vSrcImage, vResultImage;
        split(srcImage, vSrcImage);
        Mat resultMat;
        for (int i = 0; i < 3; i++)
        {
                //分通道轉換成浮點型資料  
                Mat tempImage;
                vSrcImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0);
                Mat p = tempImage.clone();
                //分別進行導向濾波  
                Mat resultImage = guidedfilter(tempImage, p, 4, 0.01);
                vResultImage.push_back(resultImage);
        }
        //通道結果合併  
        merge(vResultImage, resultMat);
        imshow("原影象", srcImage);
        imshow("導向濾波後圖像", resultMat);
        waitKey(0);
        return 0;
}

Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps)
{
        //轉換源影象資訊  
        srcImage.convertTo(srcImage, CV_64FC1);
        srcClone.convertTo(srcClone, CV_64FC1);
        int NumRows = srcImage.rows;
        int NumCols = srcImage.cols;
        Mat boxResult;

        //下面按照步驟進行導向濾波操作  
        /////////////////////////////////////////////////////////////  
        //步驟一:計算均值  
        boxFilter(Mat::ones(NumRows, NumCols, srcImage.type()),
                boxResult, CV_64FC1, Size(r, r));
        //生成導向均值mean_I  
        Mat mean_I;
        boxFilter(srcImage, mean_I, CV_64FC1, Size(r, r));
        //生成原始均值mean_P  
        Mat mean_P;
        boxFilter(srcClone, mean_P, CV_64FC1, Size(r, r));
        //生成互相關均值mean_IP  
        Mat mean_IP;
        boxFilter(srcImage.mul(srcClone), mean_IP,
                CV_64FC1, Size(r, r));
        Mat cov_IP = mean_IP - mean_I.mul(mean_P);
        //生成自相關均值mean_II  
        Mat mean_II;
        //應用盒濾波計算相關均值  
        boxFilter(srcImage.mul(srcImage), mean_II, CV_64FC1, Size(r, r));
        //步驟二:計算相關係數  
        Mat var_I = mean_II - mean_I.mul(mean_I);
        Mat var_IP = mean_IP - mean_I.mul(mean_P);
        //步驟三:計算引數係數a,b  
        Mat a = cov_IP / (var_I + eps);
        Mat b = mean_P = a.mul(mean_I);
        //步驟四:計算係數a,b的均值  
        Mat mean_a;
        boxFilter(a, mean_a, CV_64FC1, Size(r, r));
        mean_a = mean_a / boxResult;
        Mat mean_b;
        boxFilter(b, mean_b, CV_64FC1, Size(r, r));
        mean_b = mean_b / boxResult;
        //步驟五:生成輸出矩陣  
        Mat resultMat = mean_a.mul(srcImage) + mean_b;
        return resultMat;
}


執行結果截圖如下

程式碼說明
在上面的程式碼中,導向圖I就是原圖本身,大家可以修改程式碼換一張圖片試試。