#3 Image processing using wxHaskell

Next Release
open
nobody
5
2013-10-09
2009-06-09
Daniel Mundra
No

I liked wxHaskell, its quite useful for a lot of stuff. I wanted to use the getPixelArray to read in an image and then run a function on pixels to affect it and create a new image. The below examples blurs the image.

{-----------------------------------------------------------------------------------------
Author: Daniel M

Description: Uses wxhaskell a gui widget program written in haskell. This program
takes in an image and calls a function on its pixels and then creates a new image.
We get the pixels in the form of an array

wxHaskell: http://haskell.org/haskellwiki/WxHaskell
-----------------------------------------------------------------------------------------}
module Main where

import Graphics.UI.WX
import Graphics.UI.WXCore
import System
import Array
import Text.Regex.Posix

-- Needs 'start' to run the gui and handles for images
main :: IO ()
main = do
args <- getArgs
let fname = head args
start $ imageViewer fname

-- Loads a image and transforms the pixels using changeImg
-- Creates a new image chg_test.jpg with the changed pixels
imageViewer fname
= do
f <- frame [text := "Working!"]
let img = image fname
arr <- loadImageArr img
w <- imageGetWidth img
h <- imageGetHeight img
let newArr = changeImgArr arr w h
newImg <- imageCreateFromPixelArray newArr
imageSaveFile newImg ("chg_" ++ fname) 1
let msg = "Done!"
print msg
close f

-- Returns a Array of pixels as (Point,Color)
loadImageArr img
= do
arr <- imageGetPixelArray img
return arr

-- Takes a array of pixels and width, height of an image
-- and a creates a new array where pixel color has been affected
-- to blur the image. The code will ignore all the edge pixels.
changeImgArr arr w h = array b ([( point x y, arr!(point x y) ) | x <- [0..w-1], y <- [0..h-1], x==0 || y==0] ++
[( point x y, recChgImg arr x y ) | x <- [1..w-2], y <- [1..h-2]] ++
[( point x y, arr!(point x y) ) | x <- [0..w-1], y <- [0..h-1], x==(w-1) || y==(h-1)])
where
b = bounds arr

-- Gets the color of current pixel and its neighbors (up,down,left,right)
-- Algorithm:
-- newX = (Xi,j + Xi-1,j + Xi+1,j + Xi,j-1 + Xi,j+1) / 5
recChgImg arr x y = newCol
where
col = arr!(point x y)
colUp = arr!(point (x-1) y)
colDown = arr!(point (x+1) y)
colLeft = arr!(point x (y-1))
colRight = arr!(point x (y+1))
newColR = (colorRed col + colorRed colUp + colorRed colDown + colorRed colLeft + colorRed colRight) `div` 5
newColG = (colorGreen col + colorGreen colUp + colorGreen colDown + colorGreen colLeft + colorGreen colRight) `div` 5
newColB = (colorBlue col + colorBlue colUp + colorBlue colDown + colorBlue colLeft + colorBlue colRight) `div` 5
newCol = rgb newColR newColG newColB

The above program works but it is quite slow for big images. You can see I have to call colorRed, colorBlue, ... for each pixel to get the color value. I think that's where it is really slow because it is calling that function so many times. I wonder maybe for the next version whether having a Color constructor would be useful to pattern match on. I am new to haskell and wxHaskell was the few libraries that actually can give me pixel values.

Thanks
Daniel

Discussion