簡體   English   中英

如何使用FFT根據局部方向和密度調整具有不同gabor濾波器的圖像?

[英]How to convolve an image with different gabor filters adjusted according to the local orientation and density using FFT?

我目前正在開發一個使用SFinGe方法(由 Maltoni、Maio 和 Cappelli 提供)鏈接生成合成指紋的庫: http : //biolab.csr.unibo.it/research.asp?organize=Activities&select=&selObj=12&pathSubj= 111%7C%7C12&

其中一個步驟要求我將不同的 gabor 過濾器應用於圖像,圖像中的每個像素都有一個相關的方向和頻率,因此卷積不是在整個圖像上使用一個內核完成的,但過濾器必須在此過程中根據情況而改變在像素的這些屬性上,圖像上的每個像素都以不同的方式改變。

如果您以這種方式應用過濾器,並對圖像進行多次卷積(您還必須在每次卷積后對圖像進行二值化),您將獲得:

在此處輸入圖片說明

一個主指紋,這個圖像需要大約 20 秒才能生成(這太慢了,這就是我想用 FFT 來做的原因),因為我必須執行 5 次卷積才能完成它(你從幾個開始隨機黑點)。

我的過濾器是 30x30,圖像是 275x400。 共有 36000 個過濾器,每個度數和密度(密度從 0 到 100)一個。 我計划將過濾器的數量從 36000 減少到 9000,因為我可以用它們覆蓋所有角度。 此外,所有濾波器都經過預先計算並存儲在濾波器組中。

這是gabor卷積實現的C#源代碼:

這兩種方法執行卷積:

    /// <summary>
    /// Convolve the image with the different filters depending on the orientation and density of the pixel.
    /// </summary>
    /// <param name="image">The image to be filtered.</param>
    /// <param name="directionalMap">The directional map.</param>
    /// <param name="densityMap">The density map.</param>
    /// <returns></returns>
    public double[,] Filter(double[,] image, double[,] directionalMap, double[,] densityMap)
    {
        int       midX                          = FILTER_SIZE / 2;
        int       midY                          = FILTER_SIZE / 2;
        double[,] filteredImage                 = new double[image.GetLength(0), image.GetLength(1)];
        double[,] filteredImageWithValuesScaled = new double[image.GetLength(0), image.GetLength(1)];
        double[,] finalImage                    = new double[image.GetLength(0), image.GetLength(1)];

        for (int i = 0; i < image.GetLength(0); i++)
            for (int j = 0; j < image.GetLength(1); j++)
            {

                double pixelValue = GetPixelConvolutionValue(image, this.filterBank[(int)Math.Floor((directionalMap[i, j] * 180 / Math.PI))][Math.Round(densityMap[i, j], 2)], i - midX, j - midY);

                filteredImage[i, j] = pixelValue;
            }

        filteredImageWithValuesScaled = this.RescaleValues(filteredImage, 0.0, 255.0);

        return filteredImageWithValuesScaled;
    }
    /// <summary>
    /// Gets the pixel convolution value.
    /// </summary>
    /// <param name="image">The image.</param>
    /// <param name="filter">The filter.</param>
    /// <param name="sourceX">The source X.</param>
    /// <param name="sourceY">The source Y.</param>
    /// <returns></returns>
    private double GetPixelConvolutionValue(double[,] image, double[,] filter, int sourceX, int sourceY)
    {
        double result      = 0.0;
        int    totalPixels = 0;

        for (int i = 0; i < filter.GetLength(0); i++)
        {
            if(i + sourceX < 0 || i + sourceX >= image.GetLength(0))
                continue;

            for (int j = 0; j < filter.GetLength(1); j++)
            {
                if(j + sourceY < 0 || j + sourceY >= image.GetLength(1))
                    continue;

                double deltaResult = image[sourceX + i,sourceY + j] * filter[i, j];
                result += deltaResult;

                ++totalPixels;
            }
        }

        double filteredValue = result / totalPixels;
        return filteredValue;
    }

這兩種方法為濾波器組生成不同的 Gabor 濾波器:

    /// <summary>
    /// Creates the gabor filter.
    /// </summary>
    /// <param name="size">The size.</param>
    /// <param name="angle">The angle.</param>
    /// <param name="wavelength">The wavelength.</param>
    /// <param name="sigma">The sigma.</param>
    /// <returns></returns>
    public double[,] CreateGaborFilter(int size, double angle, double wavelength, double sigma)
    {
        double[,] filter    = new double[size, size];
        double    frequency = 7 + (100 - (wavelength * 100)) * 0.03;

        int windowSize = FILTER_SIZE/2;

        for (int y = 0; y < size; ++y)
        {
            for (int x = 0; x < size; ++x)
            {
                int dy = -windowSize + y;
                int dx = -windowSize + x;

                filter[x, y] = GaborFilterValue(dy, dx, frequency, angle, 0, sigma, 0.80);
            }
        }

        return filter;
    }
    /// <summary>
    /// Gabor filter values generation.
    /// </summary>
    /// <param name="x">The x.</param>
    /// <param name="y">The y.</param>
    /// <param name="lambda">The wavelength.</param>
    /// <param name="theta">The orientation.</param>
    /// <param name="phi">The phaseoffset.</param>
    /// <param name="sigma">The gaussvar.</param>
    /// <param name="gamma">The aspectratio.</param>
    /// <returns></returns>
    double GaborFilterValue(int x, int y, double lambda, double theta, double phi, double sigma, double gamma)
    {
        double xx = x * Math.Cos(theta) + y * Math.Sin(theta);
        double yy = -x * Math.Sin(theta) + y * Math.Cos(theta);

        double envelopeVal = Math.Exp(-((xx * xx + gamma * gamma * yy * yy) / (2.0f * sigma * sigma)));

        double carrierVal = Math.Cos(2.0f * (float)Math.PI * xx / lambda + phi);

        double g = envelopeVal * carrierVal;

        return g;
    }

我的目標是將這個時間減少到 1 秒以下(有幾個程序在這段時間內做完全相同的事情)。 因此,由於直接卷積方法對我不起作用,我決定實施快速傅立葉變換卷積,但問題在於 FFT 一次將相同的內核應用於整個圖像,我需要更改每個像素的內核,因為每個像素都必須根據其屬性(密度和方向)進行更改。 在這篇文章中如何將 Gabor 小波應用於圖像? reve-etrange解釋了如何將不同的 gabor 過濾器應用於圖像,但問題是他的做法是將不同的過濾器應用於整個圖像,然后對響應求和,而我需要的是來自不同像素的響應到不同的過濾器。

這是當我將一個過濾器與圖像進行卷積(使用 FFT)時發生的情況:

在此處輸入圖片說明

這是使用的過濾器:

在此處輸入圖片說明

這是它卷積的圖像:

在此處輸入圖片說明

這是 FFT 實現的 C# 算法:

    /// <summary>
    /// Convolve the image using FFT.
    /// </summary>
    /// <param name="image">The image to be filtered.</param>
    /// <param name="directionalMap">The directional map.</param>
    /// <param name="densityMap">The density map.</param>
    /// <param name="FFT">if set to <c>true</c> [FFT].</param>
    /// <returns></returns>
    public double[,] Filter(double[,] image, double[,] directionalMap, double[,] densityMap, bool FFT)
    {
        double[,] filter        = null;
        double[,] paddedFilter  = null;
        double[,] paddedImage   = null;
        double[,] croppedImage  = null;
        double[,] filteredImage = new double[image.GetLength(0), image.GetLength(1)];
        double[,] filteredImageWithValuesScaled = new double[image.GetLength(0), image.GetLength(1)];
        double[,] finalImage = new double[image.GetLength(0), image.GetLength(1)];

        filter = this.filterBank[70][0];
        paddedFilter = PadImage(filter, 512, 512, 0, 0); // Pad the filter to have a potency of 2 dimensions.
        paddedImage = PadImage(image, 512, 512, 0, 0);   // Pad the image to have a potency of 2 dimensions.

        FFT fftOne = new FFT(paddedImage);
        FFT fftTwo = new FFT(paddedFilter);

        fftOne.ForwardFFT();
        fftTwo.ForwardFFT();

        FFT result = fftOne * fftTwo;

        result.InverseFFT();

        filteredImage = result.GreyImage;

        filteredImageWithValuesScaled = this.RescaleValues(filteredImage, 0.0, 255.0);

        croppedImage = CropImage(filteredImageWithValuesScaled, image.GetLength(0), image.GetLength(1));

        return croppedImage;
    }

所以我要問的是,您如何使用 FFT 獲得從不同像素到不同內核的響應? 如果這是不可能的,有沒有辦法改進我的直接卷積,使其至少快 20 倍?

是否可以使用所有過濾器制作一個內核,以便我可以將它們應用於整個圖像?

我找到了一種方法,可以使用不同的 gabor 濾波器對圖像進行卷積,並使用 FFT 根據像素的局部特征收集像素的響應。

這稱為上下文過濾,通常當您過濾圖像時,您只會將單個內核應用於整個事物,但在上下文過濾中,過濾器的特征會根據本地上下文(在這種情況下,像素的密度和方向)而變化。

在直接卷積中,過程非常簡單,您只需在卷積的每一步更改內核,但在 FFT 卷積中,由於內核應用於頻域中的圖像,您無法在此過程中更改濾波器屬性。 因此,您這樣做的方法是分別將圖像與每個過濾器進行卷積,這將提供 N 個過濾圖像,其中 N 是過濾器組中過濾器的數量,然后您必須構建最終圖像,從中獲取信息基於您正在重新創建的像素的上下文的不同過濾圖像。

因此,對於每個像素,您查看其方向和密度屬性,然后從過濾圖像中獲取該像素位置的值,該圖像是通過將原始圖像與具有相同屬性的過濾器進行卷積而生成的。 以下是該過程的示例:

這是方向圖的圖形表示。

在此處輸入圖片說明

我對所有像素使用相同的密度來減少生成的過濾器數量。

這是源圖像:

在此處輸入圖片說明

這是使用的三個過濾器的示例(0 度、45 度、90 度):

在此處輸入圖片說明在此處輸入圖片說明在此處輸入圖片說明

以下是源圖像與不同過濾器進行不同程度卷積的三個示例:

在此處輸入圖片說明

在此處輸入圖片說明

在此處輸入圖片說明

最后這是生成的圖像,圖像是根據像素的方向和密度從不同過濾圖像中獲取像素值創建的。

在此處輸入圖片說明

這個過程是一個很大比直接卷積慢=(,因為你必須與所有的過濾器首先要卷積的原始圖像。最終的圖像了將要生成一分鍾。到目前為止,我堅持了下來,似乎直接卷積=/。

謝謝閱讀。

您是否嘗試過使用 CUDA? 使用卷積和 FFT(在本例中為 cufft)它會更快! 嘗試看看是否有並行化的可能性,實際上我正在努力,我可以說改進是巨大的。 目前我將實施 Gabor 過濾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM