Starting from:
$35

$29

Project: Higher-Order Functions For Image Processing Solution

Introduction




We have learned how to use higher order functions, e.g., map, reduce, and filter, to perform tasks on arrays. We saw how such a functional programming approach allows us to abstract away the operations applied to array elements from the code required to iterate over the arrays. We also saw in project 1, how we could write several image filtering functions -- note how in all such filtering functions, there is a common structure: an iteration over the 2D array, and the computation of each pixel value. In this project, you will combine these two concepts to define higher order functions for image processing and use them to write write image processing functions with far less code than in Project 1.




Programming Task




Write a function called imageMap(img, func) that takes two arguments, an image img and a function func ,and returns a new image of the same size as the original, constructed by calling the function func for every pixel location. The function signature of func is func(img, x, y) where img is the input image, and x, y are the coordinates of the pixel for which func should return a pixel value. You may use the library functions lib220.createImage(width, height, fillColor) ,or image.copy() to create new images, or make copies of them as necessary. Note that the fillColor parameter for lib220.createImage needs to be a pixel value. Figure 1 shows an example output of using the imageMap function as follows:



let robot = lib220.loadImageFromURL('https://people.cs.umass.edu/~joydeepb/robot.jpg'); imageMap(robot, function(img, x, y) {




const c = img.getPixel(x, y); return [c[0], 0, 0];




}).show();




Write a function called imageMask(img, func, maskValue) that takes three arguments, an image img ,a function func , and a pixel value maskValue ,and returns a new image constructed by calling func for every pixel location, and setting the pixels to maskValue if func returns true, and to the original pixel value from the input image if it



returns false . The function signature of func is func(img, x, y), and it returns a boolean, where img is the input image, and x, y are the coordinates of the current pixel. You should use the imageMap higher order function -- this will enable you to write the imageMask function




without using any loops. You will have to use the imageMap function. Figure 2 shows an example output of using the imageMask function as follows:







let robot =




lib220.loadImageFromURL('https://people.cs.umass.edu/~joydeepb/robot.jpg');




imageMask(robot, function(img, x, y) { return (y % 10 === 0);}, [1, 0, 0]).show();













Write a function called blurPixel(img, x, y) to return the blurred value of the pixel at location x, y. To calculate the value of the blurred pixel, take the mean of all the individual color channels for the five pixels to the left of x,y, and five pixels to the right of x, y (i.e. over 11 pixels in total).
Write a function called blurImage(img) that takes in an image, and returns its blurred result. The output of this function should be identical in behavior to the blur function in project 1, with the only difference that in this function, you will not use any loops, but instead use a higher-order image processing function to perform the iteration.



Write a function called isD ark(img, x, y) that returns true if all the color channels of the pixel x,y are less than 0.5.
Write a function called darken(img) that takes in an image, and returns a copy where dark pixels (pixels where isDark returns true ) are replaced with black (pixel value [0, 0, 0] ). In this function, you must not use any loops, but instead use one of the higher-order image processing functions that you wrote.
Write a function called isLight (img, x, y) that returns true if all the color channels of the pixel x,y are greater than, or equal to 0.5.
Write a function called lighten(img) that takes in an image, and returns a copy where light pixels (pixels where isLight returns true) are replaced with white (pixel value [1, 1, 1] ). In this function, you must not use any loops, but instead use one of the higher-order image processing functions that you wrote.
Write a function called lightenAndDarken(img) that first applies the lighten operation, then the darken operation to the image, to produce an image with black and white sections. An example result is shown below.





Note that your code must not produce any run-time errors, irrespective of the input image dimensions.







Testing Your Code




As you already know, an important part of this project is testing your code thoroughly. In this project, in addition to testing with a variety of input images, you will also have to test with a variety of input functions to test your higher-order functions for correctness. To help you get started, we have provided a few test cases here. It is up to you to define additional tests to check your solution for correctness.




The value returned by imageMap should be an image, and it must be distinct from the input image.






test('imageMap function definition is correct', function() { let identityFunction = function(image, x, y) {




return image.getPixel(x, y);




};




let inputImage = lib220.createImage(10, 10, [0, 0, 0]); let outputImage = imageMap(inputImage, identityFunction);




Output should be an image, so getPixel must work without errors. let p = outputImage.getPixel(0, 0);



assert(p[0] === 0); assert(p[1] === 0); assert(p[2] === 0); assert(inputImage !== outputImage);




});




Test an identity function with imageMap. The resulting image should be unchanged. For this test, we will re-use the pixel equality testing helper function from project 1.






function pixelEq (p1, p2) {




const epsilon = 0.002;




for (let i = 0; i < 3; ++i) {




if (Math.abs(p1[i] - p2[i]) epsilon) {




return false;




}

}




return true;




};




test('identity function with imageMap', function() { let identityFunction = function(image, x, y ) {




return image.getPixel(x, y);




};




let inputImage = lib220.createImage(10, 10, [0.2, 0.2, 0.2]); inputImage.setPixel(0, 0, [0.5, 0.5, 0.5]); inputImage.setPixel(5, 5, [0.1, 0.2, 0.3]); inputImage.setPixel(2, 8, [0.9, 0.7, 0.8]);




let outputImage = imageMap(inputImage, identityFunction); assert(pixelEq(outputImage.getPixel(0, 0), [0.5, 0.5, 0.5])); assert(pixelEq(outputImage.getPixel(5, 5), [0.1, 0.2, 0.3])); assert(pixelEq(outputImage.getPixel(2, 8), [0.9, 0.7, 0.8])); assert(pixelEq(outputImage.getPixel(9, 9), [0.2, 0.2, 0.2]));

});




































































































































4

More products