Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
fp:lab07 [2021/04/22 13:01] lfa |
fp:lab07 [2022/05/03 17:25] (current) pdmatei |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== 7. Working with matrices and images using higher-order functions ====== | + | ====== L07. For expressions ====== |
- | ===== 7.1. Bitmaps as matrices ===== | + | In this lab, we will use matrices to encode Bitmap images. The 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> |
- | m = "********\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 a test. | + | 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> |
- | 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 a 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(img: Img): 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(img: Img): 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(img: Img): 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(img: Img): 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.2. Combining 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> |
- | unionp :: Image -> Image -> Image | + | def contrast(x: Int)(img: Img): Img = ??? |
- | unionp = | + | |
</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(img1: Img, img2: Img): Img = ??? |
</code> | </code> | ||
- | Test it with the following sequence | ||
- | <code haskell> | ||
- | seq1 = transformationSequence [invert, unionp mask, rotate90r] | ||
- | </code> | ||
- | |||
- | ===== 7.3 Number Matrices ===== | ||
- | |||
- | 7.3.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}{ccc} 2 & 4 & 6 \\ 8 & 10 & 12 \\ 14 & 16 & 18 \\ \end{array}\right)] | ||
- | <code haskell> | + | **7.11.** Write a function which takes two images ''X'' and ''Y'' and //glues// them on the vertical axis: |
- | vprod :: Integer -> Matrix -> Matrix | + | <code scala> |
- | vprod v = | + | def vglue(img1: Img, img2: Img): Img = ??? |
</code> | </code> | ||
- | 7.3.2. Write a function which adjoins two matrices by extending rows: | + | **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> | |
- | $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 diag(img: Img): Img = ??? |
- | + | ||
- | <code haskell> | + | |
- | hjoin :: Matrix -> Matrix -> Matrix | + | |
- | hjoin = | + | |
</code> | </code> | ||
- | 7.3.3. Write a function which adjoins two matrices by adding new rows: | + | **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. | ||
- | $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) ] | + | <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: |
- | vjoin :: Matrix -> Matrix -> Matrix | + | <code scala> |
- | vjoin = | + | val img2 = List( |
- | </code> | + | List(0,0,0,0,0,0,0,0,0), |
+ | List(0,0,0,0,0,0,0,0,0), | ||
+ | List(0,0,0,0,0,0,0,0,0), | ||
+ | List(0,0,0,0,1,0,0,0,0), | ||
+ | List(0,0,0,1,2,1,0,0,0), | ||
+ | List(0,0,0,0,1,0,0,0,0), | ||
+ | List(0,0,0,0,0,0,0,0,0), | ||
+ | List(0,0,0,0,0,0,0,0,0), | ||
+ | List(0,0,0,0,0,0,0,0,0) | ||
+ | ) | ||
- | 7.3.4. Write a function which adds two matrices. | + | /* |
+ | Before: After (for x = 2) | ||
- | <code haskell> | + | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
- | msum :: Matrix -> Matrix -> Matrix | + | 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 |
- | msum = | + | 0 0 0 0 0 0 0 0 0 0 1 1 2 2 2 1 1 0 |
- | </code> | + | 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 | ||
- | ===== 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> | ||
+ | Hint: a single foldRight is sufficient. Which is the list you should apply it on? | ||
+ | */ | ||
+ | def effect(intensity: Int, img: Img): Img = ??? | ||
+ | </code> |