diff --git a/assignment2/solution.py b/assignment2/solution.py index e479d7b..c435bf8 100644 --- a/assignment2/solution.py +++ b/assignment2/solution.py @@ -288,9 +288,11 @@ def two_e(): # EXCERCISE 3: Image Filtering # ################################ def ex3(): - three_a() - three_b() - three_c() + #three_a() + # three_b() + # three_c() + #three_d() + three_e() def three_a(): """ @@ -382,14 +384,84 @@ def three_c(): axs[3].set(title='Median') plt.show() + +def three_d(): + """ + Implement a 2-D version of the median filter. Test it on an image + that was corrupted by Gaussian noise and on an image that was corrupted by salt + and pepper noise. Compare the results with the Gaussian filter for multiple noise + intensities and filter sizes. + """ + lena = uz_image.imread('./data/images/obama.jpg', uz_image.ImageType.float64) + lena_grayscale = uz_image.transform_coloured_image_to_grayscale(lena.astype(np.float64)) + lena_salt_and_pepper = uz_image.sp_noise(lena_grayscale) + + # Depeppered + deppepered_lena = uz_image.apply_median_method_2D(lena_salt_and_pepper, 7) + # Sharpened + kernel = np.array([[-1, -1, -1], + [-1, 17, -1], + [-1, -1,-1]]) + + kernel = kernel * 1./9. + sharpened_lena = cv2.filter2D(deppepered_lena, cv2.CV_64F, kernel) + + + fig, axs = plt.subplots(1, 4) + + axs[0].imshow(lena_grayscale, cmap='gray') + axs[0].set(title='Orginal image') + axs[1].imshow(lena_salt_and_pepper, cmap='gray') + axs[1].set(title='Salt and Pepper applied') + axs[2].imshow(deppepered_lena, cmap='gray') + axs[2].set(title='Deppepeerd lena') + axs[3].imshow(sharpened_lena, cmap='gray') + axs[3].set(title='Sharpened lena') + + plt.show() + +def three_e(): + """ + Implement the hybrid image merging that was presented at the lectures. + To do this you will have to implement the Laplacian filter. Filter the images + (one with the Gaussian and one with the Laplacian filter) and merge them together + (regular or weighted average). You can use images lincoln.jpg and obama.jpg. + Hint: To get good results, experiment with different kernel sizes for each operation + and different weights when merging images. + """ + obama_image = uz_image.imread_gray('./data/images/obama.jpg', uz_image.ImageType.float64) + lincoln_image = uz_image.imread_gray('./data/images/lincoln.jpg', uz_image.ImageType.float64) + laplaced_obama = uz_image.filter_laplace(obama_image, 35) + gaussed_lincoln = uz_image.gaussfilter2D(lincoln_image, 5) + + merged = uz_image.sum_two_grayscale_images(laplaced_obama, gaussed_lincoln) + + fig, axs = plt.subplots(2, 3) + fig.suptitle('Linoln and Obama') + + axs[0, 0].imshow(lincoln_image, cmap='gray') + axs[0, 0].set(title='Lincoln') + axs[1, 0].imshow(gaussed_lincoln, cmap='gray') + axs[1, 0].set(title='Lincoln gauss') + axs[0, 1].imshow(obama_image, cmap='gray') + axs[0, 1].set(title='Obama') + axs[1, 1].imshow(laplaced_obama, cmap='gray') + axs[1, 1].set(title='Obama laplace') + axs[0, 2].imshow(merged, cmap='gray') + axs[0, 2].set(title='Merged') + axs[1, 2].set_visible(False) + + plt.show() + + # ######## # # SOLUTION # # ######## # def main(): #ex1() - ex2() - #ex3() + #ex2() + ex3() if __name__ == '__main__': main() diff --git a/assignment2/uz_framework/image.py b/assignment2/uz_framework/image.py index 7acb558..43835cd 100644 --- a/assignment2/uz_framework/image.py +++ b/assignment2/uz_framework/image.py @@ -326,9 +326,18 @@ def get_gaussian_kernel(sigma: float): return result / np.sum(result) -def gaussfilter2D(imge: Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], sigma: float): - kernel = get_gaussian_kernel(sigma) - kernel = cv2.filter2D(kernel, cv2.CV_64F, kernel) +def gaussfilter2D(image: Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], sigma: float) -> Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]]: + """ + Accepts: image, sigma + Applies gaussian noise on image + returns: filtered_image + """ + filtered_image = image.copy() + kernel = np.array(get_gaussian_kernel(sigma)) + filtered_image = cv2.filter2D(filtered_image, cv2.CV_64F, kernel) + filtered_image = cv2.filter2D(filtered_image, cv2.CV_64F, kernel.T) + + return filtered_image def simple_median(signal: npt.NDArray[np.float64], width: int): signal = signal.copy() @@ -340,6 +349,44 @@ def simple_median(signal: npt.NDArray[np.float64], width: int): signal[middle_element] = np.median(signal[i:i+width]) return signal +def apply_median_method_2D(image:Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], width: int): + if width % 2 == 0: + raise Exception('No u won\'t do that') + image = image.copy() + W_HALF = int(np.floor(width/2)) + padded_image = np.pad(image, W_HALF, mode='edge') + print(image.shape) + IMAGE_HEIGHT = image.shape[0] # y + IMAGE_WIDTH = image.shape[1] # x + + for x in range(W_HALF, IMAGE_WIDTH): + for y in range(W_HALF, IMAGE_HEIGHT): + median_filter = np.zeros(0) + STARTX = x - W_HALF + STARTY = y - W_HALF + for m in range(width): + median_filter = np.append(median_filter, padded_image[STARTY + m][STARTX: STARTX + width], axis=0) + if image.dtype.type == np.uint8: + image[y][x] = int(np.mean(median_filter)) + else: + image[y][x] = np.mean(median_filter) + return image + +def filter_laplace(image:Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], sigma: float): + # Prepare unit impulse and gauss kernel + unit_impulse = np.zeros((1, 2 * int(np.ceil(3*sigma)) + 1)) + unit_impulse[0][int(np.ceil(unit_impulse.size /2)) - 1]= 1 + gauss_kernel = get_gaussian_kernel(sigma) + assert(len(gauss_kernel) == len(unit_impulse[0])) + + laplacian_filter = unit_impulse - gauss_kernel + + # Now apply laplacian filter + applied_by_x = cv2.filter2D(image, -1, laplacian_filter) + applied_by_y = cv2.filter2D(applied_by_x, -1, laplacian_filter.T) + + return applied_by_y + def gauss_noise(I, magnitude=.1): # input: image, magnitude of noise # output: modified image @@ -366,4 +413,6 @@ def sp_noise1D(signal, percent=.1): signal[np.random.rand(signal.shape[0]) < percent / 2] = 0.4 return signal - +def sum_two_grayscale_images(image_a: Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], image_b :Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]]) -> Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]]: + # Merge image_a and image_b + return (image_a + image_b)/ 2