CV圖像基本操作【4】——實現(xiàn)高斯與快速均值濾波

編程環(huán)境:

VS + OpenCV + C++
完整代碼已經(jīng)更新至GitHub,歡迎fork~GitHub鏈接


聲明:創(chuàng)作不易,未經(jīng)授權(quán)不得復(fù)制轉(zhuǎn)載
statement:No reprinting without authorization


內(nèi)容:

1. 實現(xiàn)圖像的高斯濾波:

-通過調(diào)整高斯函數(shù)的標準差(sigma)來控制平滑程度;
-void Gaussian(const MyImage &input, MyImage &output, double sigma);
-濾波窗口大小取為[6*sigma-1],[.]表示取整;
-利用二維高斯函數(shù)的行列可分離性進行加速;
-先對每行進行一維高斯濾波,再對結(jié)果的每列進行同樣的一維高斯濾波;

2. 實現(xiàn)快速均值濾波

-實現(xiàn)圖像的均值濾波;
-濾波窗口大小通過參數(shù)來指定;
-void MeanFilter(const MyImage &input, MyImage &output, int window_size);
-采用積分圖進行加速,實現(xiàn)與濾波窗口大小無關(guān)的效率;

問題一:卷積核的大小問題:

通過創(chuàng)建進度條來動態(tài)的交互更改核的大小,其中高斯采用[6sigma-1]進度條值為sigma0.01,為保證程序能正常健壯執(zhí)行,對于計算出的核大小需要檢查是否太小或為偶數(shù):

int ksize = sigma * 6 - 1;
    if (ksize < 3) {
        cout << "ksize is too small!error" << endl;
        return;
    }
    int iRes = ksize % 2;
    if (iRes == 0) {
        ksize += 1;
}

問題二:邊緣處理

實用高斯和均值時都需考慮進行填充后才能進行濾波
常見的填充方式有三種:對稱復(fù)制填充、最邊緣復(fù)制填充、常量填充:
可以使用opencv內(nèi)建的copyMakeBorder函數(shù)實現(xiàn)填充
不同填充效果如下;

image.png

image.png

image.png

結(jié)合效果發(fā)現(xiàn)對稱填充對高斯和均值濾波有更好的效果,也更符合客觀事實。

問題三:行列可分離的具體實現(xiàn)

描述:由于高斯函數(shù)可以寫成可分離的形式,因此可以采用可分離濾波器實現(xiàn)來加速。所謂的可分離濾波器,就是可以把多維的卷積化成多個一維卷積。具體到二維的高斯濾波,就是指先對行做一維卷積,再對列做一維卷積。這樣就可以將計算復(fù)雜度從O(MMNN)降到O(2MMN),M,N分別是圖像和濾波器的窗口大小。 這樣分解開來,算法的時間復(fù)雜度為O(ksize) ,運算量和濾波器的模板尺寸呈線性增長。
得到高斯濾波的一維數(shù)組,注意需要進行歸一化:

int half = ksize / 2;
    //初始化濾波核
    for (int i = 0; i < ksize; i++)
    {
        // 只需計算指數(shù)部分,高斯函數(shù)前的常數(shù)可以不用計算,會在歸一化的過程中給消去
        //以(half,half)為中心建立坐標系進行計算
        double g = exp(-(i - half) * (i - half) / (2 * sigma * sigma));
        sum += g;
        GS_filter[i] = g;
    }
    // 歸一化
    for (int i = 0; i < ksize; i++)
        GS_filter[i] /= sum;

并且需要對單通道和三通道圖像分別進行處理:

問題四:積分圖的算法實現(xiàn)問題

1、采用一維數(shù)組int * integral來存儲像素的積分,計算積分時注意可以使用迭代來降低復(fù)雜度,如下圖:

image.png

????Integral(i,j) = Integral(i,j-1) + prow(j)
????其中prow(j)為當前位置上的列的像素之和。
2、注意數(shù)組的大小由傳統(tǒng)的W * H改為 (W + 1) * (H + 1)會進一步使算法簡便,
使某個點的積分圖反映的是原圖中此位置左上角所有像素之和,這里是的累加和是不包括這個點像素本身的??梢院喕惴?,在計算時可以不用判斷是否為原圖的邊界像素,如下:

for (int yi = 1; yi < height+1; ++yi, Integral += 3 * (width + 1)) {
            //對第一列像素值單獨處理
            Integral[0] = 0;
            Integral[1] = 0;
            Integral[2] = 0;
            Vec3b rgb = src.at<Vec3b>(yi-1, 0);
            prow[0] += rgb[0];
            prow[1] += rgb[1];
            prow[2] += rgb[2];  
            Integral[3] = prow[0];
            Integral[4] = prow[1];
            Integral[5] = prow[2];      
    for (int xi = 2; xi < width+1; ++xi)
    {
            rgb = src.at<Vec3b>(yi-1, xi-1);
            prow[3*(xi-1)+0] += rgb[0];
            prow[3*(xi-1)+1] += rgb[1];
            prow[3*(xi-1)+2] += rgb[2];
    Integral[3 * xi + 0] = Integral[3 * (xi - 1) + 0] + prow[3 * (xi-1) + 0];
    Integral[3 * xi + 1] = Integral[3 * (xi - 1) + 1] + prow[3 * (xi-1) + 1];
    Integral[3 * xi + 2] = Integral[3 * (xi - 1) + 2] + prow[3 * (xi-1) + 2];
    }
}   

查閱資料,發(fā)現(xiàn)opencv中的內(nèi)建函數(shù)也是這樣定義的:


image.png

最終實驗效果如下:


image.png

image.png

image.png

image.png

image.png

image.png

小結(jié)

圖像的濾波操作應(yīng)該是圖像處理的基本操作,很多的圖像識別與分析算法都是以基本的卷積核為核心,所以掌握圖像基本卷積濾波操作還是很重要的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容