【短道速滑十】從單幅圖像中評估加性噪音的均方差。

  在Halcon中有這樣一個函數:

  estimate_noise estimate_noise — Estimate the image noise from a single image.

  Signature

    estimate_noise(Image : : Method, Percent : Sigma)

  Description

  The operator estimate_noise estimates the standard deviation of additive noise within the domain of the image that is passed in Image. The standard deviation is returned in Sigma.

    The operator is useful in the following use cases:

    determination of MinContrast for matching,

    determination of the amplitude for edge filters,

    camera evaluation,

    monitoring errors in camera operation (e.g., user overdrives camera gain).

  即從單幅圖像中評估圖像噪音的均方差,這個算子可以用於計算匹配時的最小對比度(發現新大陸了,原路模板匹配還可以用這個做自動化)、邊緣檢測濾波器的幅度、攝像機評估、控相機操作中的錯誤(例如用戶過度調節相機增益)。

       我覺得還可以把他作爲自動去噪的一個參考指標。

  Halcon裏提供了四個評估噪音的方法:: 'foerstner', 'immerkaer', 'least_squares', 'mean',其本身最推薦的方法是immerkaer,如其幫助文檔裏所說:

  Use the method 'immerkaer', instead of the methods 'foerstner', 'least_squares', or 'mean'. The method 'immerkaer' does not rely on the existence of homogeneous image regions, and hence is almost always applicable.

  關於immerkaer方法,開放的Halcon基本上提供了完整的算法思路:

    'immerkaer': If Method is set to 'immerkaer', first the following filter mask is applied to the input image:  

                                                           

    The advantage of this method is that M is almost insensitive to image structure but only depends on the noise in the image. Assuming a Gaussian distributed noise, its standard deviation is finally obtained as

                                               

            where N is the number of image pixels to which M is applied. Note that the result obtained by this method is independent of the value passed in Percent.

  這個M算子明顯就是類似一個邊緣檢測的算子,然後把所有這個算子的結果相加,再求某個意義下的平均值,Halcon說這個方法的好處是對圖像的結構不敏感,而只完全依賴於圖像的噪音本身。 

  我想有了這個提示,要實現這個功能應該就是很簡單的過程了。 

  我的一個實現如下所示:

//    模擬實現halcon的estimate_noise函數

int IM_EstimateNoise(unsigned char *Src, int Width, int Height, int Stride, float &Sigma)
{
    int Channel = Stride / Width;
    if (Src == NULL)                                return IM_STATUS_NULLREFRENCE;
    if ((Width <= 0) || (Height <= 0))                return IM_STATUS_INVALIDPARAMETER;
    if (Channel != 1)                                return IM_STATUS_NOTSUPPORTED;
    unsigned int Sum = 0;
    for (int Y = 1; Y < Height - 1; Y++)
    {
        unsigned char *LinePL = Src + (Y - 1) * Stride;
        unsigned char *LinePC = Src + (Y - 0) * Stride;
        unsigned char *LinePN = Src + (Y + 1) * Stride;
        for (int X = 1; X < Width - 1; X++)
        {
            int L = LinePL[X - 1] - 2 * LinePL[X] + LinePL[X + 1];
            int C = -2 * LinePC[X - 1] + 4 * LinePC[X] - 2 * LinePC[X + 1];
            int N = LinePN[X - 1] - 2 * LinePN[X] + LinePN[X + 1];
            Sum += IM_Abs(L + C + N);
        }
    }
    Sigma = sqrtf(IM_PI / 2) / (6 * Width * Height) * Sum;
    return IM_STATUS_OK;
}

  爲了簡化代碼,沒有考慮圖像周邊單位像素的信息了,如果要嚴格意義的實現,也應該不是很難吧。 

  我們比較下halcon的結果和上面這段代碼的結果,使用Halcon自帶的測試代碼和圖片:

dev_update_off ()
dev_close_window ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
TestImages := ['for6','pumpe','die/die_02','clip','ic0','horses','board/board-01','combine']
NumImages := |TestImages|
for I := 0 to NumImages - 1 by 1
    read_image (Image, TestImages[I])
    dev_resize_window_fit_image (Image, 0, 0, -1, -1)
    dev_display (Image)
    for AddedNoise := 0 to 15 by 5
        gauss_distribution (AddedNoise + 1e-2, Distribution)
        add_noise_distribution (Image, ImageNoise, Distribution)
        write_image (ImageNoise, 'bmp', 0, 'C:/Users/Administrator/Desktop/1.bmp')
        estimate_noise (ImageNoise, 'foerstner', 20, SigmaFoerstner)
        estimate_noise (ImageNoise, 'immerkaer', 20, SigmaImmerkaer)
        estimate_noise (ImageNoise, 'least_squares', 20, SigmaLeastSquares)
        estimate_noise (ImageNoise, 'mean', 20, SigmaMean)
        dev_display (ImageNoise)
        disp_message (WindowHandle, 'Added Gaussian noise: Sigma = ' + AddedNoise, 'window', 12, 12, 'black', 'true')
        Message := 'Estimated image noise (Sigma):'
        Message[1] := 'Method \'foerstner\':     ' + SigmaFoerstner$'5.2f'
        Message[2] := 'Method \'immerkaer\':     ' + SigmaImmerkaer$'5.2f'
        Message[3] := 'Method \'least_squares\': ' + SigmaLeastSquares$'5.2f'
        Message[4] := 'Method \'mean\':          ' + SigmaMean$'5.2f'
        disp_message (WindowHandle, Message, 'windowe', 40, 12, 'black', 'true')
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endfor
endfor  

           

               噪音圖像                                          Halcon的結果

  使用上述C的代碼獲取的結果爲: 5.240565,和Halcon的結果基本一致。

 我們再找一些正常的圖片看看這個噪音值是否合理:

      

          噪音值 0.7763                                    噪音值 2.6604

  基本啥都比較小。 

       

                            噪音值  7.2155                                             噪音值  20.04

  對於高斯噪音,如上所示,還是能明顯的區別出來的。

  不過測試也表面,有些圖的噪音雖然視覺看起來比較明顯,但是用這參數去衡量時,確是很小,這個可能是因爲他針對的是加性噪音做的評估吧。

  參考資料:

    W. Förstner: “Image Preprocessing for Feature Extraction in Digital Intensity, Color and Range Images“, Springer Lecture Notes on Earth Sciences, Summer School on Data Analysis and the Statistical Foundations of Geomatics, 1999
    J. Immerkaer: “Fast Noise Variance Estimation“, Computer Vision and Image Understanding, Vol. 64, No. 2, pp. 300-302, 1996

  

 

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