IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Aug 26, 2010, 9:18:39 AM (16 years ago)
Author:
Serge CHASTEL
Message:

Merging trunk in branch

Location:
branches/sc_branches/trunkTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/sc_branches/trunkTest

  • branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.c

    r21183 r29060  
    2323#include <pthread.h>
    2424
     25#include "psAbort.h"
    2526#include "psAssert.h"
    2627#include "psError.h"
     
    532533    return out;
    533534}
     535
     536void psKernelFFTFree(psKernelFFT *kernel) {
     537
     538    if (!kernel->fft) return;
     539   
     540    bool threaded = psThreadPoolSize(); // Are we running threaded?
     541
     542    FFTW_LOCK;
     543    fftwf_free(kernel->fft);
     544    FFTW_UNLOCK;
     545
     546    return;
     547}
     548
     549psKernelFFT *psKernelFFTAlloc(const psKernel *input) {
     550
     551    psKernelFFT *kernel = psAlloc(sizeof(psKernelFFT));
     552    psMemSetDeallocator(kernel, (psFreeFunc)psKernelFFTFree);
     553
     554    kernel->fft = NULL;
     555
     556    kernel->xMin = input->xMin;
     557    kernel->xMax = input->xMax;
     558    kernel->yMin = input->yMin;
     559    kernel->yMax = input->yMax;
     560
     561    kernel->paddedCols = 0;
     562    kernel->paddedRows = 0;
     563
     564    return kernel;
     565}
     566
     567// generate the FFTed kernel image appropriate to be used for convolution of the given input image
     568psKernelFFT *psImageConvolveKernelInit(const psImage *in, const psKernel *kernel)
     569{
     570    PS_ASSERT_IMAGE_NON_NULL(in, NULL);
     571    PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL);
     572    PS_ASSERT_KERNEL_NON_NULL(kernel, NULL);
     573
     574    bool threaded = psThreadPoolSize(); // Are we running threaded?
     575
     576    int numCols = in->numCols, numRows = in->numRows; // Size of image
     577    int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Kernel sizes
     578
     579    // Need to pad the kernel (and later the input image) to protect from wrap-around effects
     580    if (xMax - xMin > numCols || yMax - yMin > numRows) {
     581        // Cannot pad the image if the kernel is larger.
     582        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
     583                _("Kernel cannot extend further than input image size (%dx%d vs %dx%d)."),
     584                xMax, yMax, numCols, numRows);
     585        return NULL;
     586    }
     587
     588    int paddedCols = numCols + PS_MAX(-xMin, xMax); // Number of columns in padded image
     589    int paddedRows = numRows + PS_MAX(-yMin, yMax); // Number of rows in padded image
     590
     591#if CONVOLVE_FFT_BINARY_SIZE
     592    // Make the size an integer power of two
     593    {
     594        int twoCols, twoRows;           // Size that is a factor of two
     595        for (twoCols = 1; twoCols <= paddedCols && twoCols < INT_MAX - 1; twoCols <<= 1); // No action
     596        for (twoRows = 1; twoRows <= paddedRows && twoRows < INT_MAX - 1; twoRows <<= 1); // No action
     597        if (paddedCols > twoCols || paddedRows > twoRows) {
     598            psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Unable to scale size (%dx%d) up to factor of two",
     599                    paddedCols, paddedRows);
     600            return NULL;
     601        }
     602        paddedCols = twoCols;
     603        paddedRows = twoRows;
     604    }
     605#endif
     606
     607    int numPadded = paddedCols * paddedRows; // Number of pixels in padded image
     608
     609    // Create data array containing the padded kernel
     610    FFTW_LOCK;
     611    psF32 *data = fftwf_malloc(numPadded * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Data for FFTW
     612    FFTW_UNLOCK;
     613
     614    // Generate the padded kernel image.  We could generate the padded kernel image using
     615    // memcpy, but by going pixel by pixel we can apply the normalisation that corrects for the
     616    // FFT renormalisation.  By applying it to the kernel here, we save applying it to the
     617    // output image(s).
     618
     619    // copy kernel into data array
     620    psF32 *dataPtr = data;              // Pointer into FFTW data
     621    float norm = 1.0 / (float)(paddedRows * paddedCols); // Normalisation to correct for FFT
     622
     623    int xNegMin = PS_MIN(-1, xMin), xNegMax = PS_MIN(-1, xMax); // Min and max for x when negative
     624    int xPosMin = PS_MAX(0, xMin), xPosMax = PS_MAX(0, xMax); // Min and max for x when positive
     625    int yNegMin = PS_MIN(-1, yMin), yNegMax = PS_MIN(-1, yMax); // Min and max for x when negative
     626    int yPosMin = PS_MAX(0, yMin), yPosMax = PS_MAX(0, yMax); // Min and max for x when positive
     627    int blankCols = xNegMin + paddedCols - xPosMax - 1; // Number of columns between kernel extrema
     628    int blankRows = (yNegMin + paddedRows - yPosMax - 1) * paddedCols; // Rows between kernel extrema
     629    size_t blankColBytes = blankCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes in blankCols
     630    for (int y = yPosMin; y <= yPosMax; y++) {
     631        // y is positive
     632        for (int x = xPosMin; x <= xPosMax; x++, dataPtr++) {
     633            // x is positive
     634            *dataPtr = kernel->kernel[y][x] * norm;
     635        }
     636        // Columns between kernel extrema
     637        memset(dataPtr, 0, blankColBytes);
     638        dataPtr += blankCols;
     639        for (int x = xNegMin; x <= xNegMax; x++, dataPtr++) {
     640            // x is negative
     641            *dataPtr = kernel->kernel[y][x] * norm;
     642        }
     643    }
     644    // Rows between kernel extrema
     645    memset(dataPtr, 0, blankRows * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
     646    dataPtr += blankRows;
     647    for (int y = yNegMin; y <= yNegMax; y++) {
     648        // y is negative
     649        for (int x = xPosMin; x <= xPosMax; x++, dataPtr++) {
     650            // x is positive
     651            *dataPtr = kernel->kernel[y][x] * norm;
     652        }
     653        // Columns between kernel extrema
     654        memset(dataPtr, 0, blankColBytes);
     655        dataPtr += blankCols;
     656        for (int x = xNegMin; x <= xNegMax; x++, dataPtr++) {
     657            // x is negative
     658            *dataPtr = kernel->kernel[y][x] * norm;
     659        }
     660    }
     661
     662#if 0
     663    {
     664        // Use this for inspecting the result of copying the kernel
     665        psImage *test = psImageAlloc(paddedCols, paddedRows, PS_TYPE_F32);
     666        psFree(test->p_rawDataBuffer);
     667        test->p_rawDataBuffer = data;
     668        test->data.V[0] = test->p_rawDataBuffer;
     669        for (int y = 1; y < paddedRows; y++) {
     670            test->data.V[y] = (psPtr)((int8_t *)test->data.V[y - 1] + paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
     671        }
     672        // View image here or write to disk
     673        test->p_rawDataBuffer = NULL;
     674        psFree(test);
     675    }
     676#endif
     677
     678    // Do the forward FFT
     679    // Note that the FFT images have different size from the input
     680    FFTW_LOCK;
     681    fftwf_complex *fft = fftwf_malloc((paddedCols/2 + 1) * paddedRows * sizeof(fftwf_complex)); // FFT
     682    FFTW_UNLOCK;
     683
     684    FFTW_LOCK;
     685    fftwf_plan plan = fftwf_plan_dft_r2c_2d(paddedRows, paddedCols, data, fft, FFTW_PLAN_RIGOR);
     686    FFTW_UNLOCK;
     687
     688    fftwf_execute(plan);
     689
     690    FFTW_LOCK;
     691    fftwf_destroy_plan(plan);
     692    fftwf_free(data);
     693    FFTW_UNLOCK;
     694
     695    psKernelFFT *output = psKernelFFTAlloc(kernel);
     696    output->fft = fft;
     697    output->paddedCols = paddedCols;
     698    output->paddedRows = paddedRows;
     699
     700    return output;
     701}
     702
     703psImage *psImageConvolveKernel(psImage *out, const psImage *in, const psImage *mask, psImageMaskType maskVal, const psKernelFFT *kernel)
     704{
     705    PS_ASSERT_IMAGE_NON_NULL(in, NULL);
     706    PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL);
     707    PS_ASSERT_PTR_NON_NULL(kernel, NULL);
     708    PS_ASSERT_PTR_NON_NULL(kernel->fft, NULL);
     709    if (mask) {
     710        PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
     711        PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_IMAGE_MASK, NULL);
     712        PS_ASSERT_IMAGES_SIZE_EQUAL(mask, in, NULL);
     713    }
     714
     715    bool threaded = psThreadPoolSize(); // Are we running threaded?
     716
     717    int numCols = in->numCols, numRows = in->numRows; // Size of image
     718    int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Kernel sizes
     719
     720    // Need to pad the input image to protect from wrap-around effects
     721    if (xMax - xMin > numCols || yMax - yMin > numRows) {
     722        // Cannot pad the image if the kernel is larger.
     723        psError(PS_ERR_BAD_PARAMETER_SIZE, true, _("Kernel cannot extend further than input image size (%dx%d vs %dx%d)."), xMax, yMax, numCols, numRows);
     724        return NULL;
     725    }
     726
     727    int paddedCols = numCols + PS_MAX(-xMin, xMax); // Number of columns in padded image
     728    int paddedRows = numRows + PS_MAX(-yMin, yMax); // Number of rows in padded image
     729
     730#if CONVOLVE_FFT_BINARY_SIZE
     731    // Make the size an integer power of two
     732    {
     733        int twoCols, twoRows;           // Size that is a factor of two
     734        for (twoCols = 1; twoCols <= paddedCols && twoCols < INT_MAX - 1; twoCols <<= 1); // No action
     735        for (twoRows = 1; twoRows <= paddedRows && twoRows < INT_MAX - 1; twoRows <<= 1); // No action
     736        if (paddedCols > twoCols || paddedRows > twoRows) {
     737            psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Unable to scale size (%dx%d) up to factor of two",
     738                    paddedCols, paddedRows);
     739            return NULL;
     740        }
     741        paddedCols = twoCols;
     742        paddedRows = twoRows;
     743    }
     744#endif
     745
     746    if (paddedCols != kernel->paddedCols) {
     747        psAbort(_("Image is inconsistent with allocated kernel"));
     748    }   
     749    if (paddedRows != kernel->paddedRows) {
     750        psAbort(_("Image is inconsistent with allocated kernel"));
     751    }   
     752
     753    int numPadded = paddedCols * paddedRows; // Number of pixels in padded image
     754
     755    // Create data array containing the padded image
     756    FFTW_LOCK;
     757    psF32 *data = fftwf_malloc(numPadded * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Data for FFTW
     758    FFTW_UNLOCK;
     759    psF32 *dataPtr = data;              // Pointer into FFTW data
     760    psF32 **imageData = in->data.F32;   // Pointer into image data
     761
     762    // Copy image into data array
     763    size_t goodBytes = numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes per image row
     764    size_t padBytes = (paddedCols - numCols) * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to pad
     765    for (int y = 0; y < numRows; y++, dataPtr += paddedCols, imageData++) {
     766        memcpy(dataPtr, *imageData, goodBytes);
     767        memset(dataPtr + numCols, 0, padBytes);
     768    }
     769    memset(dataPtr, 0, (paddedRows - numRows) * paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
     770
     771#if 0
     772    {
     773        // Use this for inspecting the result of copying the image
     774        psImage *test = psImageAlloc(paddedCols, paddedRows, PS_TYPE_F32);
     775        psFree(test->p_rawDataBuffer);
     776        test->p_rawDataBuffer = data;
     777        test->data.V[0] = test->p_rawDataBuffer;
     778        for (int y = 1; y < paddedRows; y++) {
     779            test->data.V[y] = (psPtr)((int8_t *)test->data.V[y - 1] +
     780                                      paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
     781        }
     782        // View image here
     783        test->p_rawDataBuffer = NULL;
     784        psFree(test);
     785    }
     786#endif
     787
     788    // Mask bad pixels (which may be NANs), lest they infect everything
     789    if (mask && maskVal) {
     790        for (int y = 0; y < numRows; y++) {
     791            for (int x = 0; x < numCols; x++) {
     792                if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) {
     793                    data[x + paddedCols * y] = 0;
     794                }
     795            }
     796        }
     797    }
     798
     799    // Do the forward FFT
     800    // Note that the FFT images have different size from the input
     801    FFTW_LOCK;
     802    fftwf_complex *fft = fftwf_malloc((paddedCols/2 + 1) * paddedRows * sizeof(fftwf_complex)); // FFT
     803    FFTW_UNLOCK;
     804
     805    int fftCols = paddedCols/2 + 1, fftRows = paddedRows; // Size of FFT images
     806    int fftPixels = fftCols * fftRows;  // Number of pixels in FFT image
     807
     808    FFTW_LOCK;
     809    fftwf_plan forward = fftwf_plan_dft_r2c_2d(paddedRows, paddedCols, data, fft, FFTW_PLAN_RIGOR);
     810    FFTW_UNLOCK;
     811
     812    fftwf_execute(forward);
     813
     814    FFTW_LOCK;
     815    fftwf_destroy_plan(forward);
     816    FFTW_UNLOCK;
     817
     818    fftwf_complex *kernelFFT = kernel->fft;
     819
     820    // Multiply the two transforms
     821    for (int i = 0; i < fftPixels; i++) {
     822        // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i
     823#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
     824        // C99 complex support
     825        fft[i] *= kernelFFT[i];
     826#else
     827        // FFTW's backup complex support
     828        float imageReal = fft[i][0], imageImag = fft[i][1];
     829        float kernelReal = kernelFFT[i][0], kernelImag = kernelFFT[i][1];
     830        fft[i][0] = imageReal * kernelReal - imageImag * kernelImag;
     831        fft[i][1] = imageImag * kernelReal + imageReal * kernelImag;
     832#endif
     833    }
     834
     835    // Do the backward FFT
     836    FFTW_LOCK;
     837    fftwf_plan backward = fftwf_plan_dft_c2r_2d(paddedRows, paddedCols, fft, data, FFTW_PLAN_RIGOR);
     838    FFTW_UNLOCK;
     839
     840    fftwf_execute(backward);
     841
     842    FFTW_LOCK;
     843    fftwf_destroy_plan(backward);
     844    fftwf_free(fft);
     845    FFTW_UNLOCK;
     846
     847    // Copy into the target, without the padding
     848    out = psImageRecycle(out, numCols, numRows, PS_TYPE_F32);
     849    psF32 **outData = out->data.F32;    // Pointer into output
     850    dataPtr = data;                     // Reset to start
     851    for (int y = 0; y < numRows; y++, outData++, dataPtr += paddedCols) {
     852        memcpy(*outData, dataPtr, goodBytes);
     853    }
     854
     855    FFTW_LOCK;
     856    fftwf_free(data);
     857    FFTW_UNLOCK;
     858
     859    return out;
     860}
Note: See TracChangeset for help on using the changeset viewer.