import UZ_utils as uz import numpy as np import numpy.typing as npt ####################################### # EXCERCISE 1: Basic image processing # ####################################### def excercise_one() -> None: image = one_a() one_b(image) one_c(image) one_d(100, 400, 50, 200, image) def one_a() -> npt.NDArray[np.float64]: """ Read the image from the file umbrellas.jpg and display it """ image = uz.imread('./images/umbrellas.jpg') uz.imshow(image, 'Umbrellas') return image def one_b(image: npt.NDArray[np.float64]) -> None: """ Convert the loaded image to grayscale. A very simple way of doing this is summing up the color channels and dividing the result by 3, effectively averaging the values. The issue, however, is that the sum easily reaches beyond the np.uint8 range. We can avoid that by casting the data to a floating point type. You can access a specific image channel using the indexing syntax like red = I[:,:,0]. """ grayscale_image = np.zeros(image.shape[:2]) for i in range(image.shape[0]): for j in range(image.shape[1]): grayscale_image[i, j] = (image[i, j, 0] + image[i,j, 1] + image[i, j, 2]) / 3 uz.imshow(grayscale_image, 'Umbrellas grayscale') def one_c(image: npt.NDArray[np.float64]) -> None: """ Cut and display a specific part of the loaded image. Extract only one of the channels so you get a grayscale image. You can do this by indexing along the first two axes, for instance: cutout=I[130:260, 240:450, 1]. You can display multiple images in a single window using plt.subplot(). Grayscale images can be displayed using different mappings (on a RGB monitor, every value needs to be mapped to a RGB triplet). Pyplot defaults to a color map named viridis, but often it is preferable to use a grayscale color map. This can be set with an additional argument to plt.imshow, like plt.imshow(I, cmap=’gray’). Question: Why would you use different color maps? Answer: """ print(image.shape) uz.imshow(image[50:200, 100:400, 2], "Just one piece of umbrellas") def one_d(startx: int, endx: int, starty: int, endy: int, image:npt.NDArray[np.float64]) -> None: """ (height, width, color) (y , x , color) x -> ################# y # # | # # v # # # # # # ################# You can also replace only a part of the image using indexing. Write a script that inverts a rectangular part of the image. This can be done pixel by pixel in a loop or by using indexing. Question: How is inverting a grayscale value defined for uint8 ? Answer: """ inverted_image = image.copy() for i in range(starty, endx): for j in range(startx, endy): inverted_image[i, j, 0] = 1 - image[i, j, 0] inverted_image[i, j, 1] = 1 - image[i, j, 1] inverted_image[i, j, 2] = 1 - image[i, j, 2] uz.imshow(inverted_image, 'Few umbrellas inverted') def one_e() -> None: """ Perform a reduction of grayscale levels in the image. First read the image from umbrellas.jpg and convert it to grayscale. You can write your own function for grayscale conversion or use the function in UZ_utils.py. Convert the grayscale image to floating point type. Then, rescale the image values so that the largest possible value is 63. Convert the image back to uint8 and display both the original and the modified image. Notice that both look the same. Pyplot tries to maximize the contrast in displayed images by checking their values and scaling them to cover the entire uint8 interval. If you want to avoid this, you need to set the maximum expected value when using plt.imshow(), like plt.imshow(I, vmax=255. Use this to display the resulting image so the change is visible. """ print("todo") def main() -> None: excercise_one() if __name__ == "__main__": main()