182 lines
8.5 KiB
Python
182 lines
8.5 KiB
Python
import numpy as np
|
||
import numpy.typing as npt
|
||
from matplotlib import pyplot as plt
|
||
import random
|
||
import cv2
|
||
import uz_framework.image as uz_image
|
||
import os
|
||
|
||
#################################################################
|
||
# EXCERCISE 1: Exercise 1: Global approach to image description #
|
||
#################################################################
|
||
def ex1():
|
||
#one_a()
|
||
#one_b()
|
||
#one_c()
|
||
image, distances, selected_distances = one_d('./data/dataset', './data/dataset_reduced/', 10)
|
||
one_e(image, distances, selected_distances)
|
||
|
||
def one_a() -> npt.NDArray[np.float64]:
|
||
"""
|
||
Firstly, you will implement the function myhist3 that computes a 3-D histogram
|
||
from a three channel image. The images you will use are RGB, but the function
|
||
should also work on other color spaces. The resulting histogram is stored in a 3-D
|
||
matrix. The size of the resulting histogram is determined by the parameter n_bins.
|
||
The bin range calculation is exactly the same as in the previous assignment, except
|
||
now you will get one index for each image channel. Iterate through the image pixels
|
||
and increment the appropriate histogram cells. You can create an empty 3-D numpy
|
||
array with H = np.zeros((n_bins,n_bins,n_bins)). Take care that you normalize
|
||
the resulting histogram.
|
||
"""
|
||
lena = uz_image.imread('./data/images/lena.png', uz_image.ImageType.float64)
|
||
lincoln = uz_image.imread('./data/images/lincoln.jpg', uz_image.ImageType.float64)
|
||
lena_h = uz_image.get_image_bins_ND(lena, 128)
|
||
lincoln_h = uz_image.get_image_bins_ND(lincoln, 128)
|
||
print(uz_image.compare_two_histograms(lena_h, lincoln_h, uz_image.DistanceMeasure.euclidian_distance))
|
||
return lena_h
|
||
|
||
def one_b() -> None:
|
||
"""
|
||
In order to perform image comparison using histograms, we need to implement
|
||
some distance measures. These are defined for two input histograms and return a
|
||
single scalar value that represents the similarity (or distance) between the two histograms.
|
||
Implement a function compare_histograms that accepts two histograms
|
||
and a string that identifies the distance measure you wish to calculate
|
||
Implement L2 metric, chi-square distance, intersection and Hellinger distance.
|
||
Function implemented in uz_framework
|
||
"""
|
||
return None
|
||
|
||
def one_c() -> None:
|
||
"""
|
||
Test your function
|
||
Compute a 8×8×8-bin 3-D histogram for each image. Reshape each of them into a
|
||
1-D array. Using plt.subplot(), display all three images in the same window as well
|
||
as their corresponding histograms. Compute the L2 distance between histograms of
|
||
object 1 and 2 as well as L2 distance between histograms of objects 1 and 3.
|
||
|
||
Question: Which image (object_02_1.png or object_03_1.png) is more similar
|
||
to image object_01_1.png considering the L2 distance? How about the other three
|
||
distances? We can see that all three histograms contain a strongly expressed component (one bin has a much higher value than the others). Which color does this
|
||
bin represent
|
||
Answer:
|
||
"""
|
||
IM1 = uz_image.imread('./data/dataset/object_01_1.png', uz_image.ImageType.float64)
|
||
IM2 = uz_image.imread('./data/dataset/object_02_1.png', uz_image.ImageType.float64)
|
||
IM3 = uz_image.imread('./data/dataset/object_03_1.png', uz_image.ImageType.float64)
|
||
N_BINS = 8
|
||
|
||
H1 = uz_image.get_image_bins_ND(IM1, N_BINS).reshape(-1)
|
||
H2 = uz_image.get_image_bins_ND(IM2, N_BINS).reshape(-1)
|
||
H3 = uz_image.get_image_bins_ND(IM3, N_BINS).reshape(-1)
|
||
|
||
fig, axs = plt.subplots(2,3)
|
||
fig.suptitle('Euclidian distance between three images')
|
||
|
||
axs[0, 0].imshow(IM1)
|
||
axs[0, 0].set(title='Image1')
|
||
axs[0, 1].imshow(IM2)
|
||
axs[0, 1].set(title='Image2')
|
||
axs[0, 2].imshow(IM3)
|
||
axs[0, 2].set(title='Image3')
|
||
|
||
axs[1, 0].bar(np.arange(N_BINS**3), H1, width=3)
|
||
axs[1, 0].set(title=f'L_2(h1, h1) = {np.round(uz_image.compare_two_histograms(H1, H1, uz_image.DistanceMeasure.euclidian_distance), 2)}')
|
||
axs[1, 1].bar(np.arange(N_BINS**3), H2, width=3)
|
||
axs[1, 1].set(title=f'L_2(h1, h2) = {np.round(uz_image.compare_two_histograms(H1, H2, uz_image.DistanceMeasure.euclidian_distance), 2)}')
|
||
axs[1, 2].bar(np.arange(N_BINS**3), H3, width=3)
|
||
axs[1, 2].set(title=f'L_2(h1, h3) = {np.round(uz_image.compare_two_histograms(H1, H3, uz_image.DistanceMeasure.euclidian_distance), 2)}')
|
||
|
||
plt.show()
|
||
|
||
def one_d(directory: str, reduced_directory: str, n_bins: int):
|
||
"""
|
||
You will now implement a simple image retrieval system that will use histograms.
|
||
Write a function that will accept the path to the image directory and the parameter
|
||
n_bins and then calculate RGB histograms for all images in the directory as well as
|
||
transform them to 1-D arrays. Store the histograms in an appropriate data structure.
|
||
Select some image from the directory dataset/ and compute the distance between
|
||
its histogram and all the other histograms you calculated before. Sort the list according to the calculated similarity and display the reference image and the first
|
||
five most similar images to it. Also display the corresponding histograms. Do this
|
||
for all four distance measures that you implemented earlier.
|
||
Question: Which distance is in your opinion best suited for image retrieval? How
|
||
does the retrieved sequence change if you use a different number of bins? Is the
|
||
execution time affected by the number of bins?
|
||
"""
|
||
img_names = os.listdir(reduced_directory)
|
||
methods=[uz_image.DistanceMeasure.euclidian_distance, uz_image.DistanceMeasure.chi_square_distance,
|
||
uz_image.DistanceMeasure.intersection_distance, uz_image.DistanceMeasure.hellinger_distance ]
|
||
imgs=[]
|
||
hists=[]
|
||
selected_dists=[]
|
||
for i in range(len(img_names)):
|
||
imgs.append(uz_image.imread(f'{reduced_directory}/{img_names[i]}', uz_image.ImageType.float64))
|
||
hists.append(uz_image.get_image_bins_ND(imgs[i], n_bins).reshape(-1))
|
||
for method in methods:
|
||
fig, axs = plt.subplots(2, len(imgs))
|
||
fig.suptitle(f'Comparrison between different measures, using:{method.name}')
|
||
distances = []
|
||
for i in range(len(hists)):
|
||
distances.append(uz_image.compare_two_histograms(hists[0], hists[i], method))
|
||
|
||
indexes = np.argsort(distances)
|
||
selected_dists.append(distances)
|
||
|
||
for i in range(len(imgs)):
|
||
axs[0, i].imshow(imgs[indexes[i]])
|
||
axs[0, i].set(title=f'{img_names[indexes[i]]}')
|
||
axs[1, i].bar(np.arange(n_bins**3), hists[indexes[i]], width=2)
|
||
axs[1, i].set(title=f'd={distances[indexes[i]]}')
|
||
|
||
plt.show()
|
||
|
||
img_names = os.listdir(directory)
|
||
h_image = uz_image.get_image_bins_ND(imgs[0], n_bins).reshape(-1)
|
||
all_dists = [[] for _ in range(len(methods))]
|
||
|
||
for i in range(len(img_names)):
|
||
im = uz_image.imread(f'{directory}/{img_names[i]}', uz_image.ImageType.float64)
|
||
h = uz_image.get_image_bins_ND(im, n_bins).reshape(-1)
|
||
for j in range(len(methods)):
|
||
all_dists[j].append(uz_image.compare_two_histograms(h_image, h, methods[j]))
|
||
|
||
print(all_dists)
|
||
return hists[0], all_dists, selected_dists
|
||
|
||
def one_e(hist: npt.NDArray[np.float64], distances: list, selected_dists: list):
|
||
"""
|
||
You can get a better sense of the differences in the distance values if you plot all
|
||
of them at the same time. Use the function plt.plot() to display image indices
|
||
on the x axis and distances to the reference image on the y axis. Display both the
|
||
unsorted and the sorted image sequence and mark the most similar values using a
|
||
circle (see pyplot documentation)
|
||
"""
|
||
methods=[uz_image.DistanceMeasure.euclidian_distance, uz_image.DistanceMeasure.chi_square_distance,
|
||
uz_image.DistanceMeasure.intersection_distance, uz_image.DistanceMeasure.hellinger_distance ]
|
||
|
||
for i in range(len(distances)):
|
||
fig, axs = plt.subplots(1, 2)
|
||
fig.suptitle(f'Using {methods[i].name}')
|
||
indexes = np.arange(0, len(distances[i]) , 1)
|
||
makevery_indexes = []
|
||
|
||
for j in range(len(distances[i])):
|
||
print(distances[i][j])
|
||
if distances[i][j] in selected_dists[i]:
|
||
makevery_indexes.append(j)
|
||
|
||
axs[0].plot(indexes,distances[i],markevery=makevery_indexes, markerfacecolor = "none", marker = "o", markeredgecolor = "orange")
|
||
axs[1].plot(indexes,np.sort(distances[i]),markevery=makevery_indexes, markerfacecolor = "none", marker = "o", markeredgecolor = "orange")
|
||
plt.show()
|
||
|
||
|
||
# ######## #
|
||
# SOLUTION #
|
||
# ######## #
|
||
|
||
def main():
|
||
ex1()
|
||
|
||
if __name__ == '__main__':
|
||
main()
|