Wie kann ein Bild mit verschiedenen Gabor-Filtern gefaltet werden, die mithilfe von FFT entsprechend der lokalen Ausrichtung und Dichte angepasst wurden?

Ich arbeite derzeit an einer Bibliothek, um synthetische Fingerabdrücke mit dem zu generierenSFinGe Methode (von Maltoni, Maio und Cappelli) link:http://biolab.csr.unibo.it/research.asp?organize=Activities&select=&selObj=12&pathSubj=111%7C%7C12&

In einem der Schritte muss ich verschiedene Gabor-Filter auf ein Bild anwenden. Jedem Pixel im Bild sind eine Ausrichtung und eine Frequenz zugeordnet, sodass die Faltung nicht mit einem Kernel über das gesamte Bild erfolgt, sondern der Filter muss sich während des Prozesses ändern Auf diese Weise wird jedes Pixel auf dem Bild auf eine andere Weise geändert.

Wenn Sie die Filter auf diese Weise anwenden und das Bild mehrmals falten (Sie müssen das Bild auch nach jeder Faltung digitalisieren), erhalten Sie Folgendes:

Es dauerte ungefähr 20 Sekunden, bis ein Master-Fingerabdruck dieses Bildes erstellt wurde (was zu langsam ist, deshalb möchte ich es mit FFT machen), da ich 5-mal die Faltung durchführen musste, um es fertigzustellen (Sie beginnen bei ein paar zufällige schwarze Punkte).

Meine Filter sind 30x30 und das Bild ist 275x400. Es gibt insgesamt 36000 Filter, einen für jeden Grad und jede Dichte (die Dichte reicht von 0 bis 100). Ich plane, die Anzahl der Filter von 36000 auf 9000 zu reduzieren, da ich damit alle Winkel abdecken kann. Außerdem werden alle Filter vorberechnet und in einer Filterbank gespeichert.

Dies ist der Quellcode in C # der Implementierung von Gabor Convolution:

Diese beiden Methoden führen die Faltung aus:

    /// <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;
    }

Diese beiden Methoden erzeugen die verschiedenen Gabor-Filter für die Filterbank:

    /// <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;
    }

Mein Ziel ist es, diese Zeit auf unter 1 Sekunde zu verkürzen (es gibt mehrere Programme, die in dieser Zeit genau dasselbe tun). Da der Ansatz der direkten Faltung bei mir nicht funktioniert, entscheide ich mich für die Implementierung der Fast Fourier Transform Convolution. Das Problem dabei ist jedoch, dass FFT den gleichen Kernel auf einmal auf das gesamte Bild anwendet und den Kernel pro Pixel ändern muss. denn jedes pixel muss abhängig von seinen eigenschaften (dichte und ausrichtung) verändert werden. In diesem BeitragWie wende ich Gabor-Wavelets auf ein Bild an? Drehzahlbereich erklärt, wie man verschiedene Gabor-Filter auf ein Bild anwendet, aber das Wichtigste ist, dass er die verschiedenen Filter auf das gesamte Bild anwendet und dann die Antworten summiert. Was ich brauche, sind die Antworten von verschiedenen Pixeln auf die verschiedenen Filter.

Das passiert, wenn ich einen Filter mit dem Bild falte (mit FFT):

Dies war der verwendete Filter:

Und das war das Bild, mit dem es verbunden war:

Dies ist der Algorithmus in C # der FFT-Implementierung:

    /// <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;
    }

Also, was ich frage ist, wie bekommst du die Antwort von verschiedenen Pixeln auf verschiedene Kernel mit FFT? Wenn dies nicht möglich ist, gibt es eine Möglichkeit, meine direkte Faltung zu verbessern, um sie mindestens 20-mal schneller zu machen?

Wäre es auch möglich, einen Kernel mit allen Filtern zu erstellen, damit ich diese auf das gesamte Bild anwenden kann?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage