Как свернуть изображение с различными фильтрами gabor, настроенными в соответствии с локальной ориентацией и плотностью с помощью FFT? - программирование
Подтвердить что ты не робот

Как свернуть изображение с различными фильтрами gabor, настроенными в соответствии с локальной ориентацией и плотностью с помощью FFT?

В настоящее время я работаю над библиотекой для создания синтетических отпечатков пальцев с использованием метода SFinGe (по Maltoni, Maio и Cappelli): http://biolab.csr.unibo.it/research.asp?organize=Activities&select=&selObj=12&pathSubj=111%7C%7C12&

Один из шагов требует от меня применения различных фильтров gabor к изображению, каждый пиксель на изображении имеет ориентацию и связанную с частотой, поэтому свертка не выполняется с одним ядром по всему изображению, но фильтр должен меняться во время процесс, зависящий от этих атрибутов пикселей, таким образом, каждый пиксель на изображении изменяется другим способом.

Если вы примените фильтры таким образом и сориентируете изображение несколько раз (вам также придется бинаризовать изображение после каждой свертки), вы получите следующее:

enter image description here

Мастер-отпечаток, это изображение заняло около 20 секунд, чтобы сгенерироваться (это слишком медленно, поэтому я хочу сделать это с помощью FFT), так как мне пришлось выполнить 5 раз свертку, чтобы завершить ее (вы начинаете из нескольких случайных черных точек).

Мои фильтры 30x30, а изображение - 275x400. Всего имеется 36000 фильтров, по одному для каждой степени и плотности (плотность от 0 до 100). Я планирую сократить количество фильтров с 36000 до 9000, так как я могу покрыть все эти углы. Также все фильтры предварительно вычисляются и сохраняются в банке фильтров.

Это исходный код в С# реализации свертки gabor:

Эти два метода выполняют свертку:

    /// <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 к изображению? раскрывать-etrange объясняет, как применять различные фильтры gabor к изображению, но вещь заключается в том, что способ, которым он это делает, применяет различные фильтры ко всему изображению, а затем суммирует ответы, и мне нужны ответы от разных пикселей к различным фильтрам.

Это то, что происходит, когда я сверлю один фильтр с изображением (используя FFT):

enter image description here

Это был использованный фильтр:

enter image description here

И это было изображение, которое было свернуто с помощью:

enter image description here

Это алгоритм в С# реализации FFT:

    /// <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 раз быстрее?

Также можно было бы сделать одно ядро ​​использующим все фильтры, поэтому я могу применить их ко всему изображению?

4b9b3361

Ответ 1

Я нашел способ свертки изображения с различными фильтрами gabor и собрать ответы базы пикселей по их локальным характеристикам с помощью FFT.

Это контекстная фильтрация вызовов, как правило, при фильтрации изображения вы применяете только одно ядро ​​ко всему предмету, но при контекстной фильтрации характеристики фильтра изменяются в соответствии с локальным контекстом, в этом случае плотность и ориентация пиксель.

В прямой свертке процесс довольно прямолинейный, вы просто меняете ядро ​​на каждом шаге свертки, но в свертке FFT, поскольку ядро ​​применяется к изображению в частотной области, вы не можете изменить свойства фильтра во время процесс. Таким образом, так, как вы делаете это, создавая свертку изображения с каждым фильтром отдельно, это даст N количество отфильтрованных изображений, где N - количество фильтров в вашем банке фильтров, тогда вы должны построить свою окончательную информацию об изображении, полученную от различные отфильтрованные изображения, основанные на контексте пикселя, который вы воссоздаете.

Итак, для каждого пикселя вы смотрите на его свойства ориентации и плотности, а затем захватываете значение этого положения пикселя из отфильтрованного изображения, которое было создано путем свертки исходного изображения с фильтром с теми же свойствами. Вот пример процесса:

Это графическое представление карты направленности.

enter image description here

Я использовал ту же плотность для всех пикселей, чтобы уменьшить количество сгенерированных фильтров.

Это исходное изображение:

enter image description here

Это пример из трех используемых фильтров (0 градусов, 45 градусов, 90 градусов):

enter image description hereenter image description hereenter image description here

Это три примера, когда исходное изображение свернулось с различными фильтрами в разной степени:

enter image description here

enter image description here

enter image description here

И, наконец, это результирующее изображение, изображение было создано с учетом значений пикселей из разных фильтрованных изображений в зависимости от направления и плотности пикселя.

enter image description here

Этот процесс LOT медленнее, чем прямая свертка = (, так как сначала необходимо сверлить исходное изображение со всеми фильтрами. Окончательное изображение заняло около минуты, чтобы сгенерироваться. До сих пор я застрял с прямой сверткой, которая кажется =/.

Спасибо за чтение.

Ответ 2

Вы пытались с CUDA? с сверткой и FFT (в данном случае cufft), это будет быстрее! Попытайтесь увидеть, есть ли возможность распараллеливания, на самом деле я над этим работаю, и могу сказать, что улучшение огромно. В настоящее время я собираюсь внедрить фильтрацию Gabor