Solve Questions 3 and 4 please from the pdf
Toronto Metropolitan University CPS125 Project - Winter 2023 Page 1 of 8 CPS125 Project – Winter 2023 Overall Instructions This is a group project with a maximum group size of 3. File named “cps125_project.c” is given. You must complete the requirements of this project by implementing the functions described in this document. Your project should produce a series of bitmap images (file extension BMP). Once you complete the project, submit only the file “cps125_project.c” and nothing else. Project background In today’s world, everyone has some experience with image filters ranging from photo editing software to social media applications. These filters are created using computer vision algorithms. In this project you practice applying the computer science concepts that you have learned in the course by implementing a few basic algorithms in C. This document will guide you through the core computer vision concepts and you will be required to implement them. 3-dimensional Array and Images In the lectures, the concept of 1-dimensional (1D) and 2-dimensional (2D) arrays is covered. We will extend that concept to 3-dimensional (3D) arrays, which is especially useful when dealing with images. This concept can be further extended to N-dimensional arrays, used in mathematics, physics, and machine learning applications. However, we will only focus on 3D arrays in this project. It is easy to think of an image as a 2D array since we can correlate each pixel location with a row and column where the number of columns and rows are the width and height of an image respectively. This is also referred to as the resolution or size of an image. In fact, each pixel does not have just one value but three values. Each value is the intensity of each channel of three colours: blue, green, and red. This intensity level is a number between 0 and 255. We can imagine an image to be a cuboid where each pixel location still has a row and column but the layers is divided such that layer 0 is for the blue pixels, layer 1 is for the green pixel and layer 2 is for the red pixel. Figure 1 is a diagram that illustrates this concept by showing a 3x3x3 cube representing a tiny image of 3 pixels by 3 pixels and their blue, green and red channels. To understand how to load an image into a 3D array we have to go back and visit the idea of 2D array. A 2D array in reality is just a 1D array where the actual memory location of a particular row and column can be calculated with the following formula: ????? = ??? × ????ℎ + ?????? We can extend this formula to access the 3 colour channels where: Figure 1 Toronto Metropolitan University CPS125 Project - Winter 2023 Page 2 of 8 ????????? = ????? + 0 ?????????? = ????? + 1 ???????? = ????? + 2 Let us apply this to the simple 3x3 pixels image example. In this example, the height and width of our image are both equal to 3. The size of the array that we need is 27 (3 × 3 × 3 = 27). We must declare an array and use the function malloc() (or calloc function) to allocate space for 27 unsigned integers. Suppose that we want the image to be all black with the pixel at 3rd row, 2nd column to be fully yellow. We can use a for loop to set all the pixel values to be zero. A fully yellow colour is where blue = 0; red = 255; and green = 255. We can then use the formula above to find which memory location to set. ????? = ???_??_?ℎ????? × (??? × ????ℎ + ??????) ????? = 3 × (2 × 3 + 1) = 21 ?????????? = 21 + 1 ???????? = 21 + 2 Let us now look at the code snippet that will accomplish this. You learned about int type in your lecture, we will use the type of byte, which is an unsigned integer of size 1 (byte). This means that a variable of type byte holds a number between 0 and 255. int width = 3, height = 3, row = 2, column = 1; int index, greenChannel, redChannel; byte *imgColour = calloc(width*height*3, sizeof(byte)); index = (2*width+1)*3; greenChannel = index + 1; redChannel = index + 2; imgColour[greenChannel] = 255; imgColour[redChannel] = 255; The code snippet above we declared an array named imageColour. The calloc() function was used to allocate space and initialize all the values to 0. We then calculate the index of the array to correspond with the pixel we want set to be yellow. Then used that to calculate the index of the green channel and red channel. We then use those indices to assign the value to the appropriate pixel channel. The next section will provide you with detail information on the tasks you must complete for this project. Toronto Metropolitan University CPS125 Project - Winter 2023 Page 3 of 8 Project Tasks Description In the file “cps125_project.c” given to you, there is code that will read in and write out to bitmap files. The code will read in a bitmap file and place the pixel data in an array in the same format described above. Your tasks will be to create filters and apply them to the image array. The rest of the code will output your filtered images back to bitmap files in the same folder. Do not change any of the core code except in the commented areas telling you to change it or add to it. Task 1 - Grayscale image conversion (10 marks) The first task in most computer vision algorithms is to convert the colour images into a grayscale image. A grayscale image is an image where each pixel has a shade of grey where the value lies between 0 and 255. To convert a colour image to a grayscale image we must average the three colour channels of the colour image to get the grey value. Since we crush our three colour channels into one channel, we only need a 2D array to hold our grayscale image. This simplicity will help us with other tasks later. For example, if we know a pixel from the colour image to have a blue value of 100, green value of 50, and red value of 180, then the grey value is 110. 100 + 50 + 180 3 = 110 In the “cps125_project.c” find the main function. Note that a function named ReadImage() is called. This function will read a bitmap file and load all the pixel information into the array colourImg, and the value of width and height of the image and assign them to the variable width and height respectively. The size of the colourImg array is width x height x 3. Look for the comment that starts with, /* Task 1 - Allocate memory for greyImg in main here After the comment, write the code that allocate space for the variable greyImg. The variable greyImg should be a 2D array of type byte with the size of width x height of the image. After allocating memory, go to the function colourToGrey(). You must write the code of the body of this function. The function takes in the input arguments colour, height, width, calculates the grey value of each pixel and then assigning that grey value to the argument grey. Note that colour will be a 3D array and grey will be a 2D array. Once Task 1 is completed find the macro TASK1 located just above the main function. Set it to be 1 instead of 0 and then compile and run your program. This will produce a grayscale image in the same folder and is named “flowers_grey.bmp”. You can then open that image to see if you implemented your function correctly. If your implementation of colourToGrey() is correct, the program will tell you that you completed it successfully. If not, you can look at the output image and compare it to the “ground truth” image name “flowers_grey_GT.bmp” That is what the image is supposed to look like. If you find Task 1 to be too difficult, perhaps due to the idea of 3D array, you can choose to skip it. There is a macro called SKIP_TASK1. Set it to be 1 and it will skip it but still allow you to work on the other tasks which deal with only 2D arrays. To do this, you must make sure you have the file “flowers_grey_GT.bmp” in the same folder. Toronto Metropolitan University CPS125 Project - Winter 2023 Page 4 of 8 Task 2 – Convolution function (10 marks) The convolution function is an important function in calculus that can be applied to many different applications. We are applying it to our computer vision task here. We will not worry much about the mathematic theory but instead we will treat it like a matrix multiplication function. In our case we will convolve a 3x3 matrix called the kernel with every 3x3 patch of pixels on our grayscale image and then assign the value from our convolution to the middle pixel. For example, if we have a generalized kernel defined and a 3x3 patch of pixels. ?????? = [ ?0,0 ?0,1 ?0,2 ?1,0 ?1,1 ?1,2 ?2,0 ?2,1 ?2,2 ] ??????????ℎ = [ ?0,0 ?0,1 ?0,2 ?1,0 ?1,1 ?1,2 ?2,0 ?2,1 ?2,2 ] The convolution of these two matrices is calculated as the sum of the product of the matching values of each matrix’s component. ?????? = (?0,0 × ?0,0 + ?0,1 × ?0,1 + ?0,2 × ?0,2 +?1,0 × ?1,0 + ?1,1 × ?1,1 + ?1,2 × ?1,2 + ?2,0 × ?2,0 + ?2,1 × ?2,1 + ?2,2 × ?2,2 ) Suppose that we have an example of an image of size 5x5. Below is a diagram of how a convolution operation should be calculated. Notice that all the values are integers so the return results should match. kernel 1 2 1 2 4 2 1 2 1 inputImg 50 50 50 100 100 50 50 50 100 100 50 50 50 100 100 50 50 50 100 100 50 50 50 100 100 ?????? = 1 × 50 + 2 × 50 + 1 × 100 + 2 × 50 + 4 × 50 + 2 × 100 + 1 × 50 + 2 × 50 + 1 × 100 ?????? = 1000 For Task 2, you are to implement the convolution() function in the “cps125_project.c” file. The function takes in a 3x3 array as the kernel, a 2D array input image (inputImg), the center pixel location, and the width of the input image. The output should be the result of convolving inputImg with kernel at the center pixel. The center location is calculated with the formula below. In the example of the 5x5 image above the center location would be 7. ?????? = ??? × ????ℎ + ?????? The function MUST use nested for loops to perform the calculation. If you do not use loops, no marks will be given for this task. Once Task 2 is completed find the macro TASK2 located just above the main function. Set it to be 1 instead of 0 and then compile and run your program. This will run a test and will output on the console indicating if you complete the task correctly or not. Toronto Metropolitan University CPS125 Project - Winter 2023 Page 5 of 8 Task 3 – Applying Gaussian blur filter (10 marks) Applying a blurring filter over an image is a way to reduce the noise that is produced when an image is taken by averaging out each pixel with its surrounding neighbour. This is often the first operation that is performed in an image processing task. To apply a blurring filter, you perform convolutions on every pixel over the entire image with a kernel. One example of such kernel is the Gaussian kernel. You have already seen it in the previous task. Since we are doing an average, we must take the result from the convolution and divide it by the sum of the components of our Gaussian kernel, which equals 16 in our case. Note that (1 + 2 + 1 + 2 + 4 + 2 + 1 + 2 + 1 = 16) It is not entirely true that we are going to