Differences

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

Link to this comparison view

Next revision
Previous revision
fp:lab07 [2021/04/22 12:45]
pdmatei created
fp:lab07 [2022/05/03 17:25] (current)
pdmatei
Line 1: Line 1:
-====== ​4Working with matrices and images using higher-order functions ​======+====== ​L07For expressions ​======
  
-===== 1Introduction =====+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 shall represent matrices as //lists of lists//, i.e. values of type ''​[ [Integer ] ]''​. Each element in the outer list represents a line of the matrix. ​ +<​code>​ 
-Hence, the matrix +    0 0 1 0 0 
- +    0 1 0 1 0 
-$math[ \displaystyle \left(\begin{array}{ccc} ​& 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right)]  +    ​0 ​1 1 0    letter A 
- +    1 0 0 0 
-will be represented by the list ''​[ [1,​2,​3],​[4,​5,​6],​[7,​8,​9] ]''​. +    0 0 0 
- +     
-To make signatures more legible, add the //type alias// to your code: +    5 4 3 2 1 
-<code haskell> type Matrix = [[Integer]] </​code>​ +    5 4 3 2 1 
-which makes the type-name ''​Matrix''​ stand for ''​[ [Integer] ]''​. +    5 4 3 2 1    shader 
- +    5 4 3 2 1 
-1.1. Write a function ''​parsem''​ which takes a string and parses it to a ''​Matrix''​. In the string, the columns are separated by whitespace and lines - by '​\n'​. ​ +    5 4 3 2 1
-     * (Hint: You need to perform two types of very similar splitting operations: one into lines, and another into column values, for each line) +
- +
-<code haskell> +
-parsem :: String -> Matrix +
-parsem = +
 </​code>​ </​code>​
  
-1.2. Write a function that converts a matrix to a string encoded as illustrated in the previous exercise.  +Add the following type definition for the rest of your lab
-     * (Hint: use folds) +<​code ​scala
-     * (Hint: test the function ''​show''​ on several different values) +type Img List[List[Int]]
-     * (Hintfirst make a function to display one line) +
- +
-<​code ​haskell>​ +
-toString:: Matrix -String +
-toString+
 </​code>​ </​code>​
  
-1.3. Add the following ​to your code. Test the function ''​displayMatrix''​. +Also, in order to benefit from visualisation,​ instead of using a worksheet, you can create a new Scala project, containing an object with a main method: 
-<​code ​haskell+<​code ​scala
-displayMatrix = putStrLn . toString +object Matrix { 
-</code> +// define your functions here
- +
-===== 2. Matrix operations ===== +
- +
-2.1. Write a function that computes the scalar product with an integer:+
  
-$math\displaystyle 2 * \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right) = \left(\begin{array}{ccc2 & 4 & 6 \\ 8 & 10 & 12 \\ 14 & 16 & 18 \\ \end{array}\right)] ​+  def main(args: Array[String]) = { 
 +  // write your tests here 
 +  ​} 
 +} 
 +</​code> ​
  
-<​code ​haskell+**7.1.** Write a function which converts an image to a string (Hint: you can draw inspiration from a similar one from the lecture): 
-vprod :: Integer -> Matrix -> Matrix +<​code ​scala
-vprod v +def show(mImg)String ​???
 </​code>​ </​code>​
  
