Haskell get Matrix from bmp Image - haskell

Hi Everyone Im beginner in Haskell I want to read and extract matrix of pixels (numbers) from a grayscale bmp image in haskell
anyone has idea how to do that I searched online without finding any clues thank you

Unfortunately, there are not as many tutorials on this topic as there should be, but it is at least not as hard as it might seem at first. As #leftaroundabout pointed out, the first thing you need is to decide on the library you want to use for dealing matrices. I personally would recommend massiv for array manipulation and massiv-io for reading and writing images. You didn't specify what exactly you want to do with the image, so all I am gonna provide in this example is reading a bmp image into an array, printing some stuff about the matrix and the writing it in jpg format:
module Main where
import Data.Massiv.Array as A
import Data.Massiv.Array.IO
main :: IO ()
main = do
img <- readImage "frog.bmp" :: IO (Image S SRGB Word8)
putStrLn $ "Size: " ++ show (size img)
putStrLn $ "Pixel at <row:10, col:20>: " ++ show (img ! (10 :. 20))
writeImageAuto "frog.jpg" img
Then if you save that snippet into a file named convert-bmp.hs, place frog.bmp image next to it then using stack:
$ stack --resolver lts-16.25 runghc --package massiv --package massiv-io convert-bmp.hs
Size: Sz (200 :. 320)
Pixel at <row:10, col:20>: <SRGB:( 61, 64, 35)>

Related

Get the Height and Width of an image

I'm very new to Haskell so I apologise if this is too basic, or if it makes very little sense. I'm trying to read an image; I can get it to a list of pixel data with the following code:
data Pixel = Pixel {
red :: Integer,
green :: Integer,
blue :: Integer,
alpha :: Integer
} deriving (Show)
getImagePixelArray :: FilePath -> IO (Codec.Picture.Repa.Img RGBA)
getImagePixelArray fp = do
img <- (either error return =<< readImageRGBA fp)
return img
getImagePixelData :: Codec.Picture.Repa.Img RGBA -> [(Word8,Word8,Word8,Word8)]
getImagePixelData img = R.toList (collapseColorChannel img)
rawPixelToPixel :: (Word8,Word8,Word8,Word8) -> Pixel
rawPixelToPixel (r, g, b, a) = Pixel {
red = (toInteger r),
green = (toInteger g),
blue = (toInteger b),
alpha = (toInteger a)
}
main = do
imageData <- getImagePixelArray "./images/image1.png"
let imageRawPixels = getImagePixelData imageData
let asPixels = Prelude.map rawPixelToPixel imageRawPixels
mapM print asPixels
I more or less follow what's going on, but my knowledge of Haskell is still limited, so when it comes to making sense of api documentation, I'm struggling a little.
I really want to be able to parse the positions of the pixels; I understand how to do that if I know the width and height of an image, but I can't figure out how to get the width/height of an image.
I'm making my way through a Haskell course, but I'm also trying to put it to some practical use along the way to help the concepts sink in.
Start with the documentation. None of what you're asking for is obviously available on Img, so where else could it be? There's a related Image type, mentioned in convertImage's documentation - I wonder what that is. As it turns out, it has a width and a height. How can we get an Image from our Img, then? imgToImage will give us a DynamicImage, which has several constructors each containing an Image. Figure out what kind of Image you have inside your DynamicImage, and then ask that Image its dimensions.
Perhaps there is something easier with the other lens-y stuff in that module, but it is not obvious to me, and this approach seems simple enough, if a hassle.

How do find the width of a Text Picture in gloss?

In the Haskell Gloss library, one draws text with the Text constructor of the Picture type. But how, then does one find the width (and height) of such a picture?
Here's how text is rendered in Gloss:
Text str
-> do
GL.blend $= GL.Disabled
GL.preservingMatrix $ GLUT.renderString GLUT.Roman str
GL.blend $= GL.Enabled
The important point here is that it calls renderString. Looking at the documentation for renderString, we immediately see two other useful functions: stringWidth and fontHeight. As such, you can get your width and height like this:
import Graphics.UI.GLUT.Fonts
do
width <- stringWidth Roman str
height <- fontHeight Roman

Haskell Diagrams: Why does text not have length or width?

I would like to create a text box that I can set to have a particular width and height. However, the text box that I create appears to not have a width and height in the first place. E.g. the following code:
main = do
putStrLn $ show $ width $ myText
putStrLn $ show $ height $ myText
mainWith myText
myText :: Diagram B
myText = text "here" # lw 1 # fontSizeL 0.2 # fc grey # scaleX 1
results in a blank diagram (with no text), and prints "0.0" as the width and height of the text box:
ghc --make Main.hs && ./Main -o circle.svg -w 400
[1 of 1] Compiling Main ( Main.hs, Main.o )
Linking Main ...
0.0
0.0
In order to get the text to appear it seem that I need to place it on top of something else. E.g. the following code:
main = do
putStrLn $ show $ width $ myDiagram
putStrLn $ show $ height $ myDiagram
mainWith myDiagram
myDiagram :: Diagram B
myDiagram = myText <> myBackground
myText :: Diagram B
myText = text "here" # lw 1 # fontSizeL 0.2 # fc grey # scaleX 1
myBackground :: Diagram B
myBackground = rect 1 1 # fc black
produces the grey text within a black background as expected.
Why does the text box not have a size?
How can I set the length and width of a text box to a certain value?
Why does the text box not have a size?
Because text handling is not only highly dependent on the backend used to render the diagrams (cf. the User's Guide) but also potentially dependent on how fonts are configured in the system used to run the program.
How can I set the length and width of a text box to a certain value?
Use text handling functions provided by your chosen backend, if they exist. For instance, diagrams-cairo provides functions that use Pango to render text on its own, though with the significant annoyance of them being IO functions, as they need to query font information from the system.
Use SVGFonts to stroke the text independently of the backend. There are a few inconveniences with this approach as well (limited choice of fonts unless you follow the instructions in the documentation to convert your chosen font to the SVGFonts format yourself; fonts with large sets of characters might lead to a small but noticeable delay when they are first used by your program, as they have to go through an initial processing), but at least you don't have to bother with IO or backend-specific quirks.

How to create this simple gif animation with Diagrams

I am trying to understand how to use Diagrams library in Haskell.
Here is my attempt at making a simple gif animation which switches between two circles of radii 1 and 2. I tried to mimic what I saw on
Here is the code, I tried.
{-# LANGUAGE NoMonomorphismRestriction #-}
import Diagrams.Backend.SVG.CmdLine
import Diagrams.Prelude
delays = take 2 (repeat 3)
gif :: [(Diagram B, Int)]
gif = zip [circle 1, circle 2] delays
main = mainWith $ gif
But this fails to compile! The errors I get are
[1 of 1] Compiling Main ( maze.hs, maze.o )
maze.hs:10:8:
No instance for (Diagrams.Backend.CmdLine.Parseable
(Diagrams.Backend.CmdLine.MainOpts
[(QDiagram B V2 Double Any, Int)]))
arising from a use of ‘mainWith’
In the expression: mainWith
In the expression: mainWith $ gif
In an equation for ‘main’: main = mainWith $ gif
Where am I going wrong in the code above?
It took me a moment to figure it out, because the error message is not obvious at all, but it's a backend problem. The documentation states that the cairo backend can create animated gif. However, you are using the svg backend (which is unable to understand what [(Diagram B, Int)] is.
To solve this, make sure you have the diagrams-cairo package installed, and change the line
import Diagrams.Backend.SVG.CmdLine
to
import Diagrams.Backend.Cairo.CmdLine
I'll explain the other steps necessary, since this is one of the first search results for doing animations in diagrams. Diagrams rescales the viewport to the image size for each circle, so that circle 1 and circle 2 are equivalent. To solve this you can lay the circles on invisible squares of the same size as circle 2.
Also the delays are given in 1/100 seconds. The correct code would then be:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Diagrams.Backend.Cairo.CmdLine
import Diagrams.Prelude
gif :: [(Diagram B, Int)]
gif = map (\x -> (x # lc white <> square 4 # lw none,300)) [circle 1,circle 2]
main = mainWith gif

Dynamically updating a plot in Haskell

I have a program which performs a long-going calculation where the result is shown as a plot.
I am currently using Chart-0.14 for this. I want to show the partial results, and update during calculations.
Graphics.Rendering.Chart.Gtk.updateCanvas :: Renderable a -> DrawingArea -> IO Bool seems to do that, but I do not find any way to get a DrawingArea from the plot. The function renderableToWindow :: Renderable a -> Int -> Int -> IO () does not return anything (and furthermore it does not return before the window is closed).
I would like to do something like the following:
main = do
drawingArea = forkRenderableToWindow (toRenderable $ plotLayout $
plot [0,0.1..10] sin "sin(x)") 640 480
updateCanvas (toRenderable $ plotLayout $ plot [0,0.1..10] sin "sin(x)") drawingArea
How should I do this? Would I need to reimplement the functions in Graphics.Rendering.Chart.Gtk with a version that returns the DrawingArea and in some way (how would I do this? forkIO?) returns immediately without closing the window?
You are looking for createRenderableWindow and then you need to use the GTK operations to work on the given Window - I don't think the Chart package exports any higher level operations on Windows.
EDIT2: So ignore the below - it doesn't work even with GUI initilization. My comment was a guess based on types.
EDIT:
Here is some example code. Understand, I'm just piecing things together based on the types. There might be better ways to do things if you ask someone who actually knows the library.
Below we use:
createRenderableWindow - this was the crux of my answer
castToDrawingArea - This is needed to get a DrawingArea from the Window type provided by GTK. These casts are taking place of C++ OO inheritance, I think.
widgetShowAll - because we haven't actually displayed the window, we best do that. I stole this function after looking at the source for renderableToWindow.
updateCanvas - I just saw this in the haddock documentation and figured it is why you wanted a DrawingArea in the first place.
Now for the code:
import Graphics.Rendering.Chart.Gtk
import Graphics.Rendering.Chart.Renderable
import Graphics.UI.Gtk.Misc.DrawingArea
import qualified Graphics.UI.Gtk as G
main = do
win <- createRenderableWindow emptyRenderable 400 400
let draw = castToDrawingArea win
G.widgetShowAll win
updateCanvas emptyRenderable draw

Resources