diff --git a/CVExample.hs b/CVExample.hs
new file mode 100644
--- /dev/null
+++ b/CVExample.hs
@@ -0,0 +1,263 @@
+{-#LANGUAGE TypeFamilies, MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances
+, FlexibleContexts, FunctionalDependencies, ScopedTypeVariables, DoRec,
+UndecidableInstances#-}
+module Main where
+
+import Graphics.UI.WX
+import Graphics.Tools.WX
+import Graphics.Tools.CV2WX
+import CV.Image as CV
+import CV.Filters
+import CV.Edges
+import CV.ColourUtils
+import CV.Corners
+import CV.HoughTransform hiding (start)
+import CV.DFT
+import CV.Operations hiding (set)
+import qualified CV.Operations as Op
+import CV.ImageMath as IM
+import CV.ImageMathOp
+import CV.Iterators
+import CV.Histogram
+
+import Data.IORef
+import Control.Applicative
+
+triangleImage :: IO (CV.Image CV.GrayScale CV.D32)
+triangleImage = CV.readFromFile "triangle_1.png"
+
+triangleImage8 :: IO (CV.Image CV.GrayScale CV.D8)
+triangleImage8 = CV.readFromFile "triangle_1.png"
+
+triangleImageColor :: IO (CV.Image CV.RGB CV.D8)
+triangleImageColor = CV.readFromFile "triangle_1.png"
+
+rectangleImage :: IO (CV.Image CV.GrayScale CV.D32)
+rectangleImage = CV.readFromFile "rectangle_5.png"
+
+smallLenaImage :: IO (CV.Image CV.GrayScale CV.D32)
+smallLenaImage = CV.readFromFile "smallLena.jpg"
+
+smallLenaImage8 :: IO (CV.Image CV.GrayScale CV.D8)
+smallLenaImage8 = CV.readFromFile "smallLena.jpg"
+
+smallLenaImageColor :: IO (CV.Image CV.RGB CV.D32)
+smallLenaImageColor = CV.readFromFile "smallLena.jpg"
+
+main :: IO ()
+main = do
+  --i <- smallLenaImage
+  --i <- smallLenaImage
+  --i <- smallLenaImageColor
+  --i <- smallLenaImage8
+  i <- triangleImage8
+  start (buildGUI i (Label "i" 25,Label "j" 75,(OneOf [3,5,7] 1)) f)
+  where
+    --f (i::Int,j::Int,t::OneOf) img = stretch_experiment img (selectOne t) i j
+    --f (i::Int,j::Int,t::OneOf) img = dft_experiment img i
+    --f (i::Int,j::Int,t::OneOf) img = rgb_experiment img i
+    --f (i::Int,j::Int,t::OneOf) img = canny_experiment img i j $ selectOne t
+    f (Label _ (i::Int),Label "j" (j::Int),t::OneOf) img = hough_experiment img i j
+
+stretch_experiment img t i j =
+  stretchHistogram $ (img #+) . unsafeImageTo32F . IM.lessThan (fromIntegral t/100) $
+      ((iterate (gaussian (3,3)) img) !! i) #- ((iterate (gaussian (3,3)) img) !! j)
+
+dft_experiment i v =
+  [ PB $ polarDFT i,
+    PB $ thresholdMag t $ polarDFT i,
+    PB $ mapPair logNormalize $ maskMag t $ dftToPolar $ dft i,
+    PB $ filterPolar (maskMag t) i ]
+  where
+    t = (fromIntegral v / 100)
+
+rgb_experiment i v =
+  [ PB $ i,
+    PB $ histStatRgb $ rgbSplit i,
+    PB $ maskR s $ rgbSplit i,
+    PB $ filterRgb (maskR s) i ]
+  where
+    s = (fromIntegral v / 100)
+
+canny_experiment :: Image GrayScale D8 -> Int -> Int -> Int -> [PaintableBox]
+canny_experiment i v1 v2 a =
+  [ PB $ (i32, stat i32, hist i32),
+    PB $ IM.lessThan t1 $ i32,
+    PB $ IM.lessThan t2 $ i32,
+    PB $ canny (round t1 * 255) (round t2 * 255) a i]
+  where
+    i32 = unsafeImageTo32F i
+    t1 = (fromIntegral v1 / 100)
+    t2 = (fromIntegral v2 / 100)
+
+hough_experiment i a b =
+  imageHoughLinesProbabilistic 100 rho1pix theta1deg (fromIntegral a) (fromIntegral b) 10 $
+  canny 64 192 5 i
+
+scharrXEdges = sobel (1,0) sScharr
+
+defaultHarrisResponse = harris 2 3 0.04
+
+strongHarris = harrisCorners 0.4
+
+probabilisticHough = (imageHoughLinesProbabilistic 100 rho1pix theta1deg 20 10 10) . (canny 64 192 5)
+
+mapPair f (a,b) = (f a, f b)
+mapTriple f (a,b,c) = (f a, f b, f c)
+
+dftRound = idft . dft
+
+cartesianDFT i = mapPair logNormalize (dftSplit $ dft i)
+
+polarDFT i = mapPair logNormalize (dftToPolar $ dft i)
+
+polarRound = idft . dftFromPolar . dftToPolar . dft
+
+zeroPhase (mag,ang) = (mag,(clear ang))
+
+setPhase v (mag,ang) = (mag,(Op.set v ang))
+
+setMag v (mag,ang) = ((Op.set v mag),ang)
+
+threshold t = gaussian (5,5) . CV.unsafeImageTo32F . IM.lessThan t
+
+thresholdMag t (mag,ang) = (threshold t mag, ang)
+
+maskMag t (mag,ang) = (mul (threshold t $ logNormalize mag) mag, ang)
+
+filterPolar f = idft . dftFromPolar . f . dftToPolar . dft
+
+filterRgb f = rgbMerge . f . rgbSplit
+
+hist i = simpleGetHistogram i Nothing 0 1 100 False
+
+histRgb (r,g,b) = ((r, hist r), (g, hist g), (b, hist b))
+
+stat :: CV.Image CV.GrayScale CV.D32 -> (Float,Float)
+stat i = (a,s)
+  where ((a,_,_,_),(s,_,_,_)) = imageAvgSdv i
+
+histStatRgb (r,g,b) = ((r, stat r, hist r), (g, stat g, hist g), (b, stat b, hist b))
+
+maskR s (r,g,b) = (subS r s, g, b)
+
+class Tangible a where
+   data Representation a :: *
+   type GUI a :: *
+   present :: a -> (a -> IO ()) -> Window b -> IO (Representation a)
+   acquire :: Representation a -> GUI a
+   getValue :: Representation a -> IO a
+
+data Labeled a = Label String a deriving (Eq,Ord,Show)
+
+instance (Tangible a, Widget (GUI a), Tangible b, Widget (GUI b))
+         => Tangible (a,b) where
+   data Representation (a,b) = RPair (Panel ()) (Representation a) (Representation b)
+   type GUI (a,b) = Panel ()
+   acquire (RPair panel _ _) = panel
+   getValue (RPair _ a b) = (,) <$> getValue a <*> getValue b
+   present (a,b) act parent = do
+                           p <- panel parent []
+                           rec
+                              aw <- present a act1 p
+                              bw <- present b act2 p
+                              let act1 x = do
+                                         v <-getValue bw
+                                         act (x,v)
+                                  act2 x = do
+                                         v<-getValue aw
+                                         act (v,x)
+                           set p [layout := column 2 [hfill $ widget (acquire aw)
+                                                     ,hfill $ widget (acquire bw)]]
+                           return $ RPair p aw bw
+
+instance (Tangible a, Widget (GUI a))
+         => Tangible (Labeled a) where
+   type GUI (Labeled a) = Panel ()
+   data Representation (Labeled a) = LabelRep String (Panel ()) (Representation a)
+   acquire (LabelRep s p a) = p
+   getValue (LabelRep s p a) = Label s <$> (getValue a)
+   present (Label s a) e p = do
+                  pnl <- panel p []
+                  ctext <- staticText pnl [ text := s ]
+                  el <- present a (\a -> e (Label s a)) pnl
+                  set pnl [layout := column 2 [hfill $ widget ctext
+                                              ,hfill $ widget (acquire el)]]
+                  return $ LabelRep s pnl el
+
+
+instance (Tangible a, Tangible b, Tangible c,Widget (GUI a), Widget (GUI b), Widget (GUI c))
+         => Tangible (a,b,c) where
+   type GUI (a,b,c) = GUI (a,(b,c))
+   data Representation (a,b,c) = RTriple (Representation (a,(b,c)))
+   acquire (RTriple a) = acquire a
+   getValue (RTriple a) = getValue a >>= \(a,(b,c)) -> return (a,b,c)
+   present (a,b,c) e p = RTriple <$> present (a,(b,c)) (\(a,(b,c))-> e (a,b,c)) p
+
+instance (Tangible a, Widget (GUI a)) => Tangible [a] where
+   type GUI [a] = Panel ()
+   data Representation [a] = RList (Panel ()) [Representation a]
+   acquire (RList p _) = p
+   getValue (RList _ r) = mapM getValue r
+   present xs act parent = do
+               p <- panel parent []
+               rec
+                  let act' _ = mapM getValue reps >>= act
+                  reps <- mapM (\a -> present a act' p) xs
+               set p [layout := column 2 (map (hfill.widget.acquire) reps)]
+               return $ RList p reps
+
+instance Tangible Int where
+  data Representation Int = RInt (Slider ())
+  type GUI Int = Slider ()
+  acquire (RInt s) = s
+  getValue (RInt s) = get s selection
+  present i act parent = do
+    s <- hslider parent True 1 100 [selection := i]
+    set s [on command := get s selection >>= act]
+    return (RInt s)
+
+data OneOf = OneOf{ choices :: [Int], index :: Int }
+
+selectOne :: OneOf -> Int
+selectOne (OneOf xs i)
+  | i >= 0 && i < length xs = xs !! i
+  | otherwise = 0
+
+instance Tangible OneOf where
+  type GUI OneOf = RadioBox ()
+  data Representation OneOf = ROneOf (RadioBox ()) [Int] Int
+  acquire (ROneOf b _ _) = b
+  getValue (ROneOf b as _) = do
+    i <- get b selection
+    return $ (OneOf as i)
+  present (OneOf as i) act parent = do
+    b <- radioBox parent Horizontal (map show as) [selection := i]
+    set b [on select := getValue (ROneOf b as i) >>= act]
+    return $ ROneOf b as i
+
+paintSurface p dc viewArea = doPaint dc (point 0 0) p
+
+createSurface f p =
+  panel f [ on paint := paintSurface p, outerSize := paintSize p ]
+
+updateSurface s p = do
+  set s [ on paint := paintSurface p, outerSize := paintSize p ]
+  repaint s
+
+buildGUI :: (Tangible a, Widget (GUI a), WxPaintable p)
+            => Image c d -> a ->
+               (a -> Image c d -> p) -> IO ()
+buildGUI i tv function = do
+  f <- frame [ text := "FilterVictor" ]
+  s <- createSurface f (function tv i)
+
+  let update tv' = updateSurface s (function tv' i)
+
+  controls <- panel f []
+  ctext <- staticText controls [ text := "Controls" ]
+  c :: b <- acquire <$> present tv update controls
+  set controls [layout := margin 5 (column 2 [widget ctext, hfill $ widget c])]
+
+  set f [ layout := margin 10 $ column 10 [row 10 [widget s,widget controls]]]
+  return ()
diff --git a/Graphics/Tools/Bindings/Convert.hsc b/Graphics/Tools/Bindings/Convert.hsc
new file mode 100644
--- /dev/null
+++ b/Graphics/Tools/Bindings/Convert.hsc
@@ -0,0 +1,17 @@
+#include <bindings.dsl.h>
+#include "convert.h"
+
+module Graphics.Tools.Bindings.Convert (
+  c'cpy_ipl_d8_gray_to_d8_rgb
+, c'cpy_ipl_f32_gray_to_d8_rgb
+, c'cpy_ipl_d8_rgb_to_d8_rgb
+, c'cpy_ipl_f32_rgb_to_d8_rgb
+) where
+
+import Foreign.Ptr
+import CV.Image(BareImage)
+
+#ccall cpy_ipl_d8_gray_to_d8_rgb  , Ptr BareImage -> Ptr () -> IO ()
+#ccall cpy_ipl_f32_gray_to_d8_rgb , Ptr BareImage -> Ptr () -> IO ()
+#ccall cpy_ipl_d8_rgb_to_d8_rgb   , Ptr BareImage -> Ptr () -> IO ()
+#ccall cpy_ipl_f32_rgb_to_d8_rgb  , Ptr BareImage -> Ptr () -> IO ()
diff --git a/Graphics/Tools/CV2WX.hs b/Graphics/Tools/CV2WX.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Tools/CV2WX.hs
@@ -0,0 +1,201 @@
+{-#LANGUAGE ScopedTypeVariables, FlexibleInstances, FlexibleContexts,
+   UndecidableInstances, TypeSynonymInstances, OverlappingInstances,
+   TypeOperators#-}
+
+module Graphics.Tools.CV2WX (
+  WxImage(..), WxPaintable(..)
+) where
+
+import Graphics.UI.WXCore.Types
+import Graphics.UI.WXCore.Image
+import Graphics.UI.WX
+import Graphics.Tools.WX
+import Graphics.Tools.Bindings.Convert
+import CV.Image
+import CV.Operations hiding (set)
+import CV.Corners
+import CV.HoughTransform hiding (start, Line)
+import qualified CV.HoughTransform as HT
+import CV.DFT
+import Data.List(genericLength)
+
+instance WxImage (Image GrayScale D8) where
+  toImage i = cvToWx i c'cpy_ipl_d8_gray_to_d8_rgb
+  toSize i = do return $ sz w h
+    where (w,h) = getSize i
+
+instance WxImage (Image GrayScale D32) where
+  toImage i = cvToWx (unitNormalize i) c'cpy_ipl_f32_gray_to_d8_rgb
+  toSize i = do return $ sz w h
+    where (w,h) = getSize i
+
+instance WxImage (Image DFT D32) where
+  toImage i = cvToWx (logNormalize mag) c'cpy_ipl_f32_gray_to_d8_rgb
+    where
+      (mag,ang) = dftToPolar i
+  toSize i = do return $ sz w h
+    where
+      (w,h) = getSize i
+
+instance WxImage (Image RGB D8) where
+  toImage i = cvToWx i c'cpy_ipl_d8_rgb_to_d8_rgb
+  toSize i = do return $ sz w h
+    where (w,h) = getSize i
+
+instance WxImage (Image RGB D32) where
+  toImage i = cvToWx i c'cpy_ipl_f32_rgb_to_d8_rgb
+  toSize i = do return $ sz w h
+    where (w,h) = getSize i
+
+cvToWx img cpy = do
+    pb <- pixelBufferCreate (sz w h)
+    i <- imageCreateFromPixelBuffer pb
+    withImage img $ \cimg -> do
+      withImageData i $ cpy cimg
+    return i
+  where
+    (w,h) = getSize img
+
+instance (WxImage (Image c d)) => WxPaintable (Image c d) where
+  doPaint dc p i = do
+    img <- toImage $ i
+    drawImage dc img p []
+  paintSize i = sz w h
+    where (w,h) = getSize i
+
+instance (WxPaintable a, WxPaintable b) => WxPaintable (a, b) where
+  doPaint dc p (p1,p2) = do
+    doPaint dc p p1
+    doPaint dc np p2
+    where
+      (Size w _) = paintSize p1
+      np = (pointAdd p (point w 0))
+  paintSize (i1,i2) =
+    sz (w1+w2) (max h1 h2)
+    where
+      (Size w1 h1) = paintSize i1
+      (Size w2 h2) = paintSize i2
+
+instance (WxPaintable a, WxPaintable b, WxPaintable c) => WxPaintable (a,b,c) where
+  doPaint dc p (p1,p2,p3) = do
+    doPaint dc p p1
+    doPaint dc np1 p2
+    doPaint dc np2 p3
+    where
+      (Size w1 _) = paintSize p1
+      (Size w2 _) = paintSize p2
+      np1 = (pointAdd p (point w1 0))
+      np2 = (pointAdd np1 (point w2 0))
+  paintSize (i1,i2,i3) =
+    sz (w1+w2+w3) (maximum [h1,h2,h3])
+    where
+      (Size w1 h1) = paintSize i1
+      (Size w2 h2) = paintSize i2
+      (Size w3 h3) = paintSize i3
+
+instance WxPaintable [PaintableBox] where
+  doPaint dc p [] = return ()
+  doPaint dc p (b:bs) = do
+    doPaint dc p b
+    doPaint dc np bs
+    where
+      (Size _ h) = paintSize b
+      np = pointAdd p (point 0 h)
+  paintSize bs =
+    sz (maximum $ map (sizeW . paintSize) bs)  (sum $ map (sizeH . paintSize) bs)
+
+-- starting point
+-- area width
+-- area height
+-- points
+listToPoints :: Point -> Int -> Int -> [Float] -> [Point]
+listToPoints (Point x y) w h ps =
+  [ Point (x + (round i)) (y - (round j)) | (i,j) <- zip (map (* inc) [0..genericLength ps - 1]) (map (* scale) ps) ]
+  where
+        inc :: Float = (fromIntegral w) / (fromIntegral (length ps))
+        scale :: Float = (fromIntegral h) / (maximum ps)
+
+instance (WxPaintable (Image c d)) => WxPaintable ((Image c d), [Float]) where
+  doPaint dc p@(Point x y) (i,hs) = do
+    doPaint dc p i
+    set dc [penColor := red, brushColor := yellow, brushKind := BrushSolid]
+    polygon dc (listToPoints hp hw hh (concat [[0],hs,[0]])) []
+    where
+      (Size w h) = paintSize i
+      hw = round $ (fromIntegral w) * 0.9
+      dx = round $ (fromIntegral (w - hw)) / 2
+      hh = round $ (fromIntegral h) * 0.3
+      dy = 5
+      hx = (x + dx)
+      hy = (y + h - dy)
+      hp = (Point hx hy)
+  paintSize (i,h) = paintSize i
+
+instance (WxPaintable (Image c d)) => WxPaintable ((Image c d), (Float,Float), [Float]) where
+  doPaint dc p@(Point x y) (i,(a,s),hs) = do
+    doPaint dc p i
+    set dc [penColor := red, brushColor := yellow, brushKind := BrushSolid]
+    polygon dc (listToPoints hp hw hh (concat [[0],hs,[0]])) []
+    line dc (point ax (hy + ds)) (point ax (hy - hh - ds)) []
+    line dc (point sx (hy + ds)) (point (sx + sw) (hy + ds)) []
+    where
+      (Size w h) = paintSize i
+      hw = round $ (fromIntegral w) * 0.9
+      dx = round $ (fromIntegral (w - hw)) / 2
+      hh = round $ (fromIntegral h) * 0.3
+      dy = 5
+      hx = (x + dx)
+      hy = (y + h - dy)
+      hp = (Point hx hy)
+      ax = hx + (round $ a * (fromIntegral hw))
+      sx = ax - (round $ s * (fromIntegral hw))
+      sw = round $ 2 * s * (fromIntegral hw)
+      ds = 3
+  paintSize (i,s,h) = paintSize i
+
+instance WxColor HarrisDesc where
+  toColor d = colorRGB i i i
+    where i = round $ 255 * d
+
+instance WxColor HoughDesc where
+  toColor d = red
+
+instance (WxColor a) => WxPaintable (Corner a) where
+  doPaint dc p (Corner (x,y) d) = do
+    set dc [penColor := black, brushColor := toColor d]
+    drawRect dc (rect (point (x-5) (y-5)) (sz 10 10)) []
+
+instance WxPaintable HT.Segment where
+  doPaint dc p (HT.Segment (x1,y1) (x2,y2)) = do
+    set dc [penColor := red]
+    circle dc (point x1 y1) 5 []
+    circle dc (point x2 y2) 5 []
+    line dc (point x1 y1) (point x2 y2) []
+
+instance (WxColor a) => WxPaintable (ImageWithCorners a) where
+  doPaint dc p (ImageWithCorners i c) = do
+    doPaint dc p i
+    mapM_ (doPaint dc p) $ c
+  paintSize (ImageWithCorners i _) = sz w h
+    where (w,h) = getSize i
+
+instance (WxPaintable a, WxPaintable b) => WxPaintable (a `With` b) where
+  doPaint dc p (i `With` c) = do
+    doPaint dc p i
+    doPaint dc p $ c
+  paintSize (i `With` _) = paintSize i
+
+
+instance WxPaintable (HT.ImageWithLines) where
+  doPaint dc p (i `With` l) = do
+    doPaint dc p i
+    mapM_ (doPaint dc p) $ map (HT.lineToSegment (getSize i)) l
+  paintSize (i `With` l) = sz w h
+    where (w,h) = getSize i
+
+instance WxPaintable (HT.ImageWithSegments) where
+  doPaint dc p (i `With` l) = do
+    doPaint dc p i
+    mapM_ (doPaint dc p) $ l
+  paintSize (i `With` l) = sz w h
+    where (w,h) = getSize i
diff --git a/Graphics/Tools/WX.hs b/Graphics/Tools/WX.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Tools/WX.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE ExistentialQuantification #-}
+module Graphics.Tools.WX where
+
+import Graphics.UI.WXCore.Image
+import Graphics.UI.WXCore.WxcTypes
+import Graphics.UI.WXCore.WxcDefs
+import Graphics.UI.WXCore.WxcClasses
+import Graphics.UI.WXCore.Types
+import Graphics.UI.WXCore.Defines
+
+class WxPaintable p where
+  doPaint :: DC a -> Point -> p -> IO ()
+  paintSize :: p -> Size
+  paintSize x = sz 0 0
+
+data PaintableBox = forall a . WxPaintable a => PB a
+
+instance WxPaintable PaintableBox where
+  doPaint dc p (PB b) = doPaint dc p b
+  paintSize (PB b) = paintSize b
+
+class WxColor c where
+  toColor :: c -> Color
+
+class WxImage i where
+  toSize :: i -> IO (Size)
+  toImage :: i -> IO (Image ())
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2012, Matti J. Eskelinen
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of the copyright holder nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,19 @@
+GraphicsTools v.0.1
+
+Tools for creating graphical UIs, based on wxHaskell.
+
+This library provides interfaces for creating easily graphical UIs
+especially for computer vision purposes, and for rendering information in
+graphical form. Implementations are provided for CV and CVSU libraries.
+Example applications are included.
+
+Installation:
+
+cabal-dev is recommended for experimenting with this library.
+
+At the moment you need to get hs-cvsu from yousource.
+
+git clone git@yousource.it.jyu.fi:hs-cvsu/hs-cvsu.git
+cd graphicstools
+cabal-dev add-source ../hs-cvsu
+cabal-dev install
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/c/convert.c b/c/convert.c
new file mode 100644
--- /dev/null
+++ b/c/convert.c
@@ -0,0 +1,148 @@
+#include <stdint.h>
+#include <string.h>
+#include "convert.h"
+
+void cpy_ipl_d8_gray_to_d8_rgb(IplImage *src, void *dst)
+{
+    uint8_t *src_data, *dst_data, value;
+    src_data = (uint8_t *)src->imageData;
+    dst_data = (uint8_t *)dst;
+
+    if (src->width == src->widthStep) {
+        PRINT("D8 Gray Continuous\n");
+        unsigned int i, size, pos;
+        size = src->width * src->height;
+        for (i = size, pos = (size - 1) * 3; i--; pos -= 3) {
+            value = src_data[i];
+            dst_data[pos] = dst_data[pos + 1] = dst_data[pos + 2] = value;
+        }
+    }
+    else {
+        PRINT("D8 Gray Discontinuous\n");
+        unsigned int x, y, width, height, stride, data_pos, pos;
+        width = src->width;
+        height = src->height;
+        stride = src->widthStep;
+        for (y = 0; y < height; y++) {
+            data_pos = y * stride;
+            pos = y * width * 3;
+            for (x = 0; x < width; x++, data_pos++, pos += 3) {
+                value = src_data[data_pos];
+                dst_data[pos] = dst_data[pos + 1] = dst_data[pos + 2] = value;
+            }
+        }
+    }
+}
+
+void cpy_ipl_f32_gray_to_d8_rgb(IplImage *src, void *dst)
+{
+    float *src_data;
+    unsigned int src_width, src_height, src_stride;
+    uint8_t *dst_data, value;
+
+    src_data = (float *)src->imageData;
+    src_width =  src->width;
+    src_height = src->height;
+    src_stride = src->widthStep / sizeof(float);
+    dst_data = (uint8_t *)dst;
+
+    if (src_width == src_stride) {
+        PRINT("D32 Gray Continuous\n");
+        unsigned int size, src_pos, dst_pos;
+
+        size = src_width * src_height;
+        dst_pos = (size - 1) * 3;
+        for (src_pos = size; src_pos--; dst_pos -= 3) {
+            value = (uint8_t)(255 * src_data[src_pos]);
+            dst_data[dst_pos] = dst_data[dst_pos + 1] = dst_data[dst_pos + 2] = value;
+        }
+    }
+    else {
+        PRINT("D32 Gray Discontinuous\n");
+        unsigned int x, y, src_stride, dst_stride, src_pos, dst_pos;
+
+        dst_stride = src_width * 3;
+        for (y = 0; y < src_height; y++) {
+            src_pos = y * src_stride;
+            dst_pos = y * dst_stride;
+            for (x = 0; x < src_width; x++, src_pos++, dst_pos += 3) {
+                value = (uint8_t)(255 * src_data[src_pos]);
+                dst_data[dst_pos] = dst_data[dst_pos + 1] = dst_data[dst_pos + 2] = value;
+            }
+        }
+    }
+}
+
+void cpy_ipl_d8_rgb_to_d8_rgb(IplImage *src, void *dst)
+{
+    uint8_t *src_pos, *dst_pos, r, g, b;
+    src_pos = (uint8_t *)src->imageData;
+    dst_pos = (uint8_t *)dst;
+
+    /* if image is continuous, can memcpy whole buffer */
+    if (src->width * 3 == src->widthStep) {
+        PRINT("D8 RGB Continuous\n");
+        unsigned int size;
+
+        size = src->height * src->width * 3 * sizeof(uint8_t);
+        memcpy(dst_pos, src_pos, size);
+    }
+    /* otherwise, must memcpy one row at a time */
+    else {
+        PRINT("D8 RGB Discontinuous\n");
+        unsigned int size, y, height, src_stride, dst_stride;
+
+        size = src->width * 3 * sizeof(uint8_t);
+        height = src->height;
+        src_stride = src->widthStep;
+        dst_stride = src->width * 3;
+        for (y = 0; y < height; y++, src_pos += src_stride, dst_pos += dst_stride) {
+            memcpy(dst_pos, src_pos, size);
+        }
+    }
+}
+
+void cpy_ipl_f32_rgb_to_d8_rgb(IplImage *src, void *dst)
+{
+    float *src_pos, r, g, b;
+    uint8_t *dst_pos;
+    unsigned int src_stride;
+
+    src_pos = (float *)src->imageData;
+    dst_pos = (uint8_t *)dst;
+    src_stride = src->widthStep / sizeof(float);
+
+    /* if image is continuous, can use a single loop */
+    if (src->width * 3 == src_stride) {
+        PRINT("D32 RGB Continuous\n");
+        unsigned int i, size, pos;
+        size = src->width * src->height;
+        for (i = size, pos = (size - 1) * 3; i--; pos -= 3) {
+            r = src_pos[pos];
+            g = src_pos[pos + 1];
+            b = src_pos[pos + 2];
+            dst_pos[pos]     = (uint8_t)(255 * r);
+            dst_pos[pos + 1] = (uint8_t)(255 * g);
+            dst_pos[pos + 2] = (uint8_t)(255 * b);
+        }
+    }
+    /* otherwise, must go row-wise in two loops */
+    else {
+        PRINT("D32 RGB Discontinuous\n");
+        unsigned int x, y, width, height, data_pos, pos;
+        width = src->width;
+        height = src->height;
+        for (y = 0; y < height; y++) {
+            data_pos = y * src_stride;
+            pos = y * width * 3;
+            for (x = 0; x < width; x++, data_pos += 3, pos += 3) {
+                r = src_pos[data_pos];
+                g = src_pos[data_pos + 1];
+                b = src_pos[data_pos + 2];
+                dst_pos[pos]     = (uint8_t)(255 * r);
+                dst_pos[pos + 1] = (uint8_t)(255 * g);
+                dst_pos[pos + 2] = (uint8_t)(255 * b);
+            }
+        }
+    }
+}
diff --git a/c/convert.h b/c/convert.h
new file mode 100644
--- /dev/null
+++ b/c/convert.h
@@ -0,0 +1,20 @@
+#ifndef __CVCONVERT__
+#define __CVCONVERT__
+
+#include <opencv2/core/core_c.h>
+
+#undef DEBUG_PRINT
+/*#define DEBUG_PRINT*/
+#ifdef DEBUG_PRINT
+#include <stdio.h>
+#define PRINT(s) printf(s)
+#else
+#define PRINT(s)
+#endif
+
+void cpy_ipl_d8_gray_to_d8_rgb(IplImage *src, void *dst);
+void cpy_ipl_f32_gray_to_d8_rgb(IplImage *src, void *dst);
+void cpy_ipl_d8_rgb_to_d8_rgb(IplImage *src, void *dst);
+void cpy_ipl_f32_rgb_to_d8_rgb(IplImage *src, void *dst);
+
+#endif
diff --git a/graphicstools.cabal b/graphicstools.cabal
new file mode 100644
--- /dev/null
+++ b/graphicstools.cabal
@@ -0,0 +1,55 @@
+Name:                graphicstools
+Version:             0.2
+Synopsis:            Tools for creating graphical UIs, based on wxHaskell.
+Description:         This library provides interfaces for creating easily
+                     graphical UIs especially for computer vision purposes,
+                     and for rendering information in graphical form.
+                     Implementations are provided for CV libraries.
+                     Example applications are included.
+                     (This is an early preview version)
+Homepage:            https://yousource.it.jyu.fi/cvlab/pages/GraphicsTools
+License:             BSD3
+License-file:        LICENSE
+Author:              Matti J. Eskelinen & Ville Tirronen
+Maintainer:          matti.j.eskelinen@jyu.fi
+Copyright:
+Category:            Graphics
+Build-type:          Simple
+Extra-source-files:  README
+Cabal-version:       >=1.8
+
+Executable cvexample
+  Main-is:
+    CVExample.hs
+  Build-Depends:
+    base >= 3 && < 5,
+    wxcore >= 0.13.2.0,
+    wx >= 0.12.1.6,
+    CV >= 0.3.4,
+    graphicstools >= 0.1
+
+Library
+  Exposed-modules:
+    Graphics.Tools.WX,
+    Graphics.Tools.CV2WX,
+    Graphics.Tools.Bindings.Convert
+  Extensions:
+    ForeignFunctionInterface
+  Build-Depends:
+    base >= 3 && < 5,
+    bindings-DSL >= 1.0.7 && < 1.1,
+    CV >= 0.3.4,
+    wxcore >= 0.12.1.6,
+    wx >= 0.12.1.6
+  Include-dirs:
+    c
+  Includes:
+    c/convert.h
+  Install-includes:
+    c/convert.h
+  C-sources:
+    c/convert.c
+
+source-repository head
+  type:     git
+  location: git@yousource.it.jyu.fi:cvlab/graphicstools.git
