能否借助FFTW库在C++中将图像频谱的DC分量移至中心?
Absolutely! While FFTW doesn’t include a dedicated function to shift the DC component of an image spectrum to the center, this is a straightforward task to implement manually. There are two common approaches—pre-shifting the image before FFT or post-shifting the spectrum after FFT—and I’ll walk you through both below.
Background
By default, FFT places the DC component (the lowest frequency, representing the average intensity of the image) at the top-left corner (0,0) of the spectrum. To move it to the center, we need to perform a cyclic shift of M/2 rows and N/2 columns (where M is image height, N is width). This effectively swaps the four quadrants of the spectrum.
Approach 1: Pre-Shift the Image Before FFT
This method modifies the input image data before running the FFT, so the resulting spectrum is already center-aligned. The trick is to multiply each pixel by (-1)^(row + col)—this flips the sign of pixels where the sum of row and column indices is odd, which has the effect of shifting the spectrum’s DC component to the center once FFT is applied.
Code Example
#include <fftw3.h> #include <cstring> int main() { const int img_height = 512; const int img_width = 512; // Allocate memory for FFT input/output fftw_complex* input = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * img_height * img_width); fftw_complex* spectrum = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * img_height * img_width); // Create FFT plan (forward transform) fftw_plan fft_plan = fftw_plan_dft_2d(img_height, img_width, input, spectrum, FFTW_FORWARD, FFTW_ESTIMATE); // Load your image data into the real part of 'input' (set imaginary part to 0 if working with grayscale) // For example: memcpy(input, your_image_data, sizeof(float) * img_height * img_width); // Apply pre-shift: multiply each element by (-1)^(row + col) for (int row = 0; row < img_height; ++row) { for (int col = 0; col < img_width; ++col) { const float sign = ((row + col) % 2 == 0) ? 1.0f : -1.0f; input[row * img_width + col][0] *= sign; // Real component input[row * img_width + col][1] *= sign; // Imaginary component (if applicable) } } // Execute FFT fftw_execute(fft_plan); // Now 'spectrum' has DC component at the center (img_height/2, img_width/2) // Cleanup fftw_destroy_plan(fft_plan); fftw_free(input); fftw_free(spectrum); return 0; }
Note for Inverse FFT
If you later run an inverse FFT to get back the original image, you’ll need to apply the same (-1)^(row + col) multiplication again after the inverse transform to undo the pre-shift.
Approach 2: Post-Shift the Spectrum After FFT
If you’ve already computed the FFT and need to shift the spectrum afterward, you can perform a cyclic quadrant swap. This is often more efficient than pre-shifting because it uses block memory copies instead of per-pixel calculations.
Code Example
#include <fftw3.h> #include <cstring> // Shifts a 2D FFT spectrum so DC component moves to center void shift_spectrum(fftw_complex* spectrum, int height, int width) { const int half_h = height / 2; const int half_w = width / 2; const size_t quadrant_size = sizeof(fftw_complex) * half_h * half_w; // Temporary buffer to hold one quadrant fftw_complex* temp = (fftw_complex*)fftw_malloc(quadrant_size); // Swap top-left and bottom-right quadrants memcpy(temp, spectrum, quadrant_size); memcpy(spectrum, spectrum + half_h * width + half_w, quadrant_size); memcpy(spectrum + half_h * width + half_w, temp, quadrant_size); // Swap top-right and bottom-left quadrants memcpy(temp, spectrum + half_w, quadrant_size); memcpy(spectrum + half_w, spectrum + half_h * width, quadrant_size); memcpy(spectrum + half_h * width, temp, quadrant_size); fftw_free(temp); } // Usage example: // After executing FFT and getting 'spectrum' // shift_spectrum(spectrum, img_height, img_width);
Handling Odd Dimensions
If your image has odd dimensions (e.g., 513x513), the integer division height/2 will leave a single row/column in the center. This is fine—the DC component will still end up at the approximate center of the spectrum, and the quadrant swap logic works without modification.
Key Takeaways
- Pre-shifting is simpler if you’re planning the FFT from scratch, as it avoids extra post-processing steps.
- Post-shifting is faster for large images, thanks to block memory operations.
- FFTW doesn’t handle this shift natively because it’s a general-purpose FFT library—spectral shifting is an application-specific step, not part of the core FFT algorithm.
内容的提问来源于stack exchange,提问作者user7249049