-2.2. Write a function which adjoins two matrices by extending rows: +**7.2.** Write a function which performs a horizontal flip on an image. Try to first visualise ​(you may use pen and paperhow the transformation would look like. 
- +<​code ​scala
-$math[ \displaystyle \left(\begin{array}{cc} 1 & 2 \\ 3 & 4\\\end{array}\right hjoin \left(\begin{array}{cc} 5 & 6 \\ 7 & 8\\\end{array}\right) = \left(\begin{array}{cc} 1 & 2 & 5 & 6 \\ 3 & 4 & 7 & 8\\\end{array}\right) ] +def hFlip(imgImg)Img ???
- +
-<​code ​haskell+
-hjoin :: Matrix -> Matrix -> Matrix +
-hjoin +
 </​code>​ </​code>​
  
-2.3. Write a function which adjoins two matrices by adding new rows:+**7.3.** Write a function which performs vertical flip. 
 +<code scala> 
 +def vFlip(img: Img)Img = ??? 
 +</​code> ​
  
-$math[ \displaystyle \left(\begin{array}{cc} 1 & 2 \\ 3 & 4\\\end{array}\right) ​ vjoin \left(\begin{array}{cc} 5 & 6 \\ 7 & 8\\\end{array}\right) = \left(\begin{array}{cc} 1 & 2 \\ 3 & 4 \\ 5 & 6\\ 7 & 8\\ \end{array}\right+**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 ​scala
-<​code ​haskell+def rot90Right(imgImg)Img ???
-vjoin :: Matrix -> Matrix -> Matrix +
-vjoin +
 </​code>​ </​code>​
  
-2.4. Write a function which adds two matrices. +**7.5.** Write a function which performs a 90 degrees rotation to the left
- +<​code ​scala
-<​code ​haskell+def rot90Left(imgImg)Img ???
-msum :: Matrix -> Matrix -> Matrix +
-msum +
 </​code>​ </​code>​
  
-2.5. Write a function which computes the transposition of a matrix:+**7.6.** Write a function which inverts an image (values 0 become 255, 1 - 254, and so forth).
  
-$math[ tr \left(\begin{array}{ccc} ​& 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right= \left(\begin{array}{ccc} ​& 4 & 7 \\ & 5 & 8 \\ & 6 & 9 \\ \end{array}\right) ]+**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, ​yields: ​  1 1 1 
 +*     1 0 0 0 1 
 +*     1 0 0 0 1
  
-<code haskell>​ + */
-tr :: [[a]] -> [[a]] +
-tr ([]:_) = +
-tr m = +
-</code>+
  
-2.6. Write a function which computes the vectorial product of two matrices. +def cropAt(imgImg, xSt:Int, ySt:Int, xEnd: Int, yEnd: Int): Img = ?? 
-  * (Hintstart by writing a function which computes $math[a_{ij}] for a given line $math[i] and column $math[j] (both represented as lists)+</​code> ​
-  * (Hint: write a function which takes a line of matrix m1 and the matrix m2 and computes the respective line from the product)+
  
-<​code ​haskell+**7.8.** Write a function which returns a list of all positions which have pixels of larger intensity than x 
-mprod :: Matrix -> Matrix -> Matrix +<​code ​scala
-mprod m1 m2 +def largerPos(imgImg, intInt): List[(Int,​Int)] ​???
 </​code>​ </​code>​
  
-===== 3Image operations ===== +**7.9.** Write function ​which adds ''​x'' ​to the intensity of each pixel. 
- +<​code ​scala
-We can represent images as matrices of pixelsIn our example ​pixel will be represented as a ''​Char'', ​which can take the values: ​'*' ​(signifying that the respective pixel is //on//) and ' ' ​(the pixel is off) +def contrast(x: Int)(imgImg): Img = ???
- +
-<​code ​haskell> type Image = [String] </code+
- +
-For instance, a rectangle could be represented as: +
- +
-<​code>​ +
-******** +
-*      * +
-********+
 </​code>​ </​code>​
  
-more precisely, as the string: ​ +**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
-"​********\n* ​     *\n********\n"​+def hglue(img1: Img, img2: Img): Img = ???
 </​code>​ </​code>​
  
-3.1Implement an image-displaying ​function. Use the image from the Appendix as a test. +**7.11.** Write a function ​which takes two images ''​X''​ and ''​Y''​ and //glues// them on the vertical axis: 
-<​code ​haskell+<​code ​scala
-toStringImg ​:: Image -> String +def vglue(img1Img, img2Img): Img ???
-toStringImg ​ +
 </​code>​ </​code>​
  
-Add the following ​function ​in order to view images in nicer format: +**7.12.** Define a function ​that takes **square** image, and draws two diagonal lines of intensity 1 across it. Use ''​_.until(_)''​ and ''​_.toList''​. 
-<​code ​haskell+<​code ​scala
-displayImg ​putStrLn . toStringImg+def diag(img: Img): Img ???
 </​code>​ </​code>​
  
-3.2Implement ​a function which flips an image horizontally+**7.13.** Define ​a function which blurs an image as follows
-<code haskell> +  * for each pixel p of intensity ​1make all neighbouring pixels of intensity 0 equal to p-1 (including diagonals). 
-flipH :: Image -> Image  +  * 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 
-flipH =  +  * to make the implementation easier, you do not need to implement the blur on the image edges.
-</code>+
  
-3.3. Implement a function which flips an image vertically:​ +<​code ​scala
-<​code ​haskell+def blur(imgImg)Img ??? 
-flipV :: Image -> Image +</​code> ​
-flipV =  +
-</​code>​+
  
-3.4Implement a function which rotates an image 90grd clockwise +**7.14(!) ** Define ​a function which builds an effect ​of intensity x as shown below: 
-<code haskell>​ +<​code ​scala
-rotate90r :: Image -> Image +val img2 List( 
-rotate90r = +  List(0,​0,​0,​0,​0,​0,​0,​0,​0)
-</​code>​ +  List(0,​0,​0,​0,​0,​0,​0,​0,​0), 
- +  List(0,​0,​0,​0,​0,​0,​0,​0,​0)
-3.5. Implement a function which rotates an image -90grd clockwise +  List(0,​0,​0,​0,​1,​0,​0,​0,​0), 
-<code haskell>​ +  ​List(0,0,0,1,2,1,0,0,0), 
-rotate90l :: Image -> Image +  ​List(0,0,0,0,1,0,0,0,0), 
-rotate90l =  +  List(0,0,0,0,0,0,0,0,0)
-</​code>​ +  ​List(0,0,0,0,0,0,0,0,0), 
- +  List(0,0,0,0,0,0,0,0,0) 
-3.6. Implement a function which inverts an image: ' ' becomes ​and becomes ' ': +)
-<code haskell>​ +
-invert :: Image -> Image +
-invert =  +
-</​code>​ +
- +
-3.7. 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] +
- +
-3.8. Implement a function ''​maskDiscard''​ which takes a mask and some image and discards the part of the mask which overlays the image. +
- +
-$math[ maskDiscard\left(\begin{array}{ccc} ​ &  & * \\  &  & * \\  &  & * \\ \end{array}\right\left(\begin{array}{ccc} * &  & * \\ * &  &  \\ * &  & * \\ \end{array}\right) = \left(\begin{array}{ccc} ​ &  &  \\  &  & * \\  &  &  \\ \end{array}\right] +
- +
-3.9. Implement the ''​union'''​ of two images. +
-<code haskell>​ +
-union' :: Image -> Image -> Image +
-union' =  +
-</​code>​ +
-$math[ union \left(\begin{array}{ccc} ​ &  & * \\  &  & * \\  &  & * \\ \end{array}\right) \left(\begin{array}{ccc} * &  & * \\ * &  &  \\ * &  & * \\ \end{array}\right) = \left(\begin{array}{ccc} * &  & * \\ * &  & * \\ * &  & * \\ \end{array}\right) ] +
- +
-3.10. Implement a function which takes a list of transformation and an image and applies all those transformations. +
-<code haskell>​ +
-transformationSequence :: [Image -> Image] -> Image -> Image +
-</​code>​ +
-Test it with the following sequence +
-<code haskell>​ +
-seq1 = transformationSequence [invertunion' maskrotate90r] +
-</​code>​ +
- +
-===== 4. More matrices ===== +
- +
-4.1. Implement a function which places zeros **above** the diagonal of a square matrix. Use folds. +
- +
-4.2. Implement a function which places zeros **below** the diagonal of a square matrix. Use folds. +
- +
-4.3. Implement either of 4.or 4.2 using the function(s''​take''​ and ''​drop''​. Check the types of these and test them. +
- +
-4.4. Implement a function which computes the **diagonal** matrix of a square matrix. +
- +
-4.5. Implement a function which computes **recursively** the determinant of a matrix. What additional functions would be necessary?​ +
- +
-===== Appendix ===== +
- +
-<code haskell>​ +
-logo = [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>​ +
- +
-<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>​+
  
 +/*
 +Before: ​                  After (for x = 2)
  
 +    0 0 0 0 0 0 0 0 0      0 0 0 0 0 0 0 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 1 1 2 2 2 1 1 0
 +    0 0 0 0 1 0 0 0 0      0 1 2 2 3 2 2 1 0
 +    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
  
  
 +Hint: a single foldRight is sufficient. Which is the list you should apply it on?
 + */
 +def effect(intensity:​ Int, img: Img): Img = ???
 +</​code> ​