Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
fp:lab07 [2021/04/22 12:51]
pdmatei
fp:lab07 [2022/05/03 17:25] (current)
pdmatei
Line 1: Line 1:
-====== ​7Working with matrices and images using higher-order functions ​======+====== ​L07For expressions ​======
  
-===== 7.1Bitmaps ​as matrices =====+In this lab, we will use matrices to encode Bitmap imagesThe format is called BPM, and more details are available [[https://​en.wikipedia.org/​wiki/​Netpbm#​File_formats|here]]. Our format will be grayscale only. Each pixel of the matrix is encoded ​as an integer, with values from 0 to 255. Some examples are shown below:
  
-We can represent images as matrices of pixels. In our example a pixel will be represented as a ''​Char'',​ which can take the values: '​*'​ (signifying that the respective pixel is //on//) and ' ' (the pixel is off).  
- 
-<code haskell> type Image = [String] </​code>​ 
- 
-For instance, a rectangle could be represented as: 
 <​code>​ <​code>​
-******** +    0 0 1 0 0 
-*      * +    0 1 0 1 0 
-********+    0 1 1 1 0    letter A 
 +    1 0 0 0 1 
 +    1 0 0 0 1 
 +     
 +    5 4 3 2 1 
 +    5 4 3 2 1 
 +    5 4 3 2 1    shader 
 +    5 4 3 2 1 
 +    5 4 3 2 1
 </​code>​ </​code>​
  
-more precisely, as the string:  +Add the following type definition for the rest of your lab
-<​code ​haskell+<​code ​scala
-"​********\n* ​     *\n********\n"​+type Img List[List[Int]]
 </​code>​ </​code>​
  
-7.1.1. Implement an image-displaying function. Use the image from the Appendix as test. +Also, in order to benefit ​from visualisation,​ instead of using worksheet, you can create a new Scala project, containing an object with a main method: 
-<​code ​haskell+<​code ​scala
-toStringImg :: Image -> String +object Matrix { 
-toStringImg = +// define your functions here
  
-</​code>​+  def main(args: Array[String]) = { 
 +  // write your tests here 
 +  } 
 +
 +</​code> ​
  
-Add the following ​function ​in order to view images in nicer format+**7.1.** Write a function ​which converts an image to a string (Hint: you can draw inspiration from a similar one from the lecture)
-<​code ​haskell+<​code ​scala
-displayImg ​putStrLn . toStringImg+def show(m: Img): String ​???
 </​code>​ </​code>​
  
-7.1.2. Implement ​a function which flips an image horizontally:​ +**7.2.** Write a function which performs a horizontal flip on an image. Try to first visualise (you may use pen and paper) how the transformation would look like. 
-<​code ​haskell+<​code ​scala
-flipH :: Image -> Image  +def hFlip(imgImg)Img ???
-flipH +
 </​code>​ </​code>​
  
-7.1.3. Implement ​a function which flips an image vertically: +**7.3.** Write a function which performs vertical flip. 
-<​code ​haskell+<​code ​scala
-flipV :: Image -> Image +def vFlip(imgImg)Img ??? 
-flipV =  +</​code> ​
-</​code>​+
  
-7.1.4. Implement ​a function which rotates ​an image 90grd clockwise +**7.4.**  Write a function which performs a 90 degrees rotation to the right. (Hint: you need an ingredient from the lecture. Also, note that there are multiple possible implementations.) 
-<​code ​haskell+<​code ​scala
-rotate90r ​:: Image -> Image +def rot90Right(imgImg)Img ???
-rotate90r ​=+
 </​code>​ </​code>​
  
-7.1.5. Implement ​a function which rotates an image -90grd clockwise +**7.5.** Write a function which performs a 90 degrees rotation to the left. 
-<​code ​haskell+<​code ​scala
-rotate90l ​:: Image -> Image +def rot90Left(imgImg)Img ???
-rotate90l ​+
 </​code>​ </​code>​
  
-7.1.6. Implement ​a function which inverts an image: ' ' becomes * and * becomes ' ': +**7.6.** Write a function which inverts an image (values 0 become 255, 1 254, and so forth).
-<code haskell>​ +
-invert :: Image -> Image +
-invert =  +
-</​code>​+
  
-===== 7.2Combining images =====+**7.7.** Write a function which crops a given image, using two, two-dimensional coordinates:​ the higher-left point x and y, and the lower-right point x and y. An example is shown below: 
 +<code scala> 
 +val img List(List(0,​0,​1,​0,​0),​ List(0,​1,​0,​1,​0),​ List(0,​1,​1,​1,​0),​ List(1,​0,​0,​0,​1),​ List(1,​0,​0,​0,​1)) 
 +/* 
 +      0 0 1 0 0 
 +*     0 1 0 1 0                                           1 0 1 
 +*     0 1 1 1 0     ​cropping from 1,1  to  2,3  yields: ​  1 1 1 
 +*     1 0 0 0 1 
 +*     1 0 0 0 1
  
-7.2.1. Implement a function ''​maskKeep''​ which takes a mask and some image and only keeps the part of image which overlays the mask. Use the mask and the logo from Appendix to test it. + */
-<code haskell>​ +
-maskKeep :: Image -> Image -> Image +
-maskKeep =  +
-</​code>​ +
-$math[ maskKeep \left(\begin{array}{ccc} ​ &  & \\  &  & * \\  &  & * \\ \end{array}\right) \left(\begin{array}{ccc} * &  & * \\ * &  &  \\ * &  & * \\ \end{array}\right) = \left(\begin{array}{ccc} ​ &  & * \\  &  &  \\  &  & * \\ \end{array}\right) ]+
  
-7.2.2. Implement a function ''​maskDiscard''​ which takes a mask and some image and discards the part of the mask which overlays the image.+def cropAt(img: Img, xSt:Int, ySt:Int, xEnd: Int, yEnd: Int): Img = ?? 
 +</​code> ​
  
-$math[ maskDiscard\left(\begin{array}{ccc} ​ &  & \\  &  & \\  &  & \\ \end{array}\right) \left(\begin{array}{ccc} * &  & * \\ * &  &  \\ * &  & * \\ \end{array}\right= \left(\begin{array}{ccc} ​ &  &  \\  &  & * \\  &  &  \\ \end{array}\right) ]+**7.8.** Write a function which returns a list of all positions which have pixels of larger intensity than x 
 +<code scala> 
 +def largerPos(img: Img, int: Int): List[(Int,Int)] = ??? 
 +</​code>​
  
-7.2.3. Implement the ''​union'''​ of two images+**7.9.** Write a function which adds ''​x'' ​to the intensity ​of each pixel
-<​code ​haskell+<​code ​scala
-union' ​:: Image -> Image -> Image +def contrast(xInt)(imgImg): Img ???
-union' ​+
 </​code>​ </​code>​
-$math[ union \left(\begin{array}{ccc} ​ &  & * \\  &  & * \\  &  & * \\ \end{array}\right) \left(\begin{array}{ccc} * &  & * \\ * &  &  \\ * &  & * \\ \end{array}\right) = \left(\begin{array}{ccc} * &  & * \\ * &  & * \\ * &  & * \\ \end{array}\right) ] 
  
-7.2.4. Implement ​a function which takes a list of transformations ​and an image and applies all those transformations. +**7.10.** Write a function which takes two images ''​X''​ and ''​Y'' ​and //glues// them on the horizontal axis (the resulting ​image will be ''​XY''​) 
-<​code ​haskell+<​code ​scala
-transformationSequence ​:: [Image -> Image] -> Image -> Image+def hglue(img1Img, img2Img): Img = ???
 </​code>​ </​code>​
-Test it with the following sequence + 
-<​code ​haskell+**7.11.** Write a function which takes two images ''​X''​ and ''​Y''​ and //glues// them on the vertical axis: 
-seq1 = transformationSequence [invertunion' mask, rotate90r]+<​code ​scala
 +def vglue(img1: Imgimg2: Img): Img = ???
 </​code>​ </​code>​
  
 +**7.12.** Define a function that takes a **square** image, and draws two diagonal lines of intensity 1 across it. Use ''​_.until(_)''​ and ''​_.toList''​.
 +<code scala>
 +def diag(img: Img): Img = ???
 +</​code>​
  
 +**7.13.** Define a function which blurs an image as follows:
 +  * for each pixel p of intensity > 1: make all neighbouring pixels of intensity 0 equal to p-1 (including diagonals).
 +  * if some pixel of intensity 0 is in the vicinity of two different >1 pixels of different intensities,​ the one which is larger should be taken into account
 +  * to make the implementation easier, you do not need to implement the blur on the image edges.
  
-===== Appendix =====+<code scala> 
 +def blur(img: Img): Img ??? 
 +</​code> ​
  
-<​code ​haskell+**7.14. (!) ** Define a function which builds an effect of intensity x as shown below: 
-logo [l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19] +<​code ​scala
-    where l1 =" ​       ***** **            ***** **    " +val img2 List( 
-          l2 =" ​    ​****** ​ ****        ****** ​ ****   "​ +  List(0,0,0,0,0,0,0,0,0), 
-          l3 =" ​   **   ​* ​  ***      **   ​* ​ *  ***  " +  List(0,0,0,0,0,0,0,0,0)
-          l4 =" ​  ​* ​   *  *    ***    *    *  *    *** " +  ​List(0,​0,​0,​0,​0,​0,​0,​0,​0),​ 
-          l5 =" ​       ​* ​     **        *  *      ** " +  ​List(0,​0,​0,​0,​1,​0,​0,​0,​0),​ 
-          ​l6 ​=" ​     ** **      **       ** **      ** " +  List(0,​0,​0,​1,​2,​1,​0,​0,​0),​ 
-          l7 =" ​     ** **      **       ** **      ** " +  ​List(0,​0,​0,​0,​1,​0,​0,​0,​0),​ 
-          l8 =" ​   **** **      *      **** **      *  " +  List(0,​0,​0,​0,​0,​0,​0,​0,​0),​ 
-          l9 =" ​  * *** **     ​* ​     * *** **     ​* ​  "​ +  List(0,​0,​0,​0,​0,​0,​0,​0,​0),​ 
-          ​l10=" ​     ** ******* ​         ** ******* ​   +  ​List(0,​0,​0,​0,​0,​0,​0,​0,​0) 
-          l11=" ​     ** ****** ​          ** ****** ​    "​ +
-          ​l12=" ​     ** **               ** **         "​ + 
-          ​l13=" ​     ** **               ** **         "​ +/
-          ​l14=" ​     ** **               ** **         "​ +Before: ​                  After (for x 2) 
-          ​l15="​ **   ** **          **   ** **         "​ + 
-          l16="​*** ​  ​* ​ *          ***   ​* ​ *          " +    0 0 0 0 0 0 0 0 0      0 0 0 0 0 0 0 0 0 
-          l17=" ***    *            ***    *           "​ +    ​0 0 0 0 0 0 0 0 0      0 0 1 1 1 1 1 0 0 
-          ​l18=" ​ ****** ​             ****** ​           " +    0 0 0 0 0 0 0 0 0      0 1 1 2 2 2 1 1 0 
-          l19=" ​   ***                 ​*** ​            "​ +    ​0 0 0 0 1 0 0 0 0      0 1 2 2 3 2 2 1 0 
-</​code>​+    0 0 0 1 2 1 0 0 0      0 1 2 3 4 3 2 1 0 
 +    0 0 0 0 1 0 0 0 0      0 1 2 2 3 2 2 1 0 
 +    0 0 0 0 0 0 0 0 0      0 1 1 2 2 2 1 0 0 
 +    ​0 0 0 0 0 0 0 0 0      0 0 1 1 1 1 1 0 0 
 +    ​0 0 0 0 0 0 0 0 0      0 0 0 0 0 0 0 0 0
  
-<code haskell> 
-mask = [l1,​l2,​l3,​l4,​l5,​l6,​l7,​l8,​l9,​l10,​l11,​l12,​l13,​l14,​l15,​l16,​l17,​l18,​l19] 
-    where l1 =" ​                      ​*****************"​ 
-          l2 =" ​                      ​*****************"​ 
-          l3 =" ​                      ​*****************"​ 
-          l4 =" ​                      ​*****************"​ 
-          l5 =" ​                      ​*****************"​ 
-          l6 =" ​                      ​*****************"​ 
-          l7 =" ​                      ​*****************"​ 
-          l8 =" ​                      ​*****************"​ 
-          l9 =" ​                      ​*****************"​ 
-          l10=" ​                      ​*****************"​ 
-          l11=" ​                      ​*****************"​ 
-          l12=" ​                      ​*****************"​ 
-          l13=" ​                      ​*****************"​ 
-          l14=" ​                      ​*****************"​ 
-          l15=" ​                      ​*****************"​ 
-          l16=" ​                      ​*****************"​ 
-          l17=" ​                      ​*****************"​ 
-          l18=" ​                      ​*****************"​ 
-          l19=" ​                      ​*****************"​ 
-</​code>​ 
  
 +Hint: a single foldRight is sufficient. Which is the list you should apply it on?
 + */
 +def effect(intensity:​ Int, img: Img): Img = ???
 +</​code> ​