734 KiB
Uwaga: Należy rozwiązać oba poniższe zadania. Na zaliczenie potrzeba co najmniej 3 pkt.
Zadanie 1.(2x1.5 pkt): Zreplikować wyniki związane z materiałem na stronie 2d fourier transform in python and fourier synthesis of images. Istotą tego zadania jest poprawne zrozumienie działania transformaty Fouriera na obrazach - jego zaliczenie będzie polegało na odpowiedzi na dwa pytania teoretyczne.
Zadanie 2.(2x1 pkt): Napisać kod dwóch filtrów opartych o transformatę Fouriera: dolno i górnoprzepustowego. W pierwszym przypadku przykładowy obraz dobrej jakości zaburzyć kolejno trzema różnymi szumami dostępnyhmi w programie Gimp. W każdym przypadku zastosować filtr dolnoprzepustowy możliwie dokładnie przywracający obraz przed zaszumieniem. Następnie wygenerować filtr górnoprzepustowy wizualizujący w trzech powyższych przypadkach postać dodanego szumu. Materiał referencyjny znajduje się m.in. na stronie Low and High pass filtering experiments.html.
Zadanie 1
# gratings.py
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-500, 501, 1)
X, Y = np.meshgrid(x, x)
wavelength = 100
angle = np.pi/9
grating = np.sin(
2*np.pi*(X*np.cos(angle) + Y*np.sin(angle)) / wavelength
)
plt.set_cmap("gray")
plt.subplot(131)
plt.imshow(grating)
plt.axis("off")
# Calculate the Fourier transform of the grating
ft = np.fft.ifftshift(grating)
ft = np.fft.fft2(ft)
ft = np.fft.fftshift(ft)
plt.subplot(132)
plt.imshow(abs(ft))
plt.axis("off")
plt.xlim([480, 520])
plt.ylim([520, 480])
# Calculate the inverse Fourier transform of
# the Fourier transform
ift = np.fft.ifftshift(ft)
ift = np.fft.ifft2(ift)
ift = np.fft.fftshift(ift)
ift = ift.real # Take only the real part
plt.subplot(133)
plt.imshow(ift)
plt.axis("off")
plt.show()
# fourier_synthesis.py
import numpy as np
import matplotlib.pyplot as plt
image_filename = "Earth.png"
def calculate_2dft(input):
ft = np.fft.ifftshift(input)
ft = np.fft.fft2(ft)
return np.fft.fftshift(ft)
# Read and process image
image = plt.imread(image_filename)
image = image[:, :, :3].mean(axis=2) # Convert to grayscale
plt.set_cmap("gray")
ft = calculate_2dft(image)
plt.subplot(121)
plt.imshow(image)
plt.axis("off")
plt.subplot(122)
plt.imshow(np.log(abs(ft)))
plt.axis("off")
plt.show()
# fourier_synthesis.py
import numpy as np
import matplotlib.pyplot as plt
image_filename = "Elizabeth_Tower_London.jpg"
def calculate_2dft(input):
ft = np.fft.ifftshift(input)
ft = np.fft.fft2(ft)
return np.fft.fftshift(ft)
def calculate_2dift(input):
ift = np.fft.ifftshift(input)
ift = np.fft.ifft2(ift)
ift = np.fft.fftshift(ift)
return ift.real
def calculate_distance_from_centre(coords, centre):
# Distance from centre is √(x^2 + y^2)
return np.sqrt(
(coords[0] - centre) ** 2 + (coords[1] - centre) ** 2
)
def find_symmetric_coordinates(coords, centre):
return (centre + (centre - coords[0]),
centre + (centre - coords[1]))
def display_plots(individual_grating, reconstruction, idx):
plt.subplot(121)
plt.imshow(individual_grating)
plt.axis("off")
plt.subplot(122)
plt.imshow(reconstruction)
plt.axis("off")
plt.suptitle(f"Terms: {idx}")
plt.pause(0.01)
# Read and process image
image = plt.imread(image_filename)
image = image[:, :, :3].mean(axis=2) # Convert to grayscale
# Array dimensions (array is square) and centre pixel
# Use smallest of the dimensions and ensure it's odd
array_size = min(image.shape) - 1 + min(image.shape) % 2
# Crop image so it's a square image
image = image[:array_size, :array_size]
centre = int((array_size - 1) / 2)
# Get all coordinate pairs in the left half of the array,
# including the column at the centre of the array (which
# includes the centre pixel)
coords_left_half = (
(x, y) for x in range(array_size) for y in range(centre+1)
)
# Sort points based on distance from centre
coords_left_half = sorted(
coords_left_half,
key=lambda x: calculate_distance_from_centre(x, centre)
)
plt.set_cmap("gray")
ft = calculate_2dft(image)
# Show grayscale image and its Fourier transform
plt.subplot(121)
plt.imshow(image)
plt.axis("off")
plt.subplot(122)
plt.imshow(np.log(abs(ft)))
plt.axis("off")
plt.pause(2)
# Reconstruct image
fig = plt.figure()
# Step 1
# Set up empty arrays for final image and
# individual gratings
rec_image = np.zeros(image.shape)
individual_grating = np.zeros(
image.shape, dtype="complex"
)
idx = 0
# All steps are displayed until display_all_until value
display_all_until = 200
# After this, skip which steps to display using the
# display_step value
display_step = 10
# Work out index of next step to display
next_display = display_all_until + display_step
# Step 2
for coords in coords_left_half:
# Central column: only include if points in top half of
# the central column
if not (coords[1] == centre and coords[0] > centre):
idx += 1
symm_coords = find_symmetric_coordinates(
coords, centre
)
# Step 3
# Copy values from Fourier transform into
# individual_grating for the pair of points in
# current iteration
individual_grating[coords] = ft[coords]
individual_grating[symm_coords] = ft[symm_coords]
# Step 4
# Calculate inverse Fourier transform to give the
# reconstructed grating. Add this reconstructed
# grating to the reconstructed image
rec_grating = calculate_2dift(individual_grating)
rec_image += rec_grating
# Clear individual_grating array, ready for
# next iteration
individual_grating[coords] = 0
individual_grating[symm_coords] = 0
# Don't display every step
if idx < display_all_until or idx == next_display:
if idx > display_all_until:
next_display += display_step
# Accelerate animation the further the
# iteration runs by increasing
# display_step
display_step += 10
display_plots(rec_grating, rec_image, idx)
plt.show()
Zadanie 2
wmi1.jpg <- szum RGB wmi2.jpg <- szum Ich CIE wmi3.jpg <- szum HCV
import matplotlib.pyplot as plt
import numpy as np
img = plt.imread("wmi1.jpg")/float(2**8)
plt.imshow(img)
plt.show()
shape = img.shape[:2]
def draw_cicle(shape,diamiter):
assert len(shape) == 2
TF = np.zeros(shape,dtype=np.bool)
center = np.array(TF.shape)/2.0
for iy in range(shape[0]):
for ix in range(shape[1]):
TF[iy,ix] = (iy- center[0])**2 + (ix - center[1])**2 < diamiter **2
return(TF)
TFcircleIN = draw_cicle(shape=img.shape[:2],diamiter=150)
TFcircleOUT = ~TFcircleIN
fft_img = np.zeros_like(img,dtype=complex)
for ichannel in range(fft_img.shape[2]):
fft_img[:,:,ichannel] = np.fft.fftshift(np.fft.fft2(img[:,:,ichannel]))
def filter_circle(TFcircleIN,fft_img_channel):
temp = np.zeros(fft_img_channel.shape[:2],dtype=complex)
temp[TFcircleIN] = fft_img_channel[TFcircleIN]
return(temp)
fft_img_filtered_IN = []
fft_img_filtered_OUT = []
## for each channel, pass filter
for ichannel in range(fft_img.shape[2]):
fft_img_channel = fft_img[:,:,ichannel]
## circle IN
temp = filter_circle(TFcircleIN,fft_img_channel)
fft_img_filtered_IN.append(temp)
## circle OUT
temp = filter_circle(TFcircleOUT,fft_img_channel)
fft_img_filtered_OUT.append(temp)
fft_img_filtered_IN = np.array(fft_img_filtered_IN)
fft_img_filtered_IN = np.transpose(fft_img_filtered_IN,(1,2,0))
fft_img_filtered_OUT = np.array(fft_img_filtered_OUT)
fft_img_filtered_OUT = np.transpose(fft_img_filtered_OUT,(1,2,0))
def inv_FFT_all_channel(fft_img):
img_reco = []
for ichannel in range(fft_img.shape[2]):
img_reco.append(np.fft.ifft2(np.fft.ifftshift(fft_img[:,:,ichannel])))
img_reco = np.array(img_reco)
img_reco = np.transpose(img_reco,(1,2,0))
return(img_reco)
img_reco = inv_FFT_all_channel(fft_img)
img_reco_filtered_IN = inv_FFT_all_channel(fft_img_filtered_IN)
img_reco_filtered_OUT = inv_FFT_all_channel(fft_img_filtered_OUT)
fig = plt.figure(figsize=(25,18))
ax = fig.add_subplot(1,3,1)
ax.imshow(np.abs(img_reco))
ax.set_title("original image")
ax = fig.add_subplot(1,3,2)
ax.imshow(np.abs(img_reco_filtered_IN))
ax.set_title("low pass filter image")
ax = fig.add_subplot(1,3,3)
ax.imshow(np.abs(img_reco_filtered_OUT))
ax.set_title("high pass filtered image")
plt.savefig("zdjęcie 1.jpg")
plt.show()
C:\Users\tafit\AppData\Local\Temp\ipykernel_10380\320731908.py:11: FutureWarning: In the future `np.bool` will be defined as the corresponding NumPy scalar. TF = np.zeros(shape,dtype=np.bool)
[1;31m---------------------------------------------------------------------------[0m [1;31mAttributeError[0m Traceback (most recent call last) Cell [1;32mIn[2], line 20[0m [0;32m 16[0m TF[iy,ix] [38;5;241m=[39m (iy[38;5;241m-[39m center[[38;5;241m0[39m])[38;5;241m*[39m[38;5;241m*[39m[38;5;241m2[39m [38;5;241m+[39m (ix [38;5;241m-[39m center[[38;5;241m1[39m])[38;5;241m*[39m[38;5;241m*[39m[38;5;241m2[39m [38;5;241m<[39m diamiter [38;5;241m*[39m[38;5;241m*[39m[38;5;241m2[39m [0;32m 17[0m [38;5;28;01mreturn[39;00m(TF) [1;32m---> 20[0m TFcircleIN [38;5;241m=[39m [43mdraw_cicle[49m[43m([49m[43mshape[49m[38;5;241;43m=[39;49m[43mimg[49m[38;5;241;43m.[39;49m[43mshape[49m[43m[[49m[43m:[49m[38;5;241;43m2[39;49m[43m][49m[43m,[49m[43mdiamiter[49m[38;5;241;43m=[39;49m[38;5;241;43m150[39;49m[43m)[49m [0;32m 21[0m TFcircleOUT [38;5;241m=[39m [38;5;241m~[39mTFcircleIN [0;32m 25[0m fft_img [38;5;241m=[39m np[38;5;241m.[39mzeros_like(img,dtype[38;5;241m=[39m[38;5;28mcomplex[39m) Cell [1;32mIn[2], line 11[0m, in [0;36mdraw_cicle[1;34m(shape, diamiter)[0m [0;32m 9[0m [38;5;28;01mdef[39;00m [38;5;21mdraw_cicle[39m(shape,diamiter): [0;32m 10[0m [38;5;28;01massert[39;00m [38;5;28mlen[39m(shape) [38;5;241m==[39m [38;5;241m2[39m [1;32m---> 11[0m TF [38;5;241m=[39m np[38;5;241m.[39mzeros(shape,dtype[38;5;241m=[39m[43mnp[49m[38;5;241;43m.[39;49m[43mbool[49m) [0;32m 12[0m center [38;5;241m=[39m np[38;5;241m.[39marray(TF[38;5;241m.[39mshape)[38;5;241m/[39m[38;5;241m2.0[39m [0;32m 14[0m [38;5;28;01mfor[39;00m iy [38;5;129;01min[39;00m [38;5;28mrange[39m(shape[[38;5;241m0[39m]): File [1;32m~\AppData\Roaming\Python\Python312\site-packages\numpy\__init__.py:338[0m, in [0;36m__getattr__[1;34m(attr)[0m [0;32m 333[0m warnings[38;5;241m.[39mwarn( [0;32m 334[0m [38;5;124mf[39m[38;5;124m"[39m[38;5;124mIn the future `np.[39m[38;5;132;01m{[39;00mattr[38;5;132;01m}[39;00m[38;5;124m` will be defined as the [39m[38;5;124m"[39m [0;32m 335[0m [38;5;124m"[39m[38;5;124mcorresponding NumPy scalar.[39m[38;5;124m"[39m, [38;5;167;01mFutureWarning[39;00m, stacklevel[38;5;241m=[39m[38;5;241m2[39m) [0;32m 337[0m [38;5;28;01mif[39;00m attr [38;5;129;01min[39;00m __former_attrs__: [1;32m--> 338[0m [38;5;28;01mraise[39;00m [38;5;167;01mAttributeError[39;00m(__former_attrs__[attr]) [0;32m 340[0m [38;5;28;01mif[39;00m attr [38;5;241m==[39m [38;5;124m'[39m[38;5;124mtesting[39m[38;5;124m'[39m: [0;32m 341[0m [38;5;28;01mimport[39;00m [38;5;21;01mnumpy[39;00m[38;5;21;01m.[39;00m[38;5;21;01mtesting[39;00m [38;5;28;01mas[39;00m [38;5;21;01mtesting[39;00m [1;31mAttributeError[0m: module 'numpy' has no attribute 'bool'. `np.bool` was a deprecated alias for the builtin `bool`. To avoid this error in existing code, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here. The aliases was originally deprecated in NumPy 1.20; for more details and guidance see the original release note at: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations