[CT404]: Finish Assignment 2
This commit is contained in:
@ -0,0 +1,40 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
# Load and pre-process binary image
|
||||
binary_image = cv2.imread("./output/kernel_size_17.jpg", cv2.IMREAD_GRAYSCALE)
|
||||
binary_image = cv2.medianBlur(binary_image, 3)
|
||||
|
||||
# Step 1.5: Extraction of Binary Regions of Interest / connected components
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8)
|
||||
|
||||
# Initialize an empty mask for filtered regions
|
||||
filtered_mask = np.zeros(binary_image.shape, dtype=np.uint8)
|
||||
|
||||
total_globules = 0
|
||||
|
||||
# Task 1.6: Filtering of Fat Globules
|
||||
for i in range(1, num_labels):
|
||||
area = stats[i, cv2.CC_STAT_AREA]
|
||||
|
||||
# Calculate compactness
|
||||
perimeter = cv2.arcLength(cv2.findContours((labels == i).astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][0], True)
|
||||
compactness = (perimeter ** 2) / area if area > 0 else 0
|
||||
|
||||
if (300 < area) and (compactness < 27):
|
||||
total_globules += 1
|
||||
filtered_mask[labels == i] = 255
|
||||
|
||||
cv2.imwrite("./output/filtered_fat_globules.jpg", filtered_mask)
|
||||
print("Total globules: " + str(total_globules))
|
||||
|
||||
# Task 1.7: Calculation of the Fat Area
|
||||
# Total area of the image in pixels (excluding the background)
|
||||
total_image_area = binary_image.shape[0] * binary_image.shape[1]
|
||||
|
||||
# Total fat area (in pixels)
|
||||
fat_area = np.sum(filtered_mask == 255)
|
||||
|
||||
# Calculate fat percentage
|
||||
fat_percentage = (fat_area / total_image_area) * 100
|
||||
print(f"Fat Area Percentage: {fat_percentage:.2f}%")
|
@ -1,23 +0,0 @@
|
||||
# Task 1.5: Extraction of Binary Regions of Interest / Connected Components
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
# read in noise-reduced image
|
||||
image = cv2.imread("./output/kernel_size_25.jpg", cv2.IMREAD_GRAYSCALE)
|
||||
|
||||
# Find connected components
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=4)
|
||||
|
||||
# Create an output image (color) to label components
|
||||
output_img = np.zeros((image.shape[0], image.shape[1], 3), dtype=np.uint8)
|
||||
|
||||
# Apply a single color (e.g., gray) to each component in the output image
|
||||
for label in range(1, num_labels): # Skip background (label 0)
|
||||
output_img[labels == label] = (200, 200, 200) # Light gray color for each component
|
||||
|
||||
# Overlay red text labels at component centroids
|
||||
for i in range(1, num_labels): # Skip background (label 0)
|
||||
x, y = int(centroids[i][0]), int(centroids[i][1])
|
||||
cv2.putText(output_img, str(i), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) # Red color (BGR: (0, 0, 255))
|
||||
|
||||
cv2.imwrite("./output/region_of_interest.jpg", output_img)
|
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
After Width: | Height: | Size: 803 KiB |
Binary file not shown.
After Width: | Height: | Size: 799 KiB |
@ -28,4 +28,42 @@ plt.imshow(magnitude_spectrum, cmap='gray')
|
||||
plt.axis('off')
|
||||
plt.savefig("./output/2_frequency_domain_low-pass_filter.jpg", bbox_inches='tight', pad_inches=0)
|
||||
|
||||
# Task 2.3: Frequency Domain Filtering
|
||||
# Task 2.3: Frequency Domain Filtering for
|
||||
channels = cv2.split(image)
|
||||
filtered_channels = []
|
||||
|
||||
for channel in channels:
|
||||
fft_channel = np.fft.fft2(channel)
|
||||
|
||||
# shift the zero frequency component to the center
|
||||
fft_channel_shifted = np.fft.fftshift(fft_channel)
|
||||
|
||||
# create a Gaussian filter the same size as the channel
|
||||
gaussian_kernel = cv2.getGaussianKernel(kernel_size[0], variance)
|
||||
gaussian_kernel_2d = gaussian_kernel @ gaussian_kernel.T
|
||||
|
||||
# pad the Gaussian filter to match the size of the image channel
|
||||
gaussian_kernel_padded = np.pad(gaussian_kernel_2d,
|
||||
((0, fft_channel_shifted.shape[0] - gaussian_kernel_2d.shape[0]),
|
||||
(0, fft_channel_shifted.shape[1] - gaussian_kernel_2d.shape[1])),
|
||||
mode='constant', constant_values=0)
|
||||
|
||||
# shift the padded filter in the frequency domain
|
||||
fft_gaussian_padded_shifted = np.fft.fftshift(np.fft.fft2(gaussian_kernel_padded))
|
||||
|
||||
# apply the low-pass filter to the channel
|
||||
low_pass_filtered = fft_channel_shifted * fft_gaussian_padded_shifted
|
||||
|
||||
# perform the inverse FFT to get the filtered channel in the spatial domain
|
||||
ifft_filtered = np.fft.ifft2(np.fft.ifftshift(low_pass_filtered))
|
||||
|
||||
# take the real part and normalize it
|
||||
filtered_channel = np.real(ifft_filtered)
|
||||
filtered_channel = np.clip(filtered_channel, 0, 255).astype(np.uint8)
|
||||
|
||||
# append the filtered channel to the list
|
||||
filtered_channels.append(filtered_channel)
|
||||
|
||||
filtered_image_color = cv2.merge(filtered_channels)
|
||||
|
||||
cv2.imwrite("./output/3_filtered_color_image.jpg", filtered_image_color)
|
||||
|
@ -0,0 +1,53 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
# Task 2.1: Spatial Domain
|
||||
image = cv2.imread("jennifer.jpg")
|
||||
|
||||
kernel_size = (15, 15)
|
||||
variance = 20
|
||||
|
||||
smoothed_image = cv2.GaussianBlur(image, kernel_size, variance)
|
||||
|
||||
cv2.imwrite("./output/jennifer_spatial.jpg", smoothed_image)
|
||||
|
||||
# Task 2.3: Frequency Domain Filtering for
|
||||
channels = cv2.split(image)
|
||||
filtered_channels = []
|
||||
|
||||
for channel in channels:
|
||||
fft_channel = np.fft.fft2(channel)
|
||||
|
||||
# shift the zero frequency component to the center
|
||||
fft_channel_shifted = np.fft.fftshift(fft_channel)
|
||||
|
||||
# create a Gaussian filter the same size as the channel
|
||||
gaussian_kernel = cv2.getGaussianKernel(kernel_size[0], variance)
|
||||
gaussian_kernel_2d = gaussian_kernel @ gaussian_kernel.T
|
||||
|
||||
# pad the Gaussian filter to match the size of the image channel
|
||||
gaussian_kernel_padded = np.pad(gaussian_kernel_2d,
|
||||
((0, fft_channel_shifted.shape[0] - gaussian_kernel_2d.shape[0]),
|
||||
(0, fft_channel_shifted.shape[1] - gaussian_kernel_2d.shape[1])),
|
||||
mode='constant', constant_values=0)
|
||||
|
||||
# shift the padded filter in the frequency domain
|
||||
fft_gaussian_padded_shifted = np.fft.fftshift(np.fft.fft2(gaussian_kernel_padded))
|
||||
|
||||
# apply the low-pass filter to the channel
|
||||
low_pass_filtered = fft_channel_shifted * fft_gaussian_padded_shifted
|
||||
|
||||
# perform the inverse FFT to get the filtered channel in the spatial domain
|
||||
ifft_filtered = np.fft.ifft2(np.fft.ifftshift(low_pass_filtered))
|
||||
|
||||
# take the real part and normalize it
|
||||
filtered_channel = np.real(ifft_filtered)
|
||||
filtered_channel = np.clip(filtered_channel, 0, 255).astype(np.uint8)
|
||||
|
||||
# append the filtered channel to the list
|
||||
filtered_channels.append(filtered_channel)
|
||||
|
||||
filtered_image_color = cv2.merge(filtered_channels)
|
||||
|
||||
cv2.imwrite("./output/jennifer_freq.jpg", filtered_image_color)
|
Reference in New Issue
Block a user