File size: 6,147 Bytes
2ce4737
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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()