Assignment # 5
1. Task A1: DFT Calculations
Implementation Code:
import numpy as np import cv2
# Define sequences
A = [Link]([2, 3, 4, 5], dtype=complex)
B = [Link]([2, -3, 4, -5], dtype=complex)
C = [Link]([-9, -8, -7, -6], dtype=complex)
D = [Link]([-9, 8, -7, 6], dtype=complex) sequences = {'A':
A, 'B': B, 'C': C, 'D': D}
for name, seq in [Link](): # Compute
FFT
fft_result = [Link](seq) # Compute
inverse FFT
ifft_result = [Link](fft_result) print(f"{name} = {seq}")
print(f"FFT({name}):")
for i in range(len(fft_result)): real_part = fft_result[i].real
imag_part = fft_result[i].imag
print(f" {real_part:7.4f} + {imag_part:7.4f}j") print(f"IFFT({name}): {ifft_result.real}")
Results
1) FFT Results:
Sequence A: 14.0000 + 0.0000i, -2.0000 + 2.0000i, -2.0000 + 0.0000i, -2.0000 - 2.0000i
Sequence B: -2.0000 + 0.0000i, -2.0000 - 2.0000i, 14.0000 + 0.0000i, -2.0000 + 2.0000i
Sequence C: -30.0000 + 0.0000i, -2.0000 + 2.0000i, -2.0000 + 0.0000i, -2.0000 - 2.0000i
Sequence D: -2.0000 + 0.0000i, -2.0000 - 2.0000i, -30.0000 + 0.0000i, -2.0000 + 2.0000i
2) Inverse FFT Verification:
IFFT(A): [2, 3, 4, 5] ✓
IFFT(B): [2, -3, 4, -5] ✓
IFFT(C): [-9, -8, -7, -6] ✓
IFFT(D): [-9, 8, -7, 6] ✓
Conclusion: All inverse FFT calculations successfully recover the original sequences, verifying the correctness of
the DFT computations.
2. Task A3: Convolution Theorem
3.1 Python Implementation
Code:
import numpy as np
def convolution_theorem(): #
Example 1
i = [Link]([2, 4, 6, 8], dtype=float)
j = [Link]([-1, 2, -3, 4], dtype=float) # Direct
convolution
direct_conv1 = [Link](i, j, 'full') print(f"Direct
convolution: {direct_conv1}") # Convolution via FFT
i_padded = [Link](i, (0, len(j)-1), 'constant')
j_padded = [Link](j, (0, len(i)-1), 'constant') I_fft = [Link](i_padded)
J_fft = [Link](j_padded) product = I_fft *
J_fft
conv_via_fft1 = [Link](product)
print(f"Convolution via FFT: {[Link](conv_via_fft1.real, 6)}")
# Example 2
k = [Link]([4, 5, 6, 7], dtype=float)
l = [Link]([3, 1, 5, -1], dtype=float)
direct_conv2 = [Link](k, l, 'full') print(f"Direct
convolution: {direct_conv2}")
# Convolution via FFT for example 2
k_padded = [Link](k, (0, len(l)-1), 'constant')
l_padded = [Link](l, (0, len(k)-1), 'constant')
K_fft = [Link](k_padded) L_fft =
[Link](l_padded)
product2 = K_fft * L_fft conv_via_fft2 =
[Link](product2)
print(f"Convolution via FFT: {[Link](conv_via_fft2.real, 6)}")
3.2 Results and Verification
Example 1:
Direct Convolution: [-2, 0, -4, 0, 14, 0, 32]
FFT Method: [-2, 0, -4, 0, 14, 0, 32] ✓
Example 2:
Direct Convolution: [12, 19, 43, 48, 32, 29, -7]
FFT Method: [12, 19, 43, 48, 32, 29, -7] ✓
Conclusion:
Both convolution methods produce identical results, successfully verifying the convolution theorem that states
convolution in spatial domain equals multiplication in frequency domain.
3. Fourier Transform of Images
4.1 Python Implementation
Code:
import cv2
import numpy as np
import [Link] as plt
def fourier_analysis(image_path, title): # Read image
img = [Link](image_path, cv2.IMREAD_GRAYSCALE) #
Compute DFT
dft = [Link](np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift =
[Link](dft)
# Magnitude spectrum
magnitude = [Link](dft_shift[:,:,0], dft_shift[:,:,1]) magnitude_spectrum = 20 *
[Link](magnitude + 1)
# Create visualization [Link](figsize=(15, 5))
[Link](1, 3, 1) [Link](img,
cmap='gray') [Link]('Original Image')
[Link]('off')
[Link](1, 3, 2) [Link](magnitude_spectrum,
cmap='gray') [Link]('Magnitude Spectrum') [Link]('off')
[Link](1, 3, 3)
[Link]([Link](1 + magnitude), cmap='gray') [Link]('Log
Magnitude Spectrum') [Link]('off')
plt.tight_layout() [Link](f'output/fourier_{title}.png')
[Link]()
return magnitude_spectrum #
Analyze different images
fourier_analysis('Images/[Link]', 'square')
fourier_analysis('Images/[Link]', 'Keypad') fourier_analysis('Images/[Link]', 'aaa')
4.2 Results Analysis
The Fourier transform analysis reveals important frequency domain characteristics:
DC Component: Bright center point representing average intensity
Frequency Distribution: Patterns showing image texture and edges
Spectral Characteristics: Unique frequency signatures for different images
Log Transformation: Essential for visualizing wide dynamic range of frequency components
4. Image Rotation Analysis
5.1 Python Implementation
Code:
def rotate_and_analyze(image_path):
img = [Link](image_path, cv2.IMREAD_GRAYSCALE)
# Rotations
rotated_90 = [Link](img, cv2.ROTATE_90_CLOCKWISE)
# Rotate 45 degrees rows, cols
= [Link]
M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1) rotated_45 =
[Link](img, M, (cols, rows))
# Display rotation results [Link](figsize=(15, 5))
[Link](1, 3, 1) [Link](img,
cmap='gray') [Link]('Original') [Link]('off')
[Link](1, 3, 2) [Link](rotated_90,
cmap='gray') [Link]('Rotated 90°') [Link]('off')
[Link](1, 3, 3) [Link](rotated_45,
cmap='gray') [Link]('Rotated 45°') [Link]('off')
plt.tight_layout() [Link]('output/[Link]')
[Link]()
# Fourier analysis of rotated images
for rotated_img, rotation_name in [(rotated_90, '90'), (rotated_45, '45')]: dft =
[Link](np.float32(rotated_img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = [Link](dft)
magnitude = [Link](dft_shift[:,:,0], dft_shift[:,:,1]) [Link](figsize=(10, 4))
[Link](1, 2, 1)
[Link](rotated_img, cmap='gray')
[Link](f'Rotated {rotation_name}°') [Link]('off')
[Link](1, 2, 2)
[Link]([Link](1 + magnitude), cmap='gray') [Link](f'Fourier Spectrum -
{rotation_name}°') [Link]('off')
plt.tight_layout() [Link](f'output/fourier_rotated_{rotation_name}.png')
[Link]()
5.2 Rotation Effects Analysis
90° Rotation: Frequency spectrum rotates correspondingly by 90°
45° Rotation: Demonstrates angular relationship between spatial and frequency domains
Key Observation: Rotation in spatial domain equals rotation in frequency domain Practical
Implication: Rotation-invariant pattern recognition techniques
5. Filter Implementations
6.1 Ideal Lowpass Filter
Code:
def create_ideal_lowpass(shape, radius): rows, cols = shape
crow, ccol = rows // 2, cols // 2
mask = [Link]((rows, cols), np.float32) for i in
range(rows):
for j in range(cols):
if (i - crow)**2 + (j - ccol)**2 < radius**2: mask[i, j] = 1
return mask
# Apply ideal lowpass filter
img = [Link]('Images/[Link]', cv2.IMREAD_GRAYSCALE) ideal_mask =
create_ideal_lowpass([Link], 35)
dft = [Link](np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = [Link](dft)
filtered_dft = dft_shift * ideal_mask[:, :, [Link]] filtered_img =
[Link]([Link](filtered_dft))
filtered_img = [Link](filtered_img[:,:,0], filtered_img[:,:,1])
6.2 Butterworth Filters
Code:
def create_butterworth_lowpass(shape, cutoff, order=1): rows, cols = shape
crow, ccol = rows // 2, cols // 2 u, v =
[Link][0:rows, 0:cols]
d = [Link]((u - crow)**2 + (v - ccol)**2) h = 1 / (1 + (d /
cutoff) ** (2 * order)) return h
def create_butterworth_highpass(shape, cutoff, order=1): return 1 -
create_butterworth_lowpass(shape, cutoff, order)
# Apply Butterworth filters
butter_low = create_butterworth_lowpass([Link], 15, 1)
butter_high = create_butterworth_highpass([Link], 15, 1)
filtered_butter = dft_shift * butter_low[:, :, [Link]] butter_result =
[Link]([Link](filtered_butter))
butter_result = [Link](butter_result[:,:,0], butter_result[:,:,1])
filtered_high = dft_shift * butter_high[:, :, [Link]] high_result =
[Link]([Link](filtered_high))
high_result = [Link](high_result[:,:,0], high_result[:,:,1])
6.3 Gaussian Filters
Code:
def gaussian_filters():
img = [Link]('Images/[Link]', cv2.IMREAD_GRAYSCALE)
# Gaussian Lowpass with different sigmas sigmas =
[10, 30]
for sigma in sigmas:
# Create Gaussian kernel
gaussian_kernel = [Link](256, sigma) gaussian_kernel =
gaussian_kernel * gaussian_kernel.T
gaussian_kernel = [Link](gaussian_kernel, ([Link][1], [Link][0])) gaussian_kernel = gaussian_kernel /
[Link](gaussian_kernel)
# Apply in frequency domain
dft_shift = [Link]([Link](np.float32(img),
flags=cv2.DFT_COMPLEX_OUTPUT))
filtered_dft = dft_shift * gaussian_kernel[:, :, [Link]] filtered_img =
[Link]([Link](filtered_dft))
filtered_img = [Link](filtered_img[:,:,0], filtered_img[:,:,1])
```
6.4 High Boost Filtering
Code:
def high_boost_filter():
car_img = [Link]('Images/[Link]', cv2.IMREAD_GRAYSCALE)
# Convert to float
f = car_img.astype(np.float32)
# Create edge detection (Laplacian)
g = np.zeros_like(f)
for i in range(1, [Link][0]-1):
for j in range(1, [Link][1]-1):
g[i,j] = f[i,j+1] + f[i,j-1] + f[i-1,j] + f[i+1,j] - 4*f[i,j]
# High boost: original + edges k = 1.5 #
Boost factor
d=f+k*g
# Normalize for display
f_display = [Link](f, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) g_display =
[Link](g, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) d_display = [Link](d,
None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
6.5 Filter Results Analysis
1. Ideal Lowpass Filter:
Characteristics: Sharp cutoff in frequency domain
Advantages: Perfect frequency separation
Disadvantages: Causes ringing artifacts in spatial domain
Applications: Theoretical studies, perfect reconstruction
2. Butterworth Filters:
Characteristics: Smooth transition between pass and stop
bands Advantages: Reduced ringing compared to ideal filters
Disadvantages: Gradual roll-off requires higher order
Applications: Practical image processing, medical imaging
3. Gaussian Filters:
Characteristics: Completely eliminates ringing artifacts
Advantages: Smooth in both spatial and frequency domains
Disadvantages: Wider transition band
Applications: Noise reduction, multi-scale analysis
4. High Boost Filtering:
Characteristics: Enhances high-frequency components
Advantages: Edge enhancement while preserving image content
Applications: Image sharpening, detail enhancement
6. Theory Questions and Answers
7.1 Why display log of Fourier transform magnitude?
The DC-value (zero frequency component) is typically much larger than other frequency components. Without
logarithmic transformation, the dynamic range is too large to visualize properly on screen. The log transformation
compresses the dynamic range, making all frequency components visible.
Without log: Only DC component visible, everything else appears black With
log(1 + |F(u,v)|): All frequency components become visible in grayscale
Enables visualization of both strong and weak frequency components together
7.2 What remains after lowpass and highpass filtering?
Lowpass Filtering:
Preserves: Low frequency components (slow variations, smooth regions)
Removes: High frequency components (edges, noise, fine details)
Results: Blurred/smoothed image
Applications: Noise reduction, image smoothing, blurring
Highpass Filtering:
Preserves: High frequency components (edges, fine details, noise)
Removes: Low frequency components (slow variations, constant regions)
Results: Edge-enhanced or sharpened image
Applications: Edge detection, image sharpening, detail enhancement
7.3 Circular vs Linear convolution in 2D
Linear Convolution:
• Standard convolution operation used in spatial domain
• Output size = N1 + N2 - 1 (for 1D signals)
• No periodicity assumptions
• Used in traditional image filtering
Circular Convolution:
• Assumes periodic extension of signals
• Output size = max(N1, N2)
• Naturally occurs in frequency domain multiplication (DFT properties)
• Can cause wrap-around artifacts if not properly padded
In 2D Image Processing:
• DFT-based filtering performs circular convolution by default
• To achieve linear convolution: zero-pad images to size (M1+M2-1) × (N1+N2-1)
• Without proper padding: circular convolution causes artifacts at image boundaries
7.4 Ringing effect and how to fix it
Ringing Effect:
• Artifacts appearing as oscillations or 'ghosts' near sharp edges
• Caused by sharp cutoffs in frequency domain (e.g., ideal filters)
• Manifest as alternating bright/dark bands near edges
• More pronounced with ideal filters (rectangular frequency response)
How to Fix Ringing:
1. Use smoother filters (Butterworth, Gaussian) instead of ideal filters
2. Higher order Butterworth filters reduce ringing
3. Gaussian filters eliminate ringing completely (smooth in both domains)
4. Apply windowing techniques (Hamming, Hanning windows)
5. Use spatial domain filters with smooth impulse responses
Trade-off: Sharper cutoff → more ringing, Smoother cutoff → less ringing but more frequency leakage
7. Conclusion
This assignment successfully demonstrated various digital image processing techniques using Python and OpenCV.
Key achievements include:
1. DFT Implementation: Verified forward and inverse Fourier transform operations
2. Convolution Theorem: Experimentally confirmed equivalence between spatial and frequency domain convolution
3. Frequency Domain Analysis: Explored Fourier transforms of various images and their rotations
4. Filter Design: Implemented and compared ideal, Butterworth, and Gaussian filters
5. Practical Applications: Demonstrated high boost filtering for image enhancement
The results confirm the theoretical principles while providing practical insights into frequency domain image
processing. The Python implementation proved effective for educational purposes and practical applications in digital
image processing.