- Timestamp:
- Aug 26, 2010, 9:18:39 AM (16 years ago)
- Location:
- branches/sc_branches/trunkTest
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
psLib/src/fft/psImageFFT.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/sc_branches/trunkTest
- Property svn:mergeinfo changed
-
branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.c
r21183 r29060 23 23 #include <pthread.h> 24 24 25 #include "psAbort.h" 25 26 #include "psAssert.h" 26 27 #include "psError.h" … … 532 533 return out; 533 534 } 535 536 void 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 549 psKernelFFT *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 568 psKernelFFT *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 703 psImage *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.
