import numpy as np import cv2 import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import os import csv # 1. Function to apply Fast Fourier Transform to a colored image (separate for each channel) def apply_fft(image): """Apply Fast Fourier Transform to a colored image (separate for each channel)""" fft_channels = [] for channel in cv2.split(image): # Split the image into its color channels (B, G, R) fft = np.fft.fft2(channel) fft_shifted = np.fft.fftshift(fft) # Shift the zero frequency to the center fft_channels.append(fft_shifted) return fft_channels # 2. Function to display frequency components of each color channel in interactive 3D plots using Matplotlib def show_frequency_components_3d(fft_channels, title='Frequency Components'): """Display the magnitude and phase of the FFT for each channel (R, G, B) in 3D with Matplotlib""" channel_names = ['Blue Channel', 'Green Channel', 'Red Channel'] # Create a figure for 3D plotting fig = plt.figure(figsize=(18, 6)) # Loop through each channel's FFT data for i, fft_data in enumerate(fft_channels): magnitude = np.abs(fft_data) # Magnitude spectrum phase = np.angle(fft_data) # Phase spectrum # Generate grid for the 3D plot (x, y grid of frequencies) rows, cols = magnitude.shape x = np.linspace(-cols // 2, cols // 2, cols) y = np.linspace(-rows // 2, rows // 2, rows) X, Y = np.meshgrid(x, y) # Create a subplot for each channel's magnitude and phase ax = fig.add_subplot(1, 6, 2 * i + 1, projection='3d') ax.set_title(f'{channel_names[i]} - Magnitude') ax.plot_surface(X, Y, magnitude, cmap='viridis', edgecolor='none') ax = fig.add_subplot(1, 6, 2 * i + 2, projection='3d') ax.set_title(f'{channel_names[i]} - Phase') ax.plot_surface(X, Y, phase, cmap='inferno', edgecolor='none') plt.suptitle(title, fontsize=16) plt.tight_layout() plt.show() # 3. Function to apply percentage-based filtering to the FFT (for each channel) def filter_fft_percentage(fft_channels, percentage): """Apply percentage-based filtering, keeping the highest-magnitude frequency components""" filtered_fft = [] for fft_data in fft_channels: magnitude = np.abs(fft_data) flat_mag = magnitude.flatten() sorted_mag = np.sort(flat_mag)[::-1] # Sort magnitudes in descending order # Determine the threshold for the given percentage num_elements_to_keep = int(len(sorted_mag) * percentage / 100) threshold = sorted_mag[num_elements_to_keep - 1] if num_elements_to_keep > 0 else 0 # Create a mask to keep only the top frequencies mask = magnitude >= threshold filtered_fft.append(fft_data * mask) # Apply mask to the FFT data return filtered_fft # 4. Function to apply inverse Fourier transform to reconstruct the color image def inverse_fft(filtered_fft): """Apply inverse Fourier transform to reconstruct the image from filtered FFT""" reconstructed_channels = [] for fft_data in filtered_fft: fft_ishift = np.fft.ifftshift(fft_data) # Reverse FFT shift img_reconstructed = np.fft.ifft2(fft_ishift) # Apply inverse FFT img_reconstructed = np.abs(img_reconstructed) # Get the magnitude of the result # Normalize and convert to uint8 for image format img_normalized = cv2.normalize(img_reconstructed, None, 0, 255, cv2.NORM_MINMAX) reconstructed_channels.append(img_normalized.astype(np.uint8)) # Merge the channels back into a color image (BGR format) return cv2.merge(reconstructed_channels) # 5. Main function to process images in batches def process_images(): """Main function to process images, apply FFT, and filter results""" # Create directories if they don't exist os.makedirs('Modified', exist_ok=True) # Ask user for the percentage of top frequencies to keep percentage = float(input("Enter the percentage of highest-magnitude frequencies to keep (0-100): ")) print(f"Applying percentage-based filtering: Keeping top {percentage}% of frequencies.") # Create CSV logging file with open('fft_features.csv', 'w', newline='') as csvfile: csv_writer = csv.writer(csvfile) csv_writer.writerow(['Image', 'Max Magnitude', 'Mean Magnitude', 'Non-zero Count']) # Process each image in the 'original' folder image_filenames = [filename for filename in os.listdir('original') if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff'))] # Process all images for i, filename in enumerate(image_filenames): # Read image (colored) img_path = os.path.join('original', filename) img = cv2.imread(img_path) # Apply FFT to each channel (RGB) fft_channels = apply_fft(img) # Apply percentage-based filtering filtered_fft = filter_fft_percentage(fft_channels, percentage) # Reconstruct the image using inverse FFT reconstructed = inverse_fft(filtered_fft) # Show frequency components (filtered FFT) as interactive 3D plots using Matplotlib show_frequency_components_3d(filtered_fft, f'Filtered FFT - {filename}') # Log FFT features for the first channel (R) magnitude = np.abs(filtered_fft[0]) # Just checking the first channel's magnitude non_zero = magnitude > 0 csv_writer.writerow([ filename, np.max(magnitude), np.mean(magnitude[non_zero]) if np.any(non_zero) else 0, np.count_nonzero(non_zero) ]) # Save reconstructed image cv2.imwrite(os.path.join('Modified', filename), reconstructed) print("Processing completed successfully!") # Run the main function if __name__ == "__main__": process_images()