diff --git a/CV.cabal b/CV.cabal
--- a/CV.cabal
+++ b/CV.cabal
@@ -1,10 +1,11 @@
 Name:				 CV
-Version:             0.3.1.2
+Version:             0.3.4
 Description:         OpenCV Bindings
 License:             GPL
 License-file:        LICENSE
 Category:            AI, Graphics, Machine Vision
 Synopsis:            OpenCV based machine vision library
+Homepage:            http://aleator.github.com/CV/
 Description:         This is a machine vision package that wraps some functionality
                      of OpenCV library. This package has been developed for personal use and
                      is not meant to be a complete wrapper. It also includes some things not
@@ -14,46 +15,69 @@
                      and code clean-up, but is somewhat tested.
                      .
                      (The scarce) Documentation is available at 
-                      <http://users.jyu.fi/~aleator/CV-0.3.0.2/html/index.html>
+                      <http://http://aleator.github.com/CV/>
                      .
                      Changelog.
+                     0.3.4 - Pixelwise operations, bug fixes and additional documentation
+                     .
+                     0.3.3.0 - Improvements, including compatablity with opencv 2.3.1 and removal of
+                     dependency with deprecated JYU.Utils
+                     .
+                     Changelog.
+                     0.3.2.0 - Improvements, including fancier pixel-wise manipulations 
+                     .
+                     Changelog.
                      0.3.0.2 - Workaround for compiling with OS X 10.6 & fixed errors about M_PI
                      .
 
 Author:              Ville Tirronen
 Maintainer:          ville.tirronen@jyu.fi
 Build-Type:          Simple
-Cabal-Version:       >=1.6
+Cabal-Version:       >=1.8
 Extra-Source-Files:
                      examples/*.hs
                      examples/shapes/*.png
                      examples/shapePhoto.jpg
+                     examples/chess.png
                      examples/fuse1.png
                      examples/fuse2.png
                      examples/smallLena.jpg
                      examples/elaine.jpg
+Flag opencv23
+  Description: Compatability for opencv 2.3.1
+  Default:     False
 
+
 Library
     Build-Tools:       c2hs >= 0.16.0
-    Include-dirs:      CV/  
-    Includes:          opencv/cv.h, opencv/cxcore.h, opencv/highgui.h, CV/cvWrapLEO.h
-    c-sources:         CV/cvWrapLEO.c
-    install-includes:  CV/cvWrapLEO.h
+    Include-dirs:      cbits/  
+    Includes:          opencv/cv.h, opencv/cxcore.h, opencv/highgui.h, cbits/cvWrapLEO.h
+    c-sources:         cbits/cvWrapLEO.c
+    install-includes:  cbits/cvWrapLEO.h
+    if flag(opencv23)
+         cpp-options: -DOpenCV23
+         cc-options: -DOpenCV23
     cc-options:        --std=c99 -U__BLOCKS__
     extra-libraries:   opencv_calib3d,opencv_contrib,opencv_core,opencv_features2d,opencv_highgui,opencv_imgproc,opencv_legacy,opencv_ml,opencv_objdetect,opencv_video
      
-    Build-Depends:     haskell98, base >= 3 && < 5, parallel > 1.1, unix > 2.3, array >= 0.2.0.0,
+    Build-Depends:     haskell98, base >= 3 && < 5, parallel > 3.1, unix > 2.3, array >= 0.2.0.0,
                        mtl >= 1.1.0, random >= 1.0.0, carray >= 0.1.5, QuickCheck >= 2.1, 
-                       containers >= 0.2, JYU-Utils >= 0.1 && < 0.2,
-                       storable-complex, binary >= 0.5, deepseq >= 1.1
+                       containers >= 0.2, 
+                       storable-complex, binary >= 0.5, deepseq >= 1.1,
+                       bindings-DSL >= 1.0.14 && < 1.1, vector >= 0.7.0.1 && < 1.1,
+                       lazysmallcheck >= 0.5 && < 1
     Exposed-modules:   CV.Image, CV.ImageOp, CV.ImageMath CV.Sampling, CV.Edges, CV.Filters, 
                        CV.Morphology, CV.ColourUtils, CV.ImageMathOp, CV.Video,
                        CV.Textures,CV.Drawing, CV.Thresholding, CV.Histogram,  CV.LightBalance,
                        CV.TemplateMatching, CV.Transforms, CV.Conversions,
                        CV.Binary, CV.Marking, CV.FunnyStatistics,
                        CV.MultiresolutionSpline,  CV.Gabor,
-                       CV.ConnectedComponents, CV.HighGUI
-    Other-modules:     C2HSTools, C2HS
+                       CV.ConnectedComponents, CV.HighGUI, CV.Calibration
+                       CV.Pixelwise, CV.Matrix, CV.Arbitrary
+                       Utils.List, Utils.Point, Utils.Rectangle, Utils.Stream, Utils.Function
+    Other-modules:     C2HSTools, C2HS, CV.Bindings.Matrix, CV.Bindings.Calibrate
+    Extensions: CPP
+
 
 source-repository head
   type:     git
diff --git a/CV/Arbitrary.hs b/CV/Arbitrary.hs
new file mode 100644
--- /dev/null
+++ b/CV/Arbitrary.hs
@@ -0,0 +1,42 @@
+-- | This module provides QuickCheck generators for images.
+module CV.Arbitrary (smallImage,constImage, noisyImage,smoothImage,blockNoise) where
+
+import Control.Applicative 
+import CV.Image
+import CV.Pixelwise
+import CV.Filters
+import Test.QuickCheck
+import Test.QuickCheck.Gen
+import Control.Monad
+
+newtype ZeroOne = ZO {unZo :: Float}
+instance Arbitrary ZeroOne where
+    arbitrary = ZO <$> choose (0,1)
+
+-- | Generate a random small image, that might be constant, noisy or smoothly varying
+--   Range of values is [0,1]
+smallImage :: Gen (Image GrayScale D32)
+smallImage = oneof [constImage, noisyImage,smoothImage]
+
+-- | Generate 10x10 constant image
+constImage :: Gen (Image GrayScale D32)
+constImage = do
+              ZO f <- arbitrary
+              return $ toImage $ MkP {sizeOf = (10,10), eltOf = const f} 
+
+-- | Generate 10x10 noisy image
+noisyImage :: Gen (Image GrayScale D32)
+noisyImage = do
+              f <- arbitrary
+              return $ toImage $ MkP {sizeOf = (10,10), eltOf = unZo . f} 
+
+-- | Generate 10x10 smoothly varying image
+smoothImage :: Gen (Image GrayScale D32)
+smoothImage = gaussian (5,5) <$> noisyImage
+
+blockNoise1  = montage (2,2) 0 <$> replicateM 4 smallImage
+
+-- | Generate a (10m x 10m) sized noisy image.
+blockNoise :: Int -> Gen (Image GrayScale D32)
+blockNoise m = montage (m,m) 0 . replicate (m*m) <$> blockNoise1
+
diff --git a/CV/Bindings/Calibrate.hsc b/CV/Bindings/Calibrate.hsc
new file mode 100644
--- /dev/null
+++ b/CV/Bindings/Calibrate.hsc
@@ -0,0 +1,53 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+#include <bindings.dsl.h>
+#include "cvWrapLEO.h"
+
+module CV.Bindings.Calibrate where
+import Data.Word
+import Foreign.C.Types
+import CV.Bindings.Matrix
+import CV.Image
+
+#strict_import
+
+-- typedef struct
+-- {
+--     int width;
+--     int height;
+-- }
+-- CvSize;
+
+#starttype CvSize
+#field width , CInt
+#field height , CInt
+#stoptype
+
+#starttype CvPoint2D32f
+#field x , Float
+#field y , Float
+#stoptype
+
+ 
+#ccall wrapCalibrateCamera2 , Ptr <CvMat> -> Ptr <CvMat> -> Ptr <CvMat> -> Ptr <CvSize> -> Ptr <CvMat> -> Ptr <CvMat> -> Ptr <CvMat> ->  Ptr <CvMat> -> CInt -> IO Double
+
+#ccall wrapFindCornerSubPix , Ptr BareImage -> Ptr <CvPoint2D32f> -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Double -> IO ()
+
+#num CV_TERMCRIT_ITER
+#num CV_TERMCRIT_EPS
+
+
+#num CV_CALIB_USE_INTRINSIC_GUESS  
+#num CV_CALIB_FIX_ASPECT_RATIO     
+#num CV_CALIB_FIX_PRINCIPAL_POINT  
+#num CV_CALIB_ZERO_TANGENT_DIST    
+#num CV_CALIB_FIX_FOCAL_LENGTH 
+#num CV_CALIB_FIX_K1  
+#num CV_CALIB_FIX_K2  
+#num CV_CALIB_FIX_K3  
+#num CV_CALIB_FIX_K4  
+#num CV_CALIB_FIX_K5  
+#num CV_CALIB_FIX_K6  
+#num CV_CALIB_RATIONAL_MODEL 
+
+
diff --git a/CV/Bindings/Matrix.hsc b/CV/Bindings/Matrix.hsc
new file mode 100644
--- /dev/null
+++ b/CV/Bindings/Matrix.hsc
@@ -0,0 +1,90 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+#include <bindings.dsl.h>
+#include "cvWrapLEO.h"
+
+module CV.Bindings.Matrix where
+import Data.Word
+import Foreign.C.Types
+
+#strict_import
+
+#starttype CvMat
+#field type , CInt 
+#field step , CInt
+#field refcount , Ptr CInt 
+#union_field data.ptr , Ptr CUChar 
+#union_field data.s   , Ptr CShort 
+#union_field data.i   , Ptr CInt 
+#union_field data.fl  , Ptr CFloat 
+#union_field data.db  , Ptr CDouble 
+#field rows , CInt
+#field cols , CInt
+#stoptype
+
+#ccall cvCreateMat  , Int -> Int -> Int -> IO (Ptr <CvMat>) 
+#ccall cvReleaseMat , Ptr (Ptr <CvMat>) -> IO ()
+
+#ccall cvTranspose  , Ptr <CvMat> -> Ptr <CvMat> -> IO ()
+#ccall cvGEMM       , Ptr <CvMat> -> Ptr <CvMat> -> Double -> Ptr <CvMat> -> Double -> Ptr <CvMat> -> Int -> IO ()
+
+#ccall cvRodrigues2  , Ptr <CvMat> -> Ptr <CvMat> -> Ptr <CvMat> -> IO Int
+
+#num CV_GEMM_A_T
+#num CV_GEMM_B_T
+#num CV_GEMM_C_T
+
+#num CV_8UC1 
+#num CV_8UC2 
+#num CV_8UC3 
+#num CV_8UC4 
+
+#num CV_8SC1 
+#num CV_8SC2 
+#num CV_8SC3 
+#num CV_8SC4 
+
+#num CV_16UC1 
+#num CV_16UC2 
+#num CV_16UC3 
+#num CV_16UC4 
+
+#num CV_16SC1 
+#num CV_16SC2 
+#num CV_16SC3 
+#num CV_16SC4 
+
+#num CV_32SC1 
+#num CV_32SC2 
+#num CV_32SC3 
+#num CV_32SC4 
+
+#num CV_32FC1 
+#num CV_32FC2 
+#num CV_32FC3 
+#num CV_32FC4 
+
+#num CV_64FC1 
+#num CV_64FC2 
+#num CV_64FC3 
+#num CV_64FC4 
+
+
+-- typedef struct CvMat
+-- {
+--     int type;
+--     int step;
+--     int* refcount;
+--     union
+--     {
+--         uchar* ptr;
+--         short* s;
+--         int* i;
+--         float* fl;
+--         double* db;
+--     } data;
+--     int rows;
+--     int cols;
+-- } CvMat;
+
+
diff --git a/CV/Calibration.chs b/CV/Calibration.chs
new file mode 100644
--- /dev/null
+++ b/CV/Calibration.chs
@@ -0,0 +1,173 @@
+{-#LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+#include "cvWrapLEO.h"
+-- | This module exposes opencv functions for camera calibration using a chessboard rig. This module follows opencv quite closely and the best documentation
+--   is probably found there. As quick example however, the following program detects and draws chessboard corners from an image.
+--
+-- @
+-- module Main where
+-- import CV.Image
+-- import CV.Calibration
+-- 
+-- main = do
+--     Just i <- loadColorImage \"chess.png\"
+--     let corners = findChessboardCorners (unsafeImageTo8Bit i) (4,5) (FastCheck:defaultFlags)
+--     let y = drawChessboardCorners (unsafeImageTo8Bit i) (4,5) corners
+--     mapM_ print (corners)
+--     saveImage \"found_chessboard.png\" y
+-- @
+module CV.Calibration 
+    (
+     -- * Finding chessboard calibration rig
+     FindFlags(..)
+    ,defaultFlags
+    ,findChessboardCorners
+    ,refineChessboardCorners
+    -- * Visualization
+    ,drawChessboardCorners
+    -- * Camera calibration
+    ,calibrateCamera2) where
+{-#OPTIONS-GHC -fwarn-unused-imports #-}
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.ForeignPtr
+import Foreign.Storable
+import Foreign.Marshal.Array
+import Foreign.Ptr
+import Data.Bits
+
+import CV.Image 
+
+import C2HSTools
+import Utils.Point
+import Control.Applicative
+
+import CV.Matrix
+import CV.Bindings.Calibrate
+
+{#import CV.Image#}
+
+#c
+enum FindFlags {
+     AdaptiveThresh  = CV_CALIB_CB_ADAPTIVE_THRESH
+    ,NormalizeImage  = CV_CALIB_CB_NORMALIZE_IMAGE
+    ,FilterQuads     = CV_CALIB_CB_FILTER_QUADS
+    ,FastCheck       = CV_CALIB_CB_FAST_CHECK
+    };
+#endc
+
+-- | Flags for the chessboard corner detector. See opencv documentation for cvFindChessboardCorners.
+{#enum FindFlags {}#}
+
+flagsToNum fs = foldl (.|.) 0 $ map (fromIntegral . fromEnum) fs
+
+-- |Default flags for finding corners
+defaultFlags :: [FindFlags]
+defaultFlags = [AdaptiveThresh]
+
+-- | Find the inner corners of a chessboard in a given image. 
+findChessboardCorners :: CV.Image.Image RGB D8 -> (Int, Int) -> [FindFlags] -> [(Float,Float)]
+findChessboardCorners image (w,h) flags =
+   unsafePerformIO $ 
+    with 1 $ \(c_corner_count::Ptr CInt) -> 
+     allocaArray len $ \(c_corners :: Ptr CvPoint )-> 
+      withGenImage image $ \c_image -> do
+        r <- {#call wrapFindChessBoardCorners#} c_image (fromIntegral w) (fromIntegral h)
+                                           (castPtr c_corners) c_corner_count 
+                                           (flagsToNum flags)
+        count <- peek c_corner_count
+        arr <- peekArray (fromIntegral count) c_corners
+        return (map cvPt2Pt arr) 
+  where len = w*h
+
+-- |Given an estimate of chessboard corners, provide a subpixel estimation of actual corners.
+refineChessboardCorners :: Image GrayScale D8 -> [(Float,Float)] -> (Int,Int) -> (Int,Int) -> [(Float,Float)]
+refineChessboardCorners img pts (winW,winH) (zeroW,zeroH) = unsafePerformIO $ do
+    with 1 $ \(c_corner_count::Ptr CInt) -> 
+      withImage img $ \c_img ->
+      withArray (map mkPt pts) $ \(c_corners :: Ptr C'CvPoint2D32f ) -> do 
+        c'wrapFindCornerSubPix c_img c_corners (length pts) winW winH zeroW zeroH tType maxIter epsilon 
+        map fromPt `fmap` peekArray (length pts) c_corners
+ where
+    mkPt (x,y) = C'CvPoint2D32f x y
+    fromPt (C'CvPoint2D32f x y) = (x,y)
+    tType = c'CV_TERMCRIT_ITER
+    maxIter = 100
+    epsilon = 0.01
+
+-- | Draw the found chessboard corners to an image
+drawChessboardCorners :: CV.Image.Image RGB D8 -> (Int, Int) -> [(Float,Float)] -> CV.Image.Image RGB D8
+drawChessboardCorners image (w,h) corners =
+   unsafePerformIO $ 
+    withCloneValue image $ \clone -> 
+     withArray (map pt2CvPt corners) $ \(c_corners :: Ptr CvPoint )-> 
+      withGenImage clone$ \c_image -> do
+        r <- {#call wrapDrawChessBoardCorners#} c_image (fromIntegral w) (fromIntegral h)
+                                           (castPtr c_corners) (fromIntegral $ length corners) 
+                                           (found)
+        return clone
+  where 
+    len = w*h
+    found | (w*h) == length corners = 1
+          | otherwise = 0 
+    
+newtype CvPoint = CvPt (CFloat,CFloat) deriving (Show)
+cvPt2Pt (CvPt (a,b)) = (realToFrac a , realToFrac b)
+pt2CvPt (a,b) = CvPt (realToFrac a , realToFrac b)
+
+instance Storable CvPoint where
+  sizeOf _ = {#sizeof CvPoint #}
+  alignment _ = {#alignof CvPoint2D32f #}
+  peek p = CvPt <$> ((,) 
+    <$> {#get CvPoint2D32f->x #} p
+    <*> {#get CvPoint2D32f->y #} p)
+  poke p (CvPt (hx,hy)) = do
+    {#set CvPoint2D32f.x #} p (hx)
+    {#set CvPoint2D32f.y #} p (hy)
+
+-- | See opencv function cvCalibrateCamera2. This function takes a list of world-screen coordinate pairs acquired with find-chessboard corners
+--   and attempts to find the camera parameters for the system. It returns the fitting error, the camera matrix, list of distortion co-efficients
+--   and rotation and translation vectors for each coordinate pair. 
+calibrateCamera2 ::
+     [[((Float, Float, Float), (Float, Float))]]
+     -> (Int, Int)
+     -> IO (Double, Matrix Float, [[Float]], [[Float]], [[Float]])
+calibrateCamera2 views (w,h) = do
+    let 
+        pointCounts :: Matrix Int
+        pointCounts  = fromList (1,length views) (map (length) views)
+        m = length views
+        totalPts = length (concat views)
+        objectPoints :: Matrix Float
+        objectPoints = fromList (3,totalPts) $ concat [[x,y,z] | ((x,y,z),_) <- concat views]
+        imagePoints :: Matrix Float
+        imagePoints  = fromList (2,totalPts) $ concat [[x,y]   | (_,(x,y))   <- concat views]
+        flags = c'CV_CALIB_FIX_K1
+                .|.  c'CV_CALIB_FIX_K1
+                .|.  c'CV_CALIB_FIX_K2
+                .|.  c'CV_CALIB_FIX_K3
+                .|.  c'CV_CALIB_FIX_K4
+                .|.  c'CV_CALIB_FIX_K5
+                .|.  c'CV_CALIB_FIX_K6
+                .|.  c'CV_CALIB_ZERO_TANGENT_DIST
+
+        size = C'CvSize (fromIntegral w) (fromIntegral h)
+        cameraMatrix,distCoeffs,rvecs,tvecs :: Matrix Float
+        cameraMatrix = emptyMatrix (3,3)
+        distCoeffs   = emptyMatrix (1,8)
+        rvecs        = emptyMatrix (m,3)
+        tvecs        = emptyMatrix (m,3)
+
+    err <- with size $ \c_size ->
+     withMatPtr objectPoints $ \c_objectPoints ->
+     withMatPtr imagePoints $ \c_imagePoints ->
+     withMatPtr pointCounts $ \c_pointCounts ->
+     withMatPtr cameraMatrix $ \c_cameraMatrix ->
+     withMatPtr distCoeffs $ \c_distCoeffs ->
+     withMatPtr rvecs $ \c_rvecs ->
+     withMatPtr tvecs $ \c_tvecs ->
+      c'wrapCalibrateCamera2 c_objectPoints c_imagePoints c_pointCounts c_size 
+                             c_cameraMatrix c_distCoeffs c_rvecs c_tvecs flags
+
+    -- print ( objectPoints, imagePoints, pointCounts,cameraMatrix, distCoeffs, rvecs, tvecs )
+    return (err, transpose cameraMatrix, toCols distCoeffs, toCols rvecs, toCols tvecs)
+
diff --git a/CV/ConnectedComponents.chs b/CV/ConnectedComponents.chs
--- a/CV/ConnectedComponents.chs
+++ b/CV/ConnectedComponents.chs
@@ -44,7 +44,7 @@
      {#call blobCount#} i
 
 -- |Remove all connected components that fall outside of given size range from the image.
-selectSizedComponents :: Double -> CDouble -> Image GrayScale D8 -> Image GrayScale D8
+selectSizedComponents :: Double -> Double -> Image GrayScale D8 -> Image GrayScale D8
 selectSizedComponents minSize maxSize image = unsafePerformIO $ do
     withGenImage image $ \i ->
      creatingImage ({#call sizeFilter#} i (realToFrac minSize) (realToFrac maxSize))
diff --git a/CV/Conversions.hs b/CV/Conversions.hs
--- a/CV/Conversions.hs
+++ b/CV/Conversions.hs
@@ -4,6 +4,7 @@
 module CV.Conversions (
      -- Arrays of Double
      copyCArrayToImage
+    ,copy8UCArrayToImage
     ,copyImageToCArray
      -- Arrays of Float
     ,copyFCArrayToImage
@@ -14,7 +15,8 @@
     -- * Copying
     ,copyImageToExistingCArray
     -- * Acquiring images from pointers
-    ,unsafe8UC3FromPtr
+    ,unsafe8UC_RGBFromPtr
+    ,unsafe8UC_BGRFromPtr
     ,acquireImageSlowF'
     ,acquireImageSlow'
     ,acquireImageSlow8URGB'
@@ -33,10 +35,20 @@
 import Foreign.Storable.Complex
 import System.IO.Unsafe
 
-unsafe8UC3FromPtr :: (Int,Int) -> Ptr Word8 -> IO (Image RGB D8)
-unsafe8UC3FromPtr (w,h) ptr = S `fmap`  creatingBareImage (acquireImageSlow8URGB' w h ptr)
+unsafe8UC_RGBFromPtr :: (Int,Int) -> Ptr Word8 -> IO (Image RGB D8)
+unsafe8UC_RGBFromPtr (w,h) ptr = S `fmap`  creatingBareImage (acquireImageSlow8URGB' w h ptr)
 
+unsafe8UC_BGRFromPtr :: (Int,Int) -> Ptr Word8 -> IO (Image RGB D8)
+unsafe8UC_BGRFromPtr (w,h) ptr = S `fmap`  creatingBareImage (acquireImageSlow8UBGR' w h ptr)
+
 -- |Copy the contents of a CArray into CV.Image type.
+copy8UCArrayToImage :: CArray (Int,Int) Word8 -> Image GrayScale D8
+copy8UCArrayToImage carr = S $ unsafePerformIO $
+                          creatingBareImage (withCArray carr (acquireImageSlow8U' w h))
+    where
+     ((sx,sy),(ex,ey)) = bounds carr
+     (w,h) = (fromIntegral $ ex-sx+1, fromIntegral $ ey-sy+1)
+-- |Copy the contents of a CArray into CV.Image type.
 copyCArrayToImage :: CArray (Int,Int) Double -> Image GrayScale D32
 copyCArrayToImage carr = S $ unsafePerformIO $
                           creatingBareImage (withCArray carr (acquireImageSlow' w h))
@@ -111,6 +123,12 @@
 
 foreign import ccall safe "CV/cvWrapLeo.h acquireImageSlow8URGB"
   acquireImageSlow8URGB' :: (Int -> (Int -> ((Ptr Word8) -> (IO (Ptr (BareImage))))))
+
+foreign import ccall safe "CV/cvWrapLeo.h acquireImageSlow8UBGR"
+  acquireImageSlow8UBGR' :: (Int -> (Int -> ((Ptr Word8) -> (IO (Ptr (BareImage))))))
+
+foreign import ccall safe "CV/cvWrapLeo.h acquireImageSlow8U"
+  acquireImageSlow8U' :: (Int -> (Int -> ((Ptr Word8) -> (IO (Ptr (BareImage))))))
 
 foreign import ccall safe "CV/cvWrapLeo.h acquireImageSlowComplex"
   acquireImageSlowComplex' :: (Int -> (Int -> ((Ptr (Complex Double)) -> (IO (Ptr (BareImage))))))
diff --git a/CV/Edges.chs b/CV/Edges.chs
--- a/CV/Edges.chs
+++ b/CV/Edges.chs
@@ -68,7 +68,7 @@
 --  Works only on 8-bit images
 canny :: Int -> Int -> Int -> Image GrayScale D8 -> Image GrayScale D8
 canny t1 t2 aperture src = unsafePerformIO $ do
-                           withClone src $ \clone -> 
+                           withCloneValue src $ \clone -> 
                             withGenImage src $ \si ->
                              withGenImage clone $ \ci -> do
                                {#call cvCanny#} si ci (fromIntegral t1) 
diff --git a/CV/Filters.chs b/CV/Filters.chs
--- a/CV/Filters.chs
+++ b/CV/Filters.chs
@@ -1,9 +1,9 @@
-{-#LANGUAGE ForeignFunctionInterface, TypeFamilies#-}
+{-#LANGUAGE ForeignFunctionInterface, TypeFamilies, FlexibleInstances#-}
 #include "cvWrapLEO.h"
 -- | This module is a collection of various image filters
 module CV.Filters(gaussian,gaussianOp
               ,blurOp,blur,blurNS
-              ,median
+              ,HasMedianFiltering,median
               ,susan,getCentralMoment,getAbsCentralMoment
               ,getMoment,secondMomentBinarize,secondMomentBinarizeOp
               ,secondMomentAdaptiveBinarize,secondMomentAdaptiveBinarizeOp
@@ -115,9 +115,20 @@
                         (fromIntegral colorS) (fromIntegral spaceS) 0 0
 
 
+-- TODO: The type is not exactly correct
+
+class HasMedianFiltering a where
+    median :: (Int,Int) -> a -> a
+
+instance HasMedianFiltering (Image GrayScale D8) where
+    median = median'
+
+instance HasMedianFiltering (Image RGB D8) where
+    median = median'
+
 -- | Perform median filtering on an eight bit image.
-median :: (Int,Int) -> Image GrayScale D8 -> Image GrayScale D8
-median (w,h) img 
+median' :: (Int,Int) -> Image c D8 -> Image c D8
+median' (w,h) img 
   | maskIsOk (w,h) = unsafePerformIO $ do
                     clone2 <- cloneImage img
                     withGenImage img $ \c1 -> 
@@ -162,7 +173,8 @@
 --   above and left of it. Such images are used for significantly accelerating the calculation of
 --   area averages. 
 newtype IntegralImage = IntegralImage (Image GrayScale D64)
-instance IntSized IntegralImage where
+instance Sized IntegralImage where
+    type Size IntegralImage = (Int,Int)
     getSize (IntegralImage i) = getSize i
 
 instance GetPixel IntegralImage where
diff --git a/CV/Histogram.chs b/CV/Histogram.chs
--- a/CV/Histogram.chs
+++ b/CV/Histogram.chs
@@ -142,17 +142,6 @@
                          cbins = fromIntegral bins
 
 
---getHistgramHS bins image =  calcHistogram bins $ getAllPixels image
---
----- Calculate image histogram from _Floating Point_ Image
---calcHistogram :: Int -> [CDouble] -> HistogramData Int Double
---calcHistogram bins pixels = HGD $ map (\(a,b) -> (realToFrac a, b/l)) $ assocs $ accumArray (+) 0 (0,bins) binned 
---                    where
---                     l = fromIntegral $ length pixels
---                     bin :: CDouble -> (Int,Double)
---                     bin d = (floor $ (fromIntegral bins) * d,1.0)
---                     binned = map bin pixels
---
 ---- Low level interaface:
 
 {#pointer *CvHistogram as Histogram foreign newtype#}
diff --git a/CV/Image.chs b/CV/Image.chs
--- a/CV/Image.chs
+++ b/CV/Image.chs
@@ -1,13 +1,102 @@
-{-#LANGUAGE ForeignFunctionInterface, ViewPatterns,ParallelListComp, FlexibleInstances, FlexibleContexts, TypeFamilies, EmptyDataDecls #-}
+{-#LANGUAGE ForeignFunctionInterface, ViewPatterns,ParallelListComp, FlexibleInstances, FlexibleContexts, TypeFamilies, EmptyDataDecls, ScopedTypeVariables, StandaloneDeriving #-}
 #include "cvWrapLEO.h"
-module CV.Image where
+module CV.Image (
+-- * Basic types 
+ Image(..) 
+, create
+, empty 
+, emptyCopy 
+, emptyCopy' 
+, cloneImage
+, withClone 
+, withCloneValue 
+, CreateImage 
 
+-- * Colour spaces
+, ChannelOf 
+, GrayScale
+, RGB
+, RGBA
+, RGB_Channel(..) 
+, LAB
+, LAB_Channel(..) 
+, D32 
+, D64 
+, D8 
+, Tag 
+, lab 
+, rgba 
+, rgb 
+, composeMultichannelImage 
+
+-- * IO operations
+, Loadable(..) 
+, saveImage 
+, loadColorImage 
+, loadImage 
+
+-- * Pixel level access 
+, GetPixel(..)
+, getAllPixels 
+, getAllPixelsRowMajor 
+, setPixel 
+, setPixel8U 
+, mapImageInplace 
+
+-- * Image information
+, ImageDepth
+, Sized(..)
+, getArea 
+, getChannel
+, getImageChannels 
+, getImageDepth 
+, getImageInfo 
+
+-- * ROI's, COI's and subregions
+, setCOI 
+, setROI 
+, resetROI 
+, getRegion 
+, withIOROI 
+, withROI 
+
+-- * Blitting
+, blendBlit 
+, blit 
+, blitM 
+, subPixelBlit 
+, safeBlit 
+, montage 
+, tileImages 
+
+-- * Conversions
+, rgbToGray 
+, rgbToLab 
+, unsafeImageTo32F 
+, unsafeImageTo8Bit 
+
+-- * Low level access operations
+, BareImage(..)
+, creatingImage 
+, unImage 
+, unS 
+, withGenBareImage 
+, withBareImage 
+, creatingBareImage
+, withGenImage 
+, withImage 
+, ensure32F
+
+) where
+
 import System.Posix.Files
 import System.Mem
 
 import Foreign.C.Types
 import Foreign.C.String
-import Foreign.ForeignPtr
+import Foreign.Marshal.Utils
+import Foreign.ForeignPtr hiding (newForeignPtr)
+import Foreign.Concurrent
 import Foreign.Ptr
 import Control.Parallel.Strategies
 import Control.DeepSeq
@@ -22,6 +111,7 @@
 import Foreign.Storable
 import System.IO.Unsafe
 import Data.Word
+import Control.Monad
 
 
 
@@ -47,10 +137,10 @@
 
 withImage :: Image c d -> (Ptr BareImage ->IO a) -> IO a
 withImage (S i) op = withBareImage i op
---withGenNewImage (S i) op = withGenImage i op 
+--withGenNewImage (S i) op = withGenImage i op
 
 -- Ok. this is just the example why I need image types
-withUniPtr with x fun = with x $ \y -> 
+withUniPtr with x fun = with x $ \y ->
                     fun (castPtr y)
 
 withGenImage = withUniPtr withImage
@@ -58,8 +148,10 @@
 
 {#pointer *IplImage as BareImage foreign newtype#}
 
-foreign import ccall "& wrapReleaseImage" releaseImage :: FinalizerPtr BareImage
+freeBareImage ptr = with ptr {#call cvReleaseImage#}
 
+--foreign import ccall "& wrapReleaseImage" releaseImage :: FinalizerPtr BareImage
+
 instance NFData (Image a b) where
     rnf a@(S (BareImage fptr)) = (unsafeForeignPtrToPtr) fptr `seq` a `seq` ()-- This might also need peek?
 
@@ -67,13 +159,13 @@
 creatingImage fun = do
               iptr <- fun
 --              {#call incrImageC#} -- Uncomment this line to get statistics of number of images allocated by ghc
-              fptr <- newForeignPtr releaseImage iptr
+              fptr <- newForeignPtr iptr (freeBareImage iptr)
               return . S . BareImage $ fptr
 
 creatingBareImage fun = do
               iptr <- fun
 --              {#call incrImageC#} -- Uncomment this line to get statistics of number of images allocated by ghc
-              fptr <- newForeignPtr releaseImage iptr
+              fptr <- newForeignPtr iptr (freeBareImage iptr)
               return . BareImage $ fptr
 
 unImage (S (BareImage fptr)) = fptr
@@ -85,17 +177,17 @@
 
 
 composeMultichannelImage :: (CreateImage (Image tp a)) => Maybe (Image GrayScale a) -> Maybe (Image GrayScale a) -> Maybe (Image GrayScale a) -> Maybe (Image GrayScale a) -> Tag tp -> Image tp a
-composeMultichannelImage (c1) 
+composeMultichannelImage (c1)
                          (c2)
                          (c3)
                          (c4)
                          totag
     = unsafePerformIO $ do
         res <- create (size) -- TODO: Check channel count -- This is NOT correct
-        withMaybe c1 $ \cc1 -> 
-         withMaybe c2 $ \cc2 -> 
-          withMaybe c3 $ \cc3 -> 
-           withMaybe c4 $ \cc4 -> 
+        withMaybe c1 $ \cc1 ->
+         withMaybe c2 $ \cc2 ->
+          withMaybe c3 $ \cc3 ->
+           withMaybe c4 $ \cc4 ->
             withGenImage res $ \cres -> {#call cvMerge#} cc1 cc2 cc3 cc4 cres
         return res
     where
@@ -109,42 +201,79 @@
 --              exists <- fileExist n
 --              if not exists then return Nothing
 --                            else do
---                              i <- withCString n $ \name -> 
+--                              i <- withCString n $ \name ->
 --                                     creatingImage ({#call cvLoadImage #} name (0))
 --                              bw <- imageTo32F i
 --                              return $ Just bw
 
-loadImage :: FilePath -> IO (Maybe (Image GrayScale D32))
-loadImage n = do
+class Loadable a where
+    readFromFile :: FilePath -> IO a
+
+
+instance Loadable ((Image GrayScale D32)) where
+    readFromFile fp = do
+        e <- loadImage fp
+        case e of
+         Just i -> return i
+         Nothing -> fail $ "Could not load "++fp
+
+instance Loadable ((Image RGB D32)) where
+    readFromFile fp = do
+        e <- loadColorImage fp
+        case e of
+         Just i -> return i
+         Nothing -> fail $ "Could not load "++fp
+
+instance Loadable ((Image RGB D8)) where
+    readFromFile fp = do
+        e <- loadColorImage8 fp
+        case e of
+         Just i -> return i
+         Nothing -> fail $ "Could not load "++fp
+
+instance Loadable ((Image GrayScale D8)) where
+    readFromFile fp = do
+        e <- loadImage8 fp
+        case e of
+         Just i -> return i
+         Nothing -> fail $ "Could not load "++fp
+
+
+-- | This function loads and converts image to an arbitrary format. Notice that it is
+--   polymorphic enough to cause run time errors if the declared and actual types of the
+--   images do not match. Use with care.
+unsafeloadUsing x p n = do
               exists <- fileExist n
               if not exists then return Nothing
                             else do
-                              i <- withCString n $ \name -> 
-                                     creatingBareImage ({#call cvLoadImage #} name (0))
-                              bw <- imageTo32F i
+                              i <- withCString n $ \name ->
+                                     creatingBareImage ({#call cvLoadImage #} name p)
+                              bw <- x i
                               return . Just . S $ bw
 
+loadImage :: FilePath -> IO (Maybe (Image GrayScale D32))
+loadImage = unsafeloadUsing imageTo32F 0
+loadImage8 :: FilePath -> IO (Maybe (Image GrayScale D8))
+loadImage8 = unsafeloadUsing imageTo8Bit 0
 loadColorImage :: FilePath -> IO (Maybe (Image RGB D32))
-loadColorImage n = do
-              exists <- fileExist n
-              if not exists then return Nothing
-                            else do
-                              i <- withCString n $ \name -> 
-                                     creatingBareImage ({#call cvLoadImage #} name 1)
-                              bw <- imageTo32F i
-                              return . Just . S  $ bw
+loadColorImage = unsafeloadUsing imageTo32F 1
+loadColorImage8 :: FilePath -> IO (Maybe (Image RGB D8))
+loadColorImage8 = unsafeloadUsing imageTo8Bit 1
 
-class IntSized a where
-    getSize :: a -> (Int,Int)
+class Sized a where
+    type Size a :: *
+    getSize :: a -> Size a
 
-instance IntSized BareImage where
+instance Sized BareImage where
+    type Size BareImage = (Int,Int)
    -- getSize :: (Integral a, Integral b) => Image c d -> (a,b)
     getSize image = unsafePerformIO $ withBareImage image $ \i -> do
                  w <- {#call getImageWidth#} i
                  h <- {#call getImageHeight#} i
                  return (fromIntegral w,fromIntegral h)
 
-instance IntSized (Image c d) where
+instance Sized (Image c d) where
+    type Size (Image c d) = (Int,Int)
     getSize = getSize . unS
 
 
@@ -161,41 +290,83 @@
 
 class GetPixel a where
     type P a :: *
-    getPixel   :: (Integral i) => (i,i) -> a -> P a
+    getPixel   :: (Int,Int) -> a -> P a
 
+-- #define FGET(img,x,y) (((float *)((img)->imageData + (y)*(img)->widthStep))[(x)])
 instance GetPixel (Image GrayScale D32) where
-    type P (Image GrayScale D32) = D32 
-    getPixel (fromIntegral -> x, fromIntegral -> y) image = realToFrac $ unsafePerformIO $
-             withGenImage image $ \img -> {#call wrapGet32F2D#} img y x
+    type P (Image GrayScale D32) = D32
+    {-#INLINE getPixel#-}
+    getPixel (x,y) i = unsafePerformIO $
+                        withGenImage i $ \c_i -> do
+                                         d <- {#get IplImage->imageData#} c_i
+                                         s <- {#get IplImage->widthStep#} c_i
+                                         peek (castPtr (d`plusPtr` (y*(fromIntegral s) +x*sizeOf (0::Float))):: Ptr Float)
 
-instance  GetPixel (Image RGB D32) where
-    type P (Image RGB D32) = (D32,D32,D32) 
-    getPixel (fromIntegral -> x, fromIntegral -> y) image 
-        = unsafePerformIO $ do 
+{-#INLINE getPixelOld#-}
+getPixelOld (fromIntegral -> x, fromIntegral -> y) image = realToFrac $ unsafePerformIO $
+         withGenImage image $ \img -> {#call wrapGet32F2D#} img y x
+
+-- #define UGETC(img,color,x,y) (((uint8_t *)((img)->imageData + (y)*(img)->widthStep))[(x)*3+(color)])
+instance GetPixel (Image RGB D32) where
+    type P (Image RGB D32) = (D32,D32,D32)
+    {-#INLINE getPixel#-}
+    getPixel (x,y) i = unsafePerformIO $
+                        withGenImage i $ \c_i -> do
+                                         d <- {#get IplImage->imageData#} c_i
+                                         s <- {#get IplImage->widthStep#} c_i
+                                         let cs = fromIntegral s
+                                             fs = sizeOf (undefined :: Float)
+                                         r <- peek (castPtr (d`plusPtr` (y*cs +x*3*fs)))
+                                         g <- peek (castPtr (d`plusPtr` (y*cs +(x*3+1)*fs)))
+                                         b <- peek (castPtr (d`plusPtr` (y*cs +(x*3+2)*fs)))
+                                         return (r,g,b)
+
+getPixelOldRGB (fromIntegral -> x, fromIntegral -> y) image
+        = unsafePerformIO $ do
                      withGenImage image $ \img -> do
                               r <- {#call wrapGet32F2DC#} img y x 0
                               g <- {#call wrapGet32F2DC#} img y x 1
                               b <- {#call wrapGet32F2DC#} img y x 2
                               return (realToFrac r,realToFrac g, realToFrac b)
 
+-- | Perform (a destructive) inplace map of the image. This should be wrapped inside
+-- withClone or an image operation
+mapImageInplace :: (P (Image GrayScale D32) -> P (Image GrayScale D32))
+            -> Image GrayScale D32
+            -> IO ()
+mapImageInplace f image = withGenImage image $ \c_i -> do
+             d <- {#get IplImage->imageData#} c_i
+             s <- {#get IplImage->widthStep#} c_i
+             let (w,h) = getSize image
+                 cs = fromIntegral s
+                 fs = sizeOf (undefined :: Float)
+             forM_ [(x,y) | x<-[0..w-1], y <- [0..h-1]] $ \(x,y) -> do
+                   v <- peek (castPtr (d `plusPtr` (y*cs+x*fs)))
+                   poke (castPtr (d `plusPtr` (y*cs+x*fs))) (f v)
+
+
 instance  GetPixel (Image RGB D8) where
-    type P (Image RGB D8) = (D8,D8,D8) 
-    getPixel (fromIntegral -> x, fromIntegral -> y) image 
-        = unsafePerformIO $ do 
-                     withGenImage image $ \img -> do
-                              r <- {#call wrapGet8U2DC#} img y x 0
-                              g <- {#call wrapGet8U2DC#} img y x 1
-                              b <- {#call wrapGet8U2DC#} img y x 2
-                              return (fromIntegral r,fromIntegral g, fromIntegral b)
+    type P (Image RGB D8) = (D8,D8,D8)
+    {-#INLINE getPixel#-}
+    getPixel (x,y) i = unsafePerformIO $
+                        withGenImage i $ \c_i -> do
+                                         d <- {#get IplImage->imageData#} c_i
+                                         s <- {#get IplImage->widthStep#} c_i
+                                         let cs = fromIntegral s
+                                             fs = sizeOf (undefined :: D8)
+                                         r <- peek (castPtr (d`plusPtr` (y*cs +x*3*fs)))
+                                         g <- peek (castPtr (d`plusPtr` (y*cs +(x*3+1)*fs)))
+                                         b <- peek (castPtr (d`plusPtr` (y*cs +(x*3+2)*fs)))
+                                         return (r,g,b)
 
 
 convertTo :: CInt -> CInt -> BareImage -> BareImage
 convertTo code channels img = unsafePerformIO $ creatingBareImage $ do
     res <- {#call wrapCreateImage32F#} w h channels
-    withBareImage img $ \cimg -> 
+    withBareImage img $ \cimg ->
         {#call cvCvtColor#} (castPtr cimg) (castPtr res) code
     return res
- where    
+ where
     (fromIntegral -> w,fromIntegral -> h) = getSize img
 
 class CreateImage a where
@@ -232,38 +403,38 @@
 
 
 empty :: (CreateImage (Image a b)) => (Int,Int) -> (Image a b)
-empty size = unsafePerformIO $ create size 
+empty size = unsafePerformIO $ create size
 
 emptyCopy :: (CreateImage (Image a b)) => Image a b -> IO (Image a b)
-emptyCopy img = create (getSize img) 
+emptyCopy img = create (getSize img)
 
 emptyCopy' :: (CreateImage (Image a b)) => Image a b -> (Image a b)
-emptyCopy' img = unsafePerformIO $ create (getSize img) 
+emptyCopy' img = unsafePerformIO $ create (getSize img)
 
 -- | Save image. This will convert the image to 8 bit one before saving
 saveImage :: FilePath -> Image c d -> IO ()
 saveImage filename image = do
                            fpi <- imageTo8Bit $ unS image
-                           withCString  filename $ \name  -> 
+                           withCString  filename $ \name  ->
                             withGenBareImage fpi    $ \cvArr ->
 							 alloca (\defs -> poke defs 0 >> {#call cvSaveImage #} name cvArr defs >> return ())
 
 
-getArea :: (IntSized a) => a -> Int
+getArea :: (Sized a,Num b, Size a ~ (b,b)) => a -> b
 getArea = uncurry (*).getSize
 
 getRegion :: (Int,Int) -> (Int,Int) -> Image c d -> Image c d
-getRegion (fromIntegral -> x,fromIntegral -> y) (fromIntegral -> w,fromIntegral -> h) image 
+getRegion (fromIntegral -> x,fromIntegral -> y) (fromIntegral -> w,fromIntegral -> h) image
     | x+w <= width && y+h <= height = S . getRegion' (x,y) (w,h) $ unS image
     | otherwise                   = error $ "Region outside image:"
                                             ++ show (getSize image) ++
                                             "/"++show (x+w,y+h)
  where
   (fromIntegral -> width,fromIntegral -> height) = getSize image
-    
+
 getRegion' (x,y) (w,h) image = unsafePerformIO $
                                withBareImage image $ \i ->
-                                 creatingBareImage ({#call getSubImage#} 
+                                 creatingBareImage ({#call getSubImage#}
                                                 i x y w h)
 
 
@@ -271,16 +442,16 @@
 tileImages image1 image2 (x,y) = unsafePerformIO $
                                withImage image1 $ \i1 ->
                                 withImage image2 $ \i2 ->
-                                 creatingImage ({#call simpleMergeImages#} 
+                                 creatingImage ({#call simpleMergeImages#}
                                                 i1 i2 x y)
--- | Blit image2 onto image1. 
+-- | Blit image2 onto image1.
 blitFix = blit
-blit image1 image2 (x,y) 
-    | badSizes  = error $ "Bad blit sizes: " ++ show [(w1,h1),(w2,h2)]++"<-"++show (x,y) 
+blit image1 image2 (x,y)
+    | badSizes  = error $ "Bad blit sizes: " ++ show [(w1,h1),(w2,h2)]++"<-"++show (x,y)
     | otherwise = withImage image1 $ \i1 ->
                    withImage image2 $ \i2 ->
                     ({#call plainBlit#} i1 i2 (fromIntegral y) (fromIntegral x))
-    where 
+    where
      ((w1,h1),(w2,h2)) = (getSize image1,getSize image2)
      badSizes = x+w2>w1 || y+h2>h1 || x<0 || y<0
 
@@ -288,8 +459,8 @@
 blitM (rw,rh) imgs = resultPic
     where
      resultPic = unsafePerformIO $ do
-                    r <- create (fromIntegral rw,fromIntegral rh) 
-                    sequence_ [blit r i (fromIntegral x, fromIntegral y) 
+                    r <- create (fromIntegral rw,fromIntegral rh)
+                    sequence_ [blit r i (fromIntegral x, fromIntegral y)
                               | ((x,y),i) <- imgs ]
                     return r
 
@@ -297,12 +468,12 @@
 subPixelBlit
   :: Image c d -> Image c d -> (CDouble, CDouble) -> IO ()
 
-subPixelBlit (image1) (image2) (x,y) 
-    | badSizes  = error $ "Bad blit sizes: " ++ show [(w1,h1),(w2,h2)]++"<-"++show (x,y) 
+subPixelBlit (image1) (image2) (x,y)
+    | badSizes  = error $ "Bad blit sizes: " ++ show [(w1,h1),(w2,h2)]++"<-"++show (x,y)
     | otherwise = withImage image1 $ \i1 ->
                    withImage image2 $ \i2 ->
                     ({#call subpixel_blit#} i1 i2 y x)
-    where 
+    where
      ((w1,h1),(w2,h2)) = (getSize image1,getSize image2)
      badSizes = ceiling x+w2>w1 || ceiling y+h2>h1 || x<0 || y<0
 
@@ -311,10 +482,10 @@
                   blit res i2 (x,y)
                   return res
 
--- | Blit image2 onto image1. 
---   This uses an alpha channel bitmap for determining the regions where the image should be "blended" with 
+-- | Blit image2 onto image1.
+--   This uses an alpha channel bitmap for determining the regions where the image should be "blended" with
 --   the base image.
-blendBlit image1 image1Alpha image2 image2Alpha (x,y) = 
+blendBlit image1 image1Alpha image2 image2Alpha (x,y) =
                                withImage image1 $ \i1 ->
                                 withImage image1Alpha $ \i1a ->
                                  withImage image2Alpha $ \i2a ->
@@ -322,61 +493,81 @@
                                    ({#call alphaBlit#} i1 i1a i2 i2a x y)
 
 
-cloneImage img = withGenImage img $ \image ->  
+cloneImage img = withGenImage img $ \image ->
                     creatingImage ({#call cvCloneImage #} image)
 
-withClone img fun = do 
+withClone
+  :: Image channels depth
+     -> (Image channels depth -> IO ())
+     -> IO (Image channels depth)
+withClone img fun = do
                 result <- cloneImage img
                 fun result
                 return result
 
-withCloneValue img fun = do 
+withCloneValue
+  :: Image channels depth
+     -> (Image channels depth -> IO a)
+     -> IO a
+withCloneValue img fun = do
                 result <- cloneImage img
                 r <- fun result
                 return r
 
-unsafeImageTo32F img = unsafePerformIO $ withGenImage img $ \image -> 
-                creatingImage 
+unsafeImageTo32F :: Image c d -> Image c D32
+unsafeImageTo32F img = unsafePerformIO $ withGenImage img $ \image ->
+                creatingImage
                  ({#call ensure32F #} image)
 
 unsafeImageTo8Bit :: Image cspace a -> Image cspace D8
-unsafeImageTo8Bit img = unsafePerformIO $ withGenImage img $ \image -> 
-                creatingImage 
+unsafeImageTo8Bit img = unsafePerformIO $ withGenImage img $ \image ->
+                creatingImage
                  ({#call ensure8U #} image)
 
-imageTo32F img = withGenBareImage img $ \image -> 
-                creatingBareImage 
+imageTo32F img = withGenBareImage img $ \image ->
+                creatingBareImage
                  ({#call ensure32F #} image)
 
-imageTo8Bit img = withGenBareImage img $ \image -> 
-                creatingBareImage 
+imageTo8Bit img = withGenBareImage img $ \image ->
+                creatingBareImage
                  ({#call ensure8U #} image)
 #c
 enum ImageDepth {
      Depth32F = IPL_DEPTH_32F,
      Depth64F = IPL_DEPTH_64F,
-     Depth8U  = IPL_DEPTH_8U, 
-     Depth8S  = IPL_DEPTH_8S, 
-     Depth16U  = IPL_DEPTH_16U, 
+     Depth8U  = IPL_DEPTH_8U,
+     Depth8S  = IPL_DEPTH_8S,
+     Depth16U  = IPL_DEPTH_16U,
      Depth16S  = IPL_DEPTH_16S,
      Depth32S  = IPL_DEPTH_32S
      };
 #endc
- 
+
 {#enum ImageDepth {}#}
 
-getImageDepth i = withImage i $ \c_img -> {#get IplImage->depth #} c_img
+deriving instance Show ImageDepth
 
+getImageDepth :: Image c d -> IO ImageDepth
+getImageDepth i = withImage i $ \c_img -> {#get IplImage->depth #} c_img >>= return.toEnum.fromIntegral
+getImageChannels i = withImage i $ \c_img -> {#get IplImage->nChannels #} c_img
+
+getImageInfo x = do
+    let s = getSize x
+    d <- getImageDepth x
+    c <- getImageChannels x
+    return (s,d,c)
+
+
 -- Manipulating regions of interest:
-setROI (fromIntegral -> x,fromIntegral -> y) 
-       (fromIntegral -> w,fromIntegral -> h) 
-       image = withImage image $ \i -> 
+setROI (fromIntegral -> x,fromIntegral -> y)
+       (fromIntegral -> w,fromIntegral -> h)
+       image = withImage image $ \i ->
                             {#call wrapSetImageROI#} i x y w h
 
 resetROI image = withImage image $ \i ->
                   {#call cvResetImageROI#} i
 
-setCOI chnl image = withImage image $ \i -> 
+setCOI chnl image = withImage image $ \i ->
                             {#call cvSetImageCOI#} i (fromIntegral chnl)
 resetCOI image = withImage image $ \i ->
                   {#call cvSetImageCOI#} i 0
@@ -406,43 +597,63 @@
                         resetROI image
                         return x
 
--- Manipulating image pixels
+
+-- | Manipulate image pixels. This is slow, ugly and should be avoided
 --setPixel :: (CInt,CInt) -> CDouble -> Image c d -> IO ()
-setPixel :: (Int,Int) -> D32 -> Image GrayScale D32 -> IO ()
-setPixel (x,y) v image = withGenImage image $ \img ->
+{-#INLINE setPixelOld#-}
+setPixelOld :: (Int,Int) -> D32 -> Image GrayScale D32 -> IO ()
+setPixelOld (x,y) v image = withGenImage image $ \img ->
                           {#call wrapSet32F2D#} img (fromIntegral y) (fromIntegral x) (realToFrac v)
 
+{-#INLINE setPixel#-}
+setPixel :: (Int,Int) -> D32 -> Image GrayScale D32 -> IO ()
+setPixel (x,y) v image = withGenImage image $ \c_i -> do
+                                         d <- {#get IplImage->imageData#} c_i
+                                         s <- {#get IplImage->widthStep#} c_i
+                                         poke (castPtr (d`plusPtr` (y*(fromIntegral s)
+                                              + x*sizeOf (0::Float))):: Ptr Float)
+                                              v
 
-getAllPixels image =  [getPixel (i,j) image 
+{-#INLINE setPixel8U#-}
+setPixel8U :: (Int,Int) -> Word8 -> Image GrayScale D8 -> IO ()
+setPixel8U (x,y) v image = withGenImage image $ \c_i -> do
+                                         d <- {#get IplImage->imageData#} c_i
+                                         s <- {#get IplImage->widthStep#} c_i
+                                         poke (castPtr (d`plusPtr` (y*(fromIntegral s)
+                                              + x*sizeOf (0::Word8))):: Ptr Word8)
+                                              v
+
+
+getAllPixels image =  [getPixel (i,j) image
                       | i <- [0..width-1 ]
-                      , j <- [0..height-1]]                          
+                      , j <- [0..height-1]]
                     where
                      (width,height) = getSize image
 
-getAllPixelsRowMajor image =  [getPixel (i,j) image 
+getAllPixelsRowMajor image =  [getPixel (i,j) image
                               | j <- [0..height-1]
                               , i <- [0..width-1]
-                              ]                          
+                              ]
                     where
                      (width,height) = getSize image
 
 -- |Create a montage form given images (u,v) determines the layout and space the spacing
 --  between images. Images are assumed to be the same size (determined by the first image)
 montage :: (CreateImage (Image c d)) => (Int,Int) -> Int -> [Image c d] -> Image c d
-montage (u',v') space' imgs 
+montage (u',v') space' imgs
     | u'*v' /= (length imgs) = error ("Montage mismatch: "++show (u,v, length imgs))
     | otherwise              = resultPic
     where
      space = fromIntegral space'
      (u,v) = (fromIntegral u', fromIntegral v')
-     (rw,rh) = (u*xstep,v*ystep) 
+     (rw,rh) = (u*xstep,v*ystep)
      (w,h) = getSize (head imgs)
      (xstep,ystep) = (fromIntegral space + w,fromIntegral space + h)
      edge = space`div`2
      resultPic = unsafePerformIO $ do
                     r <- create (rw,rh)
-                    sequence_ [blit r i (edge +  x*xstep, edge + y*ystep) 
-                               | y <- [0..v-1] , x <- [0..u-1] 
+                    sequence_ [blit r i (edge +  x*xstep, edge + y*ystep)
+                               | y <- [0..v-1] , x <- [0..u-1]
                                | i <- imgs ]
                     return r
 
diff --git a/CV/ImageMath.chs b/CV/ImageMath.chs
--- a/CV/ImageMath.chs
+++ b/CV/ImageMath.chs
@@ -21,15 +21,21 @@
 mkBinaryImageOpIO f = \a -> \b -> 
           withGenImage a $ \ia -> 
           withGenImage b $ \ib ->
-          withClone a    $ \clone ->
+          withCloneValue a    $ \clone ->
           withGenImage clone $ \cl -> do
             f ia ib cl 
             return clone
  
+mkBinaryImageOp
+  :: (Ptr () -> Ptr () -> Ptr () -> IO a)
+     -> CV.Image.Image c1 d1
+     -> CV.Image.Image c1 d1
+     -> CV.Image.Image c1 d1
+
 mkBinaryImageOp f = \a -> \b -> unsafePerformIO $
           withGenImage a $ \ia -> 
           withGenImage b $ \ib ->
-          withClone a    $ \clone ->
+          withCloneValue a    $ \clone ->
           withGenImage clone $ \cl -> do
             f ia ib cl 
             return clone
@@ -76,6 +82,7 @@
 
 absDiff = mkBinaryImageOp {#call cvAbsDiff#}
 
+atan :: Image GrayScale D32 -> Image GrayScale D32
 atan i = unsafePerformIO $ do
                     let (w,h) = getSize i
                     res <- create (w,h) 
@@ -209,7 +216,7 @@
 
 -- | Sum the pixels in the image. Notice that OpenCV automatically casts the
 --   result to double sum :: Image GrayScale D32 -> D32
-sum :: Image GrayScale a -> Double
+sum :: Image GrayScale D32 -> D32
 sum img = realToFrac $ unsafePerformIO $ withGenImage img $ \image ->
                     {#call wrapSum#} image
 
diff --git a/CV/ImageOp.hs b/CV/ImageOp.hs
--- a/CV/ImageOp.hs
+++ b/CV/ImageOp.hs
@@ -48,8 +48,8 @@
 img <## op = unsafeOperate (foldl1 (#>) op) img
 
 
--- runImageOperation :: Image c d -> ImageOperation c d -> IO (Image c d)
-operate (ImgOp op) img = withClone img $ \clone -> 
+operate ::ImageOperation c d -> Image c d -> IO (Image c d)
+operate (ImgOp op) img = withCloneValue img $ \clone -> 
                                     op clone >> return clone
 
 operateOn = flip operate
diff --git a/CV/Matrix.hs b/CV/Matrix.hs
new file mode 100644
--- /dev/null
+++ b/CV/Matrix.hs
@@ -0,0 +1,207 @@
+{-#LANGUAGE ParallelListComp, TypeFamilies, FlexibleInstances, FlexibleContexts, ScopedTypeVariables#-}
+-- | This module provides wrappers for CvMat type. This is still preliminary as the type of the
+--   matrix isn't coded in the haskell type.
+module CV.Matrix 
+    (
+    Exists,Exists(..),
+    Matrix, emptyMatrix ,fromList,toList,toRows,toCols,get,put,withMatPtr
+    , transpose, mxm, rodrigues2
+    )where
+
+{-#OPTIONS_GHC -fwarn-unused-imports#-}
+
+import System.Posix.Files
+import System.Mem
+
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Marshal.Utils
+import Foreign.ForeignPtr hiding (newForeignPtr)
+import Foreign.Concurrent 
+import Foreign.Ptr
+import Control.Parallel.Strategies
+import Control.DeepSeq
+
+-- import C2HSTools
+
+import Data.Maybe(catMaybes)
+import Data.List(genericLength)
+import Foreign.Marshal.Array
+import Foreign.Marshal.Alloc
+import Foreign.Ptr
+import Foreign.Storable
+import System.IO.Unsafe
+import Data.Word
+import Control.Monad
+
+import CV.Bindings.Matrix
+import CV.Image hiding (create)
+
+-- #define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size )  \
+--    (assert( (unsigned)(row) < (unsigned)(mat).rows &&   \
+--             (unsigned)(col) < (unsigned)(mat).cols ),   \
+--     (mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col))
+
+-- | Haskell reflection of CvMat type
+newtype Matrix a = Matrix (ForeignPtr C'CvMat)
+
+instance (Show t, Storable t, (Size (Matrix t))~(Int,Int)) => Show (Matrix t) where
+    show m = "fromList "++show (getSize m)++" "++show (toList m)
+
+matrixFinalizer ptr = with ptr c'cvReleaseMat
+
+class Exists a where
+    type Args a :: *
+    create :: Args a -> a
+
+instance Exists (Matrix Float) where
+    type Args (Matrix Float) = (Int,Int)
+    create (r,c) = unsafePerformIO $ creatingMat (c'cvCreateMat r c c'CV_32FC1) 
+
+instance Exists (Matrix Int) where
+    type Args (Matrix Int) = (Int,Int)
+    create (r,c) = unsafePerformIO $ creatingMat (c'cvCreateMat r c c'CV_32SC1) 
+
+instance Exists (Matrix Double) where
+    type Args (Matrix Double) = (Int,Int)
+    create (r,c) = unsafePerformIO $ creatingMat (c'cvCreateMat r c c'CV_64FC1) 
+
+instance Sized (Matrix a) where
+    type Size (Matrix a) = (Int,Int)
+    getSize (Matrix e) = unsafePerformIO $ withForeignPtr e $ \mat -> do
+                         mat' <- peek mat
+                         return (fromIntegral $ c'CvMat'rows mat', 
+                                fromIntegral $ c'CvMat'cols mat')
+
+-- | Create an empty matrix of given dimensions
+emptyMatrix :: Exists (Matrix a) => Args (Matrix a) -> Matrix a
+emptyMatrix a = create a
+
+identity :: (Num a, Sized (Matrix a), Args (Matrix a) ~ (Int,Int),  Size (Matrix a) ~ (Int,Int),  Storable a, Exists (Matrix a)) => 
+             (Matrix a) -> Matrix a
+identity a = unsafePerformIO $ do
+             let res = create (getSize a) 
+                 (rows,cols) = getSize a
+             sequence_ [put res row col 1 
+                       | row <- [0..rows-1]
+                       | col <- [0..cols-1]]
+             return res
+
+-- | Transpose a matrix. Does not do complex conjugation for complex matrices  
+transpose :: (Exists (Matrix a), Args (Matrix a) ~ Size (Matrix a)) => Matrix a -> Matrix a
+transpose m@(Matrix f_m) = unsafePerformIO $ do
+                 let res@(Matrix f_c) = create (getSize m)
+                 withForeignPtr f_m $ \c_m ->
+                  withForeignPtr f_c $ c'cvTranspose c_m 
+                 return res
+
+-- | Convert a rotation vector to a rotation matrix (1x3 -> 3x3)
+rodrigues2 :: (Exists (Matrix a), Args (Matrix a) ~ Size (Matrix a)) => Matrix a -> Matrix a
+rodrigues2 m@(Matrix f_m) = unsafePerformIO $ do
+                 let res@(Matrix f_c) = create (3,3)
+                 withForeignPtr f_m $ \c_m ->
+                  withForeignPtr f_c $ \c_c -> c'cvRodrigues2 c_m c_c nullPtr
+                 return res
+
+
+-- | Ordinary matrix multiplication
+mxm :: (Exists (Matrix a), Args (Matrix a) ~ Size (Matrix a)) => Matrix a -> Matrix a -> Matrix a
+mxm m1@(Matrix a_m) m2@(Matrix b_m) = unsafePerformIO $ do
+                 let (w1,h1) = getSize m1
+                     (w2,h2) = getSize m2
+                     res@(Matrix f_c) = create (w1,h2)
+                 when (h1 /= w2) . error  $ 
+                    "Matrix dimensions do not match for multiplication: "
+                    ++show (w1,h1)
+                    ++" vs. "
+                    ++ show (w2,h2)
+                 withForeignPtr a_m $ \c_a ->
+                  withForeignPtr b_m $ \c_b ->
+                  withForeignPtr f_c $ \c_res -> c'cvGEMM c_a c_b 1 nullPtr 1 c_res 0
+                 return res
+
+withMatPtr :: Matrix x -> (Ptr C'CvMat -> IO a) -> IO a
+withMatPtr (Matrix m) op = withForeignPtr m op 
+
+-- | Convert a list of floats into Matrix
+fromList :: forall t . (Storable t, Exists (Matrix t), Args (Matrix t) ~ (Int,Int)) 
+                        => (Int,Int) -> [t] -> Matrix t
+fromList (w,h) lst = unsafePerformIO $ do
+                let m@(Matrix e) = emptyMatrix (w,h)
+                withForeignPtr e $ \mat -> do
+                         mat' <- peek mat
+                         let d :: Ptr t
+                             d = castPtr $ c'CvMat'data'ptr mat'
+                             s = c'CvMat'step mat'
+                         sequence_ [putRaw d s row col v 
+                                   | (row,col) <- [(r,c) | c <- [0..h-1], r <- [0..w-1]]
+                                   | v <- lst ]
+                return $ m
+
+
+-- | Convert a matrix to flat list (row major order)
+toList :: (Storable a) => Matrix a -> [a] 
+toList =  concat . toRows
+
+-- | Convert matrix to rows represented as nested lists
+toRows :: forall t . (Storable t) => Matrix t -> [[t]] 
+toRows (Matrix e) = unsafePerformIO $ do
+                withForeignPtr e $ \mat -> do
+                         mat' <- peek mat
+                         let d = castPtr (c'CvMat'data'ptr mat') :: Ptr t
+                             s = c'CvMat'step mat'
+                             rows = fromIntegral $ c'CvMat'rows mat'
+                             cols = fromIntegral $ c'CvMat'cols mat'
+                         sequence [sequence [getRaw d (fromIntegral s) row col | row <- [0..rows-1]]
+                                   | col <- [0..cols-1]
+                                   ]
+
+-- | Convert matrix to cols represented as nested lists
+toCols :: forall t . (Storable t) => Matrix t -> [[t]] 
+toCols (Matrix e) = unsafePerformIO $ do
+                withForeignPtr e $ \mat -> do
+                         mat' <- peek mat
+                         let d = castPtr (c'CvMat'data'ptr mat') :: Ptr t
+                             s = c'CvMat'step mat'
+                             rows = fromIntegral $ c'CvMat'rows mat'
+                             cols = fromIntegral $ c'CvMat'cols mat'
+                         sequence [sequence [getRaw d (fromIntegral s) row col | col <- [0..cols-1]]
+                                   | row <- [0..rows-1]
+                                   ]
+
+creatingMat fun = do
+              iptr <- fun
+              fptr <- newForeignPtr iptr (matrixFinalizer iptr)
+              return . Matrix $ fptr
+
+{-#INLINE get#-}
+-- | Get an element of the matrix
+get :: forall t . (Storable t) => (Matrix t) -> Int -> Int -> IO t
+get (Matrix m) row col = withForeignPtr m $ \mat -> do
+         mat' <- peek mat
+         let d = c'CvMat'data'ptr mat'
+         let s = c'CvMat'step mat'
+         getRaw (castPtr d:: Ptr t) (fromIntegral s) (fromIntegral row) (fromIntegral col)
+
+{-#INLINE getRaw#-}
+getRaw :: forall t . (Storable t) => Ptr t -> Int -> Int -> Int -> IO t
+getRaw d s col row = 
+         peek (castPtr (d `plusPtr` (col*s+row*sizeOf (undefined::t))):: Ptr t)
+
+{-#INLINE put#-}
+-- | Write an element to a matrix
+put :: forall t . (Storable t) => (Matrix t) -> Int -> Int -> t -> IO ()
+put (Matrix m) row col v = withForeignPtr m $ \mat -> do
+         mat' <- peek mat
+         let 
+            d :: Ptr t
+            d = castPtr $ c'CvMat'data'ptr mat'
+            s = c'CvMat'step mat'
+         putRaw d s row col v
+
+{-#INLINE putRaw#-}
+putRaw :: forall t. (Storable t) => Ptr t -> CInt -> Int -> Int -> t -> IO ()
+putRaw d s col row v = 
+         poke (castPtr (d `plusPtr` (col*(fromIntegral s)+row*sizeOf (undefined::t))):: Ptr t)
+              v
+
diff --git a/CV/Morphology.chs b/CV/Morphology.chs
--- a/CV/Morphology.chs
+++ b/CV/Morphology.chs
@@ -1,4 +1,4 @@
-{-#LANGUAGE ForeignFunctionInterface, ScopedTypeVariables, UnicodeSyntax#-}
+{-#LANGUAGE ForeignFunctionInterface, ScopedTypeVariables, UnicodeSyntax, ViewPatterns#-}
 #include "cvWrapLEO.h"
 module CV.Morphology (StructuringElement
                   ,structuringElement
@@ -122,13 +122,13 @@
     ,`Int'} -> `()' #}
 
 
-erodeOp se count = ImgOp $ \(S img)  -> erosion img img se count
-dilateOp se count = ImgOp $ \(S img) -> dilation img img se count
+erodeOp se count = ImgOp $ \(unS -> img)  -> erosion img img se count
+dilateOp se count = ImgOp $ \(unS -> img) -> dilation img img se count
 
 erode se count  i = unsafeOperate (erodeOp se count)  i
 dilate se count i = unsafeOperate (dilateOp se count) i
 
-a ⊕ b = erode b 1 a
+a ⊕ b = dilate b 1 a
 a ⊖ b = erode b 1 a
                        
 erode' se count img = withImage img $ \image ->
diff --git a/CV/MultiresolutionSpline.hs b/CV/MultiresolutionSpline.hs
--- a/CV/MultiresolutionSpline.hs
+++ b/CV/MultiresolutionSpline.hs
@@ -1,3 +1,5 @@
+-- | This module provides the elementary image splining (seamless merging) using the burt-adelson multiresolution splines
+-- introduced in "A multiresolution spline with application to image mosaics", Burt, P.J. and Adelson, E.H., ACM Transactions on Graphics,1983.
 module CV.MultiresolutionSpline where
 
 import CV.Image
@@ -7,14 +9,13 @@
 import CV.Filters
 
 
--- stitchHalfAndHalf i1 i2 = montage (2,1) 0 [getRegion (0,0) (hw,dh) i1,getRegion (hw,0) (hw,dh) i2]
---     where
---      dh = h
---      (w,h) = getSize i1
---      (hw,hh) = (w`div`2,h`div`2)
 
--- | Do a burt-adelson multiresolution splining for two images.
---   Notice, that the mask should contain a tiny blurred region between images 
+-- | This function merges two images based on given mask, the first image dominates on areas where the mask
+--   is 1 and the second where the mask is 0. The merging should be relatively seamless and is controlled by
+--   the `levels` parameter, which adjusts the accuracy. Usually, decent results can be obtained with 4 pyramid 
+--   levels.
+--   
+--   Note that the mask should contain a tiny blurred region between images for optimal result.
 burtAdelsonMerge :: Int -> Image GrayScale D8 -> Image GrayScale D32 -> Image GrayScale D32 
                         -> Image GrayScale D32
 burtAdelsonMerge levels mask img1 img2 
diff --git a/CV/Pixelwise.hs b/CV/Pixelwise.hs
new file mode 100644
--- /dev/null
+++ b/CV/Pixelwise.hs
@@ -0,0 +1,63 @@
+-- | This module is an applicative wrapper for images. It introduces Pixelwise type that
+--   can be converted from and to grayscale images and which has an applicative and functor
+--   instances.
+{-#LANGUAGE TypeFamilies#-}
+module CV.Pixelwise (Pixelwise(..), fromImage, toImage, remap, (<$$>),(<+>)) where
+import Control.Applicative 
+import CV.Image
+import System.IO.Unsafe
+import Control.Parallel.Strategies
+
+-- | A wrapper for allowing functor and applicative instances for non-polymorphic image types.
+data Pixelwise x = MkP {sizeOf :: (Int,Int)
+                       ,eltOf :: (Int,Int) -> x}
+
+instance GetPixel (Pixelwise x) where
+    type P (Pixelwise x) = x
+    getPixel p (MkP s e) = e p
+
+instance Sized (Pixelwise a) where
+    type Size (Pixelwise a) = (Int,Int)
+    getSize (MkP s _) = s 
+
+instance Functor Pixelwise where
+    fmap f (MkP s e) = MkP s (fmap f e)
+
+instance Applicative Pixelwise where
+  pure x               = MkP maxBound  (pure x)
+  MkP i f <*> MkP j g  = MkP (min i j) (f <*> g)
+
+-- | Re-arrange pixel positions and values
+remap :: (((Int,Int) -> b) -> ((Int,Int) -> x)) -> Pixelwise b -> Pixelwise x
+remap f (MkP s e) = MkP s (f e)
+
+-- | Convert a pixelwise construct into an image.
+fromImage :: (GetPixel b, Sized b, Size b ~ Size (Pixelwise (P b))) => b -> Pixelwise (P b)
+fromImage i = MkP (getSize i) (flip getPixel $ i)
+
+-- | Convert an image to pixelwise construct.
+toImage :: Pixelwise D32 -> Image GrayScale D32
+toImage (MkP (w,h) e) = unsafePerformIO $ do
+        img <- create (w,h)
+        sequence_ [setPixel (i,j) (e (i,j)) img
+                  | i <- [0..w-1]
+                  , j <- [0..h-1]
+                  ]
+        return img
+
+toImageP :: Pixelwise D32 -> Image GrayScale D32
+toImageP (MkP (w,h) e) = unsafePerformIO $ do
+        img <- create (w,h)
+        let rs = parMap rdeepseq (\j -> unsafePerformIO (
+                                          sequence_ [setPixel (i,j) (e (i,j)) img | i <- [0..w-1]]
+                                          >> return True))
+                                 [0..h-1]
+        all (==True) rs `seq` return img
+
+-- | Shorthand for `a <$> fromImage b`
+(<$$>) :: (Size b1 ~ (Int, Int), Sized b1, GetPixel b1) => (P b1 -> b) -> b1 -> Pixelwise b
+a <$$> b = a <$> fromImage b
+
+-- | Shorthand for `a <*> fromImage b`
+(<+>) :: (Size b1 ~ (Int, Int), Sized b1, GetPixel b1) => Pixelwise (P b1 -> b) -> b1 -> Pixelwise b
+a <+> b = a <*> fromImage b
diff --git a/CV/Textures.chs b/CV/Textures.chs
--- a/CV/Textures.chs
+++ b/CV/Textures.chs
@@ -1,6 +1,9 @@
-{-#LANGUAGE ForeignFunctionInterface#-}
+{-#LANGUAGE ForeignFunctionInterface, ParallelListComp#-}
 #include "cvWrapLEO.h"
-module CV.Textures where
+-- |This module provides implementations for basic versions of Local Binary Pattern texture features introduced in
+-- T. Ojala, M. Pietikäinen, and D. Harwood (1994), "Performance evaluation of texture measures with classification
+--  based on Kullback discrimination of distributions", Proceedings of the 12th IAPR International Conference on Pattern Recognition (ICPR 1994).
+module CV.Textures (rotationInvariant,lbp,lbp5,weightedLBP) where
 
 import Foreign.C.Types
 import Foreign.C.String
@@ -11,36 +14,81 @@
 import CV.Image 
 import CV.ImageOp
 
+import Data.List
 import C2HSTools
+import qualified Data.Vector as V
+import Data.Vector (Vector)
+import Data.Maybe (fromMaybe)
 {#import CV.Image#}
 
 
--- | Various simple Local Binary Pattern operators
+-- * Rotation invariance
 
-lbp = broilerPlate ({#call localBinaryPattern#})
+-- |Normalize Word8 according to lbp-logic.
+normalize :: Word8 -> Word8
+normalize x = minimum [rotateL x i | i<-[0..8] ]
 
-lbp3 = broilerPlate ({#call localBinaryPattern3#})
-lbp5 = broilerPlate ({#call localBinaryPattern5#})
-lbpHorizontal = broilerPlate 
+-- |Make an lbp table element rotation invariant
+rotationInvariantE :: Word8 -> Word8 
+rotationInvariantE a =  fromIntegral
+                      . fromMaybe (error "Unthinkable happened(RI)") 
+                      . V.findIndex (==normalize a) $ keywords
+keywords = V.fromList . nub . sort . map normalize $ allWords
+allWords = [minBound .. maxBound]
+
+-- | Convert an LBP histogram into rotation invariant form
+rotationInvariant :: [Double] -> Vector Double
+rotationInvariant es = V.accum (+) (V.replicate 36 0) 
+                         [(fromIntegral . rotationInvariantE $ i, e) 
+                         | i <- [minBound .. maxBound]
+                         | e <- es]
+            
+
+-- * Various simple Local Binary Pattern operators
+
+-- | The most basic 3x3 lbp operator
+lbp :: Image GrayScale D32 -> [Double] 
+lbp   = broilerPlate256 ({#call localBinaryPattern#})
+
+-- lbp3 :: Image GrayScale D32 -> [Double] 
+-- lbp3 = broilerPlate256 ({#call localBinaryPattern3#})
+
+-- | The larger radius basic 5x5 lbp operator
+lbp5 :: Image GrayScale D32 -> [Double] 
+lbp5 = broilerPlate256 ({#call localBinaryPattern5#})
+
+lbpHorizontal :: Image GrayScale D32 -> [Double] 
+lbpHorizontal = broilerPlate256 
     ({#call localHorizontalBinaryPattern#})
-lbpVertical = broilerPlate 
+
+lbpVertical :: Image GrayScale D32 -> [Double] 
+lbpVertical = broilerPlate256 
     ({#call localVerticalBinaryPattern#})
 
--- LBP with weights and adjustable sampling points
+-- | A variant of LBP which is weighted. This can be used to select only parts of the
+-- image by using binary masks, or to give higher weight for some areas of the image.
+weightedLBP :: (Integral a, Integral a1) =>
+     a
+     -> a1
+     -> CV.Image.Image GrayScale D32
+     -> CV.Image.Image GrayScale D32
+     -> [Double]
+
 weightedLBP offsetX offsetXY weights image = unsafePerformIO $ do
              withGenImage image $ \img ->
               withGenImage weights $ \ws ->
                   withArray (replicate 256 0) $ \ptrn -> do
-                    {#call weighted_localBinaryPattern#} img (fromIntegral offsetX) (fromIntegral offsetXY) ws ptrn 
+                    {#call weighted_localBinaryPattern#} img 
+                        (fromIntegral offsetX) 
+                        (fromIntegral offsetXY) ws ptrn 
                     p <- peekArray 256 ptrn
-                    return p
+                    return $ map realToFrac p
 
-emptyPattern :: [CInt]
-emptyPattern = replicate 256 0
-broilerPlate op image = unsafePerformIO $ do
+broilerPlate256  = broilerPlate' 256
+broilerPlate' l op image = unsafePerformIO $ do
              withGenImage image $ \img ->
-              withArray emptyPattern $ \ptrn -> do
+              withArray (replicate l 0 :: [CInt]) $ \ptrn -> do
                 (op img ptrn )
-                p <- peekArray 256 ptrn
+                p <- peekArray l ptrn
                 let !maximum = fromIntegral $ sum p
                 return $ map (\x -> fromIntegral x / maximum) p
diff --git a/CV/Transforms.chs b/CV/Transforms.chs
--- a/CV/Transforms.chs
+++ b/CV/Transforms.chs
@@ -22,6 +22,7 @@
              | otherwise = 2
 
 -- |Perform Discrete Cosine Transform
+dct :: Image GrayScale d -> Image GrayScale d
 dct img | (x,y) <- getSize img, even x && even y 
         = unsafePerformIO $
             withGenImage img $ \i -> 
@@ -31,6 +32,7 @@
         | otherwise = error "DCT needs even sized image"
 
 -- |Perform Inverse Discrete Cosine Transform
+idct :: Image GrayScale d -> Image GrayScale d
 idct img | (x,y) <- getSize img, even x && even y 
         = unsafePerformIO $
             withGenImage img $ \i -> 
@@ -42,6 +44,7 @@
 data MirrorAxis = Vertical | Horizontal deriving (Show,Eq)
 
 -- |Mirror an image over a cardinal axis
+flip :: CreateImage (Image c d) => MirrorAxis -> Image c d -> Image c d
 flip axis img = unsafePerformIO $ do
                  cl <- emptyCopy img
                  withGenImage img $ \cimg -> 
@@ -50,7 +53,8 @@
                  return cl
 
 -- |Rotate `img` `angle` radians.
-rotate angle img = unsafePerformIO $
+rotate :: Double -> Image c d -> Image c d
+rotate (realToFrac -> angle) img = unsafePerformIO $
                     withImage img $ \i -> 
                         creatingImage 
                          ({#call rotateImage#} i 1 angle)
@@ -73,7 +77,7 @@
 
 
 -- |Scale an image with different ratios for axes
-scale :: (RealFloat a) => Interpolation -> (a,a) -> Image GrayScale D32 -> Image GrayScale D32
+scale :: (CreateImage (Image c D32), RealFloat a) => Interpolation -> (a,a) -> Image c D32 -> Image c D32
 scale tpe (x,y) img = unsafePerformIO $ do
                     target <- create (w',h') 
                     withGenImage img $ \i -> 
@@ -87,7 +91,8 @@
                        ,round $ fromIntegral h*x)
 
 -- |Scale an image to a given size
-scaleToSize :: Interpolation -> Bool -> (Int,Int) -> Image GrayScale D32 -> Image GrayScale D32
+scaleToSize :: (CreateImage (Image c D32)) => 
+    Interpolation -> Bool -> (Int,Int) -> Image c D32 -> Image c D32
 scaleToSize tpe retainRatio (w,h) img = unsafePerformIO $ do
                     target <- create (w',h') 
                     withGenImage img $ \i -> 
@@ -103,13 +108,9 @@
              ratio  = max (fromIntegral w/fromIntegral ow)
                           (fromIntegral h/fromIntegral oh)
 
--- | DEPRECATED: A simple one parameter shrinking of the image
-oneParamPerspective img k
-    = unsafePerformIO $ 
-       withImage img $ \cimg -> creatingImage $ {#call simplePerspective#} k cimg
-
 -- |Apply a perspective transform to the image. The transformation 3x3 matrix is supplied as
 --  a row ordered, flat, list.
+perspectiveTransform :: Real a => Image c d -> [a] -> Image c d
 perspectiveTransform img (map realToFrac -> [a1,a2,a3,a4,a5,a6,a7,a8,a9])
     = unsafePerformIO $ 
        withImage img $ \cimg -> creatingImage $ {#call wrapPerspective#} cimg a1 a2 a3 a4 a5 a6 a7 a8 a9
@@ -130,6 +131,7 @@
 
 --- Pyramid transforms
 -- |Return a copy of an image with an even size
+evenize :: Image channels depth -> Image channels depth
 evenize img = if (odd w || odd h)
               then  
                 unsafePerformIO $     
@@ -140,6 +142,7 @@
      (w,h)  = getSize img
 
 -- |Return a copy of an image with an odd size
+oddize :: Image channels depth -> Image channels depth
 oddize img = if (even w || even h)
               then  
                 unsafePerformIO $     
@@ -152,6 +155,7 @@
      (w,h)  = getSize img
 
 -- |Pad images to same size
+sameSizePad :: Image channels depth -> Image c d -> Image channels depth
 sameSizePad img img2 = if (size1 /= size2)
               then unsafePerformIO $ do
                 r <- creatingImage $
diff --git a/CV/Video.chs b/CV/Video.chs
--- a/CV/Video.chs
+++ b/CV/Video.chs
@@ -1,4 +1,4 @@
-{-#LANGUAGE ForeignFunctionInterface, ViewPatterns#-}
+{-#LANGUAGE ForeignFunctionInterface, ViewPatterns, CPP#-}
 #include "cvWrapLEO.h"
 module CV.Video where
 {#import CV.Image#}
@@ -77,11 +77,17 @@
     , CAP_PROP_GAIN           =  CV_CAP_PROP_GAIN         
     , CAP_PROP_EXPOSURE       =  CV_CAP_PROP_EXPOSURE     
     , CAP_PROP_CONVERT_RGB    =  CV_CAP_PROP_CONVERT_RGB  
-    , CAP_PROP_WHITE_BALANCE  =  CV_CAP_PROP_WHITE_BALANCE
+#ifdef OpenCV23
+    , CAP_PROP_WHITE_BALANCE_BLUE_U = CV_CAP_PROP_WHITE_BALANCE_BLUE_U 
+    , CAP_PROP_WHITE_BALANCE_RED_V  = CV_CAP_PROP_WHITE_BALANCE_RED_V
+#else
+    , CAP_PROP_WHITE_BALANCE  = CV_CAP_PROP_WHITE_BALANCE
+#endif
     , CAP_PROP_RECTIFICATION  =  CV_CAP_PROP_RECTIFICATION 
     , CAP_PROP_MONOCROME      =  CV_CAP_PROP_MONOCROME    
 };
 #endc
+
 {#enum CapProp {}#}
 
 fromProp = fromIntegral . fromEnum
diff --git a/CV/cvWrapLEO.c b/CV/cvWrapLEO.c
deleted file mode 100644
--- a/CV/cvWrapLEO.c
+++ /dev/null
@@ -1,2286 +0,0 @@
-//@+leo-ver=4-thin
-//@+node:aleator.20050908100314:@thin cvWrapLEO.c
-//@@language c
-
-//@+all
-//@+node:aleator.20050908100314.1:Includes
-#include "cvWrapLEO.h"
-#include <stdio.h>
-#include <complex.h>
-
-//@-node:aleator.20050908100314.1:Includes
-//@+node:aleator.20050908100314.2:Wrappers
-
-#define FGET(img,x,y) (((float *)((img)->imageData + (y)*(img)->widthStep))[(x)])
-#define UGETC(img,color,x,y) (((uint8_t *)((img)->imageData + (y)*(img)->widthStep))[(x)*3+(color)])
-
-size_t images;
-
-void incrImageC(void)
-{
- images++;
-}
-
-void wrapReleaseImage(IplImage *t)
-{
- // printf("%d ",images);
- cvReleaseImage(&t);
- images--;
-}
-
-void wrapReleaseCapture(CvCapture *t)
-{
- cvReleaseCapture(&t);
-}
-
-void wrapReleaseVideoWriter(CvCapture *t)
-{
- cvReleaseCapture(&t);
-}
-
-void wrapReleaseStructuringElement(IplConvKernel *t)
-{
- cvReleaseStructuringElement(&t);
-}
-
-IplImage* wrapLaplace(IplImage *src,int size)
-{
-IplImage *res;
-IplImage *tmp;
-tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
-res = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
-cvLaplace(src,tmp,size);
-cvConvertScale(tmp,res,1,0);
-return res;
-}
-
-IplImage* wrapSobel(IplImage *src,int dx
-                   ,int dy,int size)
-{
-IplImage *res;
-IplImage *tmp;
-tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
-res = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
-cvSobel(src,tmp,dx,dy,size);
-cvConvertScale(tmp,res,1,0);
-cvReleaseImage(&tmp);
-return res;
-}
-
-IplImage* wrapCreateImage32F(const int width
-                         ,const int height
-                         ,const int channels)
-{
- CvSize s;
- IplImage *r;
- s.width = width; s.height = height;
- r = cvCreateImage(s,IPL_DEPTH_32F,channels);
- cvSetZero(r);
- return r;
-}
-
-IplImage* wrapCreateImage64F(const int width
-                         ,const int height
-                         ,const int channels)
-{
- CvSize s;
- IplImage *r;
- s.width = width; s.height = height;
- r = cvCreateImage(s,IPL_DEPTH_64F,channels);
- cvSetZero(r);
- return r;
-}
-
-
-IplImage* wrapCreateImage8U(const int width
-                         ,const int height
-                         ,const int channels)
-{
- CvSize s;
- IplImage *r;
- s.width = width; s.height = height;
- r = cvCreateImage(s,IPL_DEPTH_8U,channels);
- cvSetZero(r);
- return r;
-}
-
-IplImage* composeMultiChannel(IplImage* img0
-                             ,IplImage* img1
-                             ,IplImage* img2
-                             ,IplImage* img3
-                             ,const int channels)
-{
- CvSize s;
- IplImage *r;
- s = cvGetSize(img0);
- r = cvCreateImage(s,img0->depth,channels);
- cvSetZero(r);
- cvMerge(img0,img1,img2,img3,r);
- return r;
-}
-void wrapSubRS(const CvArr *src, double s, CvArr *dst)
-{
- cvSubRS(src,cvRealScalar(s),dst,0);
-}
-
-void wrapSubS(const CvArr *src, double s, CvArr *dst)
-{
- cvSubS(src,cvRealScalar(s),dst,0);
-}
-
-void wrapAddS(const CvArr *src, double s, CvArr *dst)
-{
- cvAddS(src,cvRealScalar(s),dst,0);
-}
-
-void wrapAbsDiffS(const CvArr *src, double s, CvArr *dst)
-{
- cvAbsDiffS(src,dst,cvScalarAll(s));
-}
-
-double wrapAvg(const CvArr *src)
-{
- CvScalar avg = cvAvg(src,0);
- return avg.val[0];
-}
-
-double wrapStdDev(const CvArr *src)
-{
- CvScalar dev;
- cvAvgSdv(src,0,&dev,0);
- return dev.val[0];
-}
-
-double wrapStdDevMask(const CvArr *src,const CvArr *mask)
-{
- CvScalar dev;
- IplImage *mask8 = ensure8U(mask);
- cvAvgSdv(src,0,&dev,mask8);
- cvReleaseImage(&mask8); 
- return dev.val[0];
-}
-double wrapMeanMask(const CvArr *src,const CvArr *mask)
-{
- CvScalar mean;
- IplImage *mask8 = ensure8U(mask);
- cvAvgSdv(src,&mean,0,mask8);
- cvReleaseImage(&mask8); 
- return mean.val[0];
-}
-
-double wrapSum(const CvArr *src)
-{
- CvScalar sum = cvSum(src);
- return sum.val[0];
-}
-
-void wrapMinMax(const CvArr *src,const CvArr *mask
-               ,double *minVal, double *maxVal)
-{
- //cvMinMaxLoc(src,minVal,maxVal,NULL,NULL,NULL);
- int i,j;
- int minx,miny,maxx,maxy;
- double pixel;
- double maskP;
- int t;
- double min=100000,max=-100000; // Some problem with DBL_MIN.
-
- CvSize s = cvGetSize(src);
- for(i=0; i<s.width; i++)
-  for(j=0; j<s.height; j++)
-   {
-   pixel = cvGetReal2D(src,j,i);
-   maskP = mask != 0 ? cvGetReal2D(mask,j,i) : 1;
-   // TODO: Fix below.. 
-   min   = (maskP >0.5 ) && (pixel < min) ? pixel : min; 
-   max   = (maskP >0.5 ) && (pixel > max) ? pixel : max; 
-   }
- (*minVal) = min; (*maxVal) = max; 
-}
-
-void wrapSetImageROI(IplImage *i,int x, int y, int w, int h)
-{
- CvRect r = cvRect(x,y,w,h);
- cvSetImageROI(i,r);
-}
-
-
-// Return image that is IPL_DEPTH_8U version of 
-// given src
-IplImage* ensure8U(const IplImage *src)
-{
- CvSize size;
- IplImage *result;
- int channels = src->nChannels;
- int dstDepth = IPL_DEPTH_8U;
- size = cvGetSize(src);
- result = cvCreateImage(size,dstDepth,channels);
-
- switch(src->depth) {
-  case IPL_DEPTH_32F:
-  case IPL_DEPTH_64F:
-   cvConvertScale(src,result,255.0,0); // Scale the values to [0,255]
-   return result;
-  case IPL_DEPTH_8U:
-   cvConvertScale(src,result,1,0);
-   return result;
-  default:
-   printf("Cannot convert to floating image");
-   abort();
-   
- }
-}
-
-// Return image that is IPL_DEPTH_32F version of 
-// given src
-IplImage* ensure32F(const IplImage *src)
-{
- CvSize size;
- IplImage *result;
- int channels = src->nChannels;
- int dstDepth = IPL_DEPTH_32F;
- size = cvGetSize(src);
- result = cvCreateImage(size,dstDepth,channels);
-
- switch(src->depth) {
-  case IPL_DEPTH_32F:
-  case IPL_DEPTH_64F:
-   cvConvertScale(src,result,1,0); // Scale the values to [0,255]
-   return result;
-  case IPL_DEPTH_8U:
-  case IPL_DEPTH_8S:
-   cvConvertScale(src,result,1.0/255.0,0);
-   return result;
-  case IPL_DEPTH_16S:
-   cvConvertScale(src,result,1.0/65535.0,0);
-   return result;
-  case IPL_DEPTH_32S:
-   cvConvertScale(src,result,1.0/4294967295.0,0);
-   return result;
-  default:
-   printf("Cannot convert to floating image");
-   abort();
-   
- }
-}
-
-void wrapSet32F2D(CvArr *arr, int x, int y, double value)
-{ 
- cvSet2D(arr,x,y,cvRealScalar(value)); 
-}
-
-
-double wrapGet32F2D(CvArr *arr, int x, int y)
-{ 
- CvScalar r;
- r = cvGet2D(arr,x,y); 
- return r.val[0];
-}
-
-double wrapGet32F2DC(CvArr *arr, int x, int y,int c)
-{ 
- CvScalar r;
- r = cvGet2D(arr,x,y); 
- return r.val[c];
-}
-
-uint8_t wrapGet8U2DC(IplImage *arr, int x, int y,int c)
-{ 
- return UGETC(arr,c,y,x);
-}
-
-
-void wrapDrawCircle(CvArr *img, int x, int y, int radius, float r,float g,float b, int thickness)
-{
- cvCircle(img,cvPoint(x,y),radius,CV_RGB(r,g,b),thickness,8,0);
-}
-
-void wrapDrawText(CvArr *img, char *text, float s, int x, int y,float r,float g,float b)
-{
-CvFont font; //?
-cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, s, s, 0, 2, 8);
-cvPutText(img, text, cvPoint(x,y), &font, CV_RGB(r,g,b));
-}
-
-void wrapDrawRectangle(CvArr *img, int x1, int y1, 
-                       int x2, int y2, float r, float g, float b,
-                       int thickness)
-{
- cvRectangle(img,cvPoint(x1,y1),cvPoint(x2,y2),CV_RGB(r,g,b),thickness,8,0);
-}
-
-
-void wrapDrawLine(CvArr *img, int x, int y, int x1, int y1, double r, double g, double b, int thickness)
-{
- cvLine(img,cvPoint(x,y),cvPoint(x1,y1),CV_RGB(r,g,b),thickness,4,0);
-}
-
-void wrapFillPolygon(IplImage *img, int pc, int *xs, int *ys, float r, float g, float b)
-{ 
- int i=0;
- int pSizes[] = {pc};
- CvPoint *pts = (CvPoint*)malloc(pc*sizeof(CvPoint));
- for (i=0; i<pc; ++i)
-    {pts[i].x = xs[i]; 
-     pts[i].y = ys[i]; 
-     }
- cvFillPoly(img, &pts, pSizes, 1, CV_RGB(r,g,b), 8, 0 );
- free(pts);
-}
-
-
-
-int getImageWidth(IplImage *img)
-{
- return cvGetSize(img).width;
-}
-int getImageHeight(IplImage *img)
-{
- return cvGetSize(img).height;
-}
-
-IplImage* getSubImage(IplImage *img, int sx,int sy,int w,int h)
-{
- CvRect r;
- CvSize s;
- IplImage *newImage;
- 
- r.x = sx; r.y = sy;
- r.width = w; r.height = h;
- s.width = w; s.height = h;
- 
- cvSetImageROI(img,r);
- newImage = cvCreateImage(s,img->depth,img->nChannels);
- cvCopy(img, newImage,0);
- cvResetImageROI(img);
- return newImage;
-}
-
-IplImage* simpleMergeImages(IplImage *a, IplImage *b,int offset_x, int offset_y)
-{
- CvSize aSize = cvGetSize(a);
- CvSize bSize = cvGetSize(b);
- int startx = 0 < offset_x ? 0 : offset_x;
- int endx = aSize.width > bSize.width+offset_x ? aSize.width : bSize.width+offset_x ;
-
- int starty = 0 < offset_y ? 0 : offset_y;
- int endy = aSize.height > bSize.height+offset_y ? aSize.height : bSize.height+offset_y ;
-
- CvSize size;
- size.width  = endx-startx;
- size.height = endy-starty;
-
- CvRect aPos = cvRect(offset_x<0?-offset_x:0
-                     ,offset_y<0?-offset_y:0
-                     ,aSize.width
-                     ,aSize.height);
-
- CvRect bPos = cvRect(offset_x<0?0:offset_x
-                     ,offset_y<0?0:offset_y
-                     ,bSize.width
-                     ,bSize.height);
-
- IplImage *resultImage = cvCreateImage(size,a->depth,a->nChannels);
-
- // Blit the images into bigger result image using cvCopy
- cvSetImageROI(resultImage,aPos);
- cvCopy(a,resultImage,NULL);
- cvSetImageROI(resultImage,bPos);
- cvCopy(b,resultImage,NULL);
- cvResetImageROI(resultImage);
- return resultImage;
-}
-
-void blitImg(IplImage *a, IplImage *b,int offset_x, int offset_y)
-{
- CvSize bSize = cvGetSize(b);
- CvRect pos = cvRect(offset_x
-                    ,offset_y
-                    ,bSize.width
-                    ,bSize.height);
-
- // Blit the images b into a using cvCopy
- printf("Doing a blit\n"); fflush(stdout);
- cvSetImageROI(a,pos);
- cvCopy(b,a,NULL);
- cvResetImageROI(a);
- printf("Done!\n"); fflush(stdout);
-}
-
-IplImage* makeEvenDown(IplImage *src)
-{
- CvSize size = cvGetSize(src);
- int w = size.width-(size.width % 2);
- int h = size.height-(size.height % 2);
- IplImage *result = wrapCreateImage32F(w,h,1);    
- CvRect pos = cvRect(0
-                    ,0
-                    ,size.width
-                    ,size.height);
- // Blit the images b into a using cvCopy
- cvSetImageROI(src,pos);
- cvCopy(src,result,NULL);
- cvResetImageROI(result);
- return result;
-}
-
-IplImage* makeEvenUp(IplImage *src)
-{
- CvSize size = cvGetSize(src);
- int w = size.width+(size.width % 2);
- int h = size.height+(size.height % 2);
- int j;
- IplImage *result = wrapCreateImage32F(w,h,1);    
- CvRect pos = cvRect(0
-                    ,0
-                    ,size.width
-                    ,size.height);
- // Blit the images b into a using cvCopy
- cvSetImageROI(result,pos);
- cvCopy(src,result,NULL);
- cvResetImageROI(result);
- if (size.width % 2 == 1)
-      {for (j=0; j<=size.height; j++) {
-          FGET(result,size.width,j) = FGET(result,size.width-1,j); } }
- if (size.width % 2 == 1)
-      {for (j=0; j<=size.width; j++) {
-          FGET(result,j,(size.height)) = FGET(result,j,(size.height-1)); } }
- return result;
-}
-
-IplImage* padUp(IplImage *src,int right, int bottom)
-{
- CvSize size = cvGetSize(src);
- int w = size.width + (right  ? 1 : 0);
- int h = size.height+ (bottom ? 1 : 0);
- int j;
- IplImage *result = wrapCreateImage32F(w,h,1);    
- CvRect pos = cvRect(0
-                    ,0
-                    ,size.width
-                    ,size.height);
- // Blit the images b into a using cvCopy
- cvSetImageROI(result,pos);
- cvCopy(src,result,NULL);
- cvResetImageROI(result);
- if (right)
-      {for (j=0; j<=size.height; j++) {
-          FGET(result,size.width,j) = 2*FGET(result,size.width-1,j)
-                                       -FGET(result,size.width-2,j); } }
- if (bottom)
-      {for (j=0; j<=size.width; j++) {
-
-          FGET(result,j,(size.height)) = 2*FGET(result,j,(size.height-1))
-                                          -FGET(result,j,(size.height-2)); 
-                                          } }
- return result;
-}
-
-void masked_merge(IplImage *src1, IplImage *mask, IplImage *src2, IplImage *dst)
-{
- int i,j;
- CvSize size = cvGetSize(dst);
- for (i=0; i<size.width; i++)
-    for (j=0; j<size.height; j++) {
-       FGET(dst,i,j) =  FGET(src1,i,j)*FGET(mask,i,j) 
-                        +FGET(src2,i,j)*(1-FGET(mask,i,j));
-     }
-}
-
-void vertical_average(IplImage *src, IplImage *dst)
-{
- int i,j;
- double avg;
- CvSize size = cvGetSize(dst);
- for (i=0; i<size.width; i++) {
-    avg = 0;
-    for (j=0; j<size.height; j++) { avg += FGET(src,i,j); }
-    avg = avg / size.height;
-    for (j=0; j<size.height; j++) { FGET(dst,i,j) = avg; }
-    }
-}
-
-
-IplImage* fadedEdges(int w, int h, int edgeW) {
-    IplImage *result;
-    int i,j;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-           float dx = i < (h/2.0) ? i : h-i ;
-           float dy = j < (w/2.0) ? j : w-j ;
-           float x = dx > edgeW ? 1 : dx/edgeW;
-           float y = dy > edgeW ? 1 : dy/edgeW;
-           FGET(result,j,i) = x*y;
-           }
-    return result;
-}
-
-IplImage* rectangularDistance(int w, int h) {
-    IplImage *result;
-    int i,j;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-           float dx = i < (h/2.0) ? i/(h*1.0) : (h-i)/(h*1.0) ;
-           float dy = j < (w/2.0) ? j/(w*1.0) : (w-j)/(w*1.0) ;
-           FGET(result,j,i) = dx<dy?dx:dy;
-           }
-    return result;
-}
-IplImage* vignettingModelCos4(int w, int h) {
-    IplImage *result;
-    int i,j;
-    double nx,ny;
-    double r;
-    const double x0 = w/2.0;
-    const double y0 = h/2.0;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-            nx = (y0-i)/h;
-            ny = (x0-j)/w;
-            r = sqrt(nx*nx+ny*ny);
-            FGET(result,j,i) = pow(cos (r),4);
-           }
-    return result;
-}
-
-IplImage* vignettingModelCos4XCyl(int w, int h) {
-    IplImage *result;
-    int i,j;
-    double r;
-    const double x0 = w/2.0;
-    const double y0 = h/2.0;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-            r = fabs((i-y0)/y0) ;
-            FGET(result,j,i) = pow(cos (r),4);
-           }
-    return result;
-}
-
-IplImage* vignettingModelX2Cyl(int w, int h,double m, double s, double c) {
-    IplImage *result;
-    int i,j;
-    double r;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-            FGET(result,j,i) = -((i-c)*s)*((i-c)*s)-m;
-           }
-    return result;
-}
-inline double eucNorm(CvPoint2D64f p) {return (p.x*p.x+p.y*p.y);}
-
-IplImage* vignettingModelB3(int w, int h,double b1, double b2, double b3) {
-    IplImage *result;
-    int i,j;
-    double r;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-            CvPoint2D64f nor = toNormalizedCoords(cvSize(w,h),cvPoint(j,i));
-            r = eucNorm(nor);
-            FGET(result,j,i) = b3*pow(r,6)+b2*pow(r,4)+b3*pow(r,2)+1;
-           }
-    return result;
-}
-IplImage* vignettingModelP(int w, int h,double scalex, double scaley, double max) {
-    IplImage *result;
-    int i,j;
-    double r;
-    double mx = w/2.0;
-    double my = w/2.0;
-    result = wrapCreateImage32F(w,h,1);    
-    for (i=0; i<h; i++)
-       for (j=0; j<w; j++) {
-            FGET(result,j,i) =-((i-my)*scaley)*((i-my)*scaley)*((j-mx)*scalex)*((j-mx)*scalex)-max ;
-           }
-    return result;
-}
-
-IplImage* simplePerspective(double k,IplImage *src) {
-    IplImage *result;
-    int i,j;
-    double r;
-    result = cvCloneImage(src);    
-    int h = cvGetSize(src).height;
-    int w = cvGetSize(src).width;
-    CvPoint2D32f srcPts[4] = {{0,0},{w-1,0},{w-1,h-1},{0,h-1}};
-    CvPoint2D32f dstPts[4] = {{-k,0},{w-1+k,0},{w-1,h-1},{0,h-1}};
-    CvMat* M = cvCreateMat(3,3,CV_32FC1);
-    cvGetPerspectiveTransform(srcPts, dstPts, M);
-    cvWarpPerspective(src, result, M, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
-    cvReleaseMat(&M);
-    return result;
-}
-
-IplImage* wrapPerspective(IplImage* src, double a1, double a2, double a3
-                                       , double a4, double a5, double a6
-                                       , double a7, double a8, double a9)
-{
-    IplImage *res = cvCloneImage(src);
-    double a[] = { a1,a2,a3,
-                   a4,a5,a6,
-                   a7,a8,a9};
-
-    CvMat M = cvMat(3,3,CV_64FC1,a);
-    cvWarpPerspective(src, res, &M, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
-    return res;
-}
-
-void findHomography(double* srcPts, double *dstPts, int noPts, double *homography)
-{
-CvMat src = cvMat(noPts, 2, CV_64FC1, srcPts);
-CvMat dst = cvMat(noPts, 2, CV_64FC1, dstPts);
-CvMat *hmg = cvCreateMat(3,3,CV_32FC1);
-int i;
-cvFindHomography(&src, &dst, hmg, 0, 0, 0);
-for (i=0;i<3*3;++i)
-        homography[i] = cvmGet(hmg,i/3,i%3);
-cvReleaseMat(&hmg);
-}
-
-inline CvPoint2D64f toNormalizedCoords(CvSize area, CvPoint from)
-{
-    CvPoint2D64f res;
-    res.x = (from.x-area.width/2.0)/area.width;
-    res.y = (from.y-area.height/2.0)/area.height;   
-    return res;
-}
-
-inline CvPoint fromNormalizedCoords(CvSize area, CvPoint2D64f from)
-{
-    CvPoint res;
-    res.x = (from.x+0.5)*area.width;
-    res.y = (from.y+0.5)*area.height;   
-    return res;
-}
-
-inline CvPoint2D64f fromNormalizedCoords64f(CvSize area, CvPoint2D64f from)
-{
-    CvPoint2D64f res;
-    res.x = (from.x+0.5)*area.width;
-    res.y = (from.y+0.5)*area.height;   
-    return res;
-}
-
-void alphaBlit(IplImage *a, IplImage *aAlpha, IplImage *b, IplImage *bAlpha, int offset_y, int offset_x)
-{
-    // TODO: Add checks for image type and size
- int i,j;
- CvSize bSize = cvGetSize(b);
- CvSize aSize = cvGetSize(a);
- CvRect pos = cvRect(offset_x
-                    ,offset_y
-                    ,bSize.width
-                    ,bSize.height);
- for (i=0; i<bSize.height; i++)
-    for (j=0; j<bSize.width; j++) {
-       float aA, bA,fV;
-       if (j+offset_x>=aSize.width || i+offset_y>=aSize.height || i+offset_y < 0 || j+offset_x<0) continue;
-
-       aA = FGET(aAlpha,j+offset_x,i+offset_y);
-       bA = FGET(bAlpha,j,i);
-       fV = aA+bA > 0 ? (FGET(b,j,i)*bA+FGET(a,j+offset_x,i+offset_y)*aA)/(aA+bA) : FGET(b,j,i) ;
-       FGET(a,j+offset_x,i+offset_y) =fV;
-       FGET(aAlpha,j+offset_x,i+offset_y) =aA+bA;
-    }
-}
-
-
-void plainBlit(IplImage *a, IplImage *b, int offset_y, int offset_x)
-{
-    // TODO: Add checks for image type and size
- int i,j;
- CvSize aSize = cvGetSize(a);
- CvSize bSize = cvGetSize(b);
- for (i=0; i<bSize.height; i++) {
-    for (j=0; j<bSize.width; j++) {
-       if (j+offset_x<0 || j+offset_x>=aSize.width || i+offset_y<0 || i+offset_y>=aSize.height ) continue;
-       if (a->nChannels == 1) 
-            {FGET(a,j+offset_x,i+offset_y) =FGET(b,j,i);}
-        else if (a->nChannels ==3) 
-            {
-             int dx = j+offset_x; int dy = i+offset_y;
-             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 0] =
-              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 0] ; // B
-             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 1] =
-              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 1] ; // G
-             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 2] =
-              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 2] ; // R
-            }
-             else {printf("Can't blit this - pic weird number of channels\n"); abort();}
-
-    }}
-}
-
-void subpixel_blit(IplImage *a, IplImage *b, double offset_y, double offset_x)
-{
-    // TODO: Add checks for image type and size
- int i,j;
- CvSize aSize = cvGetSize(a);
- CvSize bSize = cvGetSize(b);
- for (i=0; i<aSize.height; i++)
-    for (j=0; j<aSize.width; j++) {
-       double x_at_b=j-offset_x;
-       double y_at_b=i-offset_y;
-       if (x_at_b <0 || x_at_b >= bSize.width
-           || y_at_b <0 || y_at_b >= bSize.height) continue;
-       FGET(a,j,i) =bilinearInterp(b,x_at_b,y_at_b);
-        // TODO: Check boundaries! #SAFETY
-
-    }
-}
-
-
-// Histograms.
-void wrapReleaseHist(CvHistogram *hist)
-{
- cvReleaseHist(&hist);
-}
-
-CvHistogram* calculateHistogram(IplImage *img,int bins)
-{
- float st_range[] = {-1,1};
- float *ranges[]  = {st_range};
- int hist_size[] = {bins};
- CvHistogram *result = cvCreateHist(1,hist_size,CV_HIST_ARRAY,ranges,1);
- cvCalcHist(&img,result,0,0);
- return result;
-}
-
-void get_histogram(IplImage *img,IplImage *mask
-                 ,float a, float b,int isCumulative
-                 ,int binCount
-                 ,double *values)
-{
- int i=0;
- float st_range[] = {a,b};
- float *ranges[]  = {st_range};
- int hist_size[] = {binCount};
- CvHistogram *result = cvCreateHist(1,hist_size,CV_HIST_ARRAY
-                                   ,ranges,1);
- cvCalcHist(&img,result,isCumulative,mask);
- for (i=0;i<binCount;++i)
-    {
-     *values = cvQueryHistValue_1D(result,i); values++;
-    }
- cvReleaseHist(&result);
- return;
-}
-
-
-double getHistValue(CvHistogram *h,int bin)
-{
- return *cvGetHistValue_1D(h,bin);
-}
-
-// Convolutions
-IplImage* wrapFilter2D(IplImage *src, int ax,int ay, 
-                    int w, int h, double *kernel){
-int i,j;
-IplImage *target = cvCloneImage(src);
-CvMat *kernelMat = cvCreateMat(w,h,CV_32FC1);
-for(i=0;i<w*h;i++)
-  cvSetReal2D(kernelMat,i%w,i/w,kernel[i]); 
-cvFilter2D(src,target,kernelMat,cvPoint(ay,ax));
-cvReleaseMat(&kernelMat);
-return target;
-}
-
-IplImage* wrapFilter2DImg(IplImage *src
-                         ,IplImage *mask
-                         ,int ax,int ay)
-{
-int i,j;
-IplImage *target = cvCloneImage(src);
-CvSize size = cvGetSize(mask);
-CvMat *kernelMat = cvCreateMat(size.width,size.height,CV_32FC1);
-for(i=0;i<size.width;i++)
- for(j=0;j<size.height;j++)
-  cvSetReal2D(kernelMat,i,j,cvGetReal2D(mask,j,i)); 
-cvFilter2D(src,target,kernelMat,cvPoint(ay,ax));
-cvReleaseMat(&kernelMat);
-return target;
-}
-
-// Connected components
-
-void wrapFloodFill(IplImage *i, int x, int y, double c
-                  ,double low, double high,int fixed)
-{
- int flag = 8 | (fixed ? CV_FLOODFILL_FIXED_RANGE : 0);
- cvFloodFill(i,cvPoint(x,y),cvRealScalar(c),cvRealScalar(low)
-            ,cvRealScalar(high),NULL,flag,NULL);
-}
-                  
-// hough-lines
-
-void wrapProbHoughLines(IplImage *img, double rho, double theta
-                       , int threshold, double minLength
-                       , double gapLength
-                       , int *maxLines
-                       , int *xs, int *ys
-                       , int *xs1, int *ys1)
-{
- IplImage *tmp;
- CvSeq *lines = 0;
- int i;
- CvMemStorage *storage = cvCreateMemStorage(0); 
- 
- tmp = ensure8U(img);
-
- lines = cvHoughLines2(tmp,storage,CV_HOUGH_PROBABILISTIC
-                     ,rho,theta,threshold,minLength,gapLength);
- for( i = 0; i < MIN(lines->total,*maxLines); i++ )
-        {
-            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
-            xs[i] = line[0].x; xs1[i] = line[1].x;
-            ys[i] = line[0].y; ys1[i] = line[1].y; 
-        }
- *maxLines = MIN(lines->total,*maxLines);
-
- cvReleaseImage(&tmp);
- cvReleaseMemStorage(&storage);
- 
-}
-                       
-
-
-//@-node:aleator.20050908100314.2:Wrappers
-//@+node:aleator.20050908100314.3:Utilities
-/* These are utilities that operate on opencv primitives but
-  are not really wrappers.. Due to the fact that I seem to
-  be incapable to link multiple objects including openCV
-  headers this seems to be the next best solution.
-
-  Watch out for name collisions!
-
-*/
-//@+node:aleator.20070906153003:Trigonometric operations
-
-void calculateAtan(IplImage *src, IplImage *dst)
-{
-  CvSize imageSize = cvGetSize(dst);
-  double r=0; int i; int j;
-  for(i=0; i<imageSize.width; ++i)
-    for(j=0; j<imageSize.height; ++j) {
-          r = cvGetReal2D(src,j,i);
-          cvSet2D(dst,j,i,cvScalarAll(atan(r)));
-    }
-}
-
-void calculateAtan2(IplImage *src1,IplImage *src2, IplImage *dst)
-{
-  CvSize imageSize = cvGetSize(dst);
-  for(int i=0; i<imageSize.width; ++i)
-    for(int j=0; j<imageSize.height; ++j) {
-          double a = FGET(src1,j,i);
-          double b = FGET(src2,j,i);
-          FGET(dst,j,i) = atan2(a,b);
-    }
-}
-
-//@nonl
-//@-node:aleator.20070906153003:Trigonometric operations
-//@+node:aleator.20051109111547:Pixel accessors
-// All these will work only on grayscale.
-inline int imax(int x, int y) {return (x>y) ? x:y;}
-inline int imin(int x, int y) {return (x<y) ? x:y;}
-inline double blurGet2D(IplImage *img,int x, int y)
-{
- CvSize size = cvGetSize(img);
- x = imax(0,imin(x,size.width-1));
- y = imax(0,imin(y,size.height-1));
-
- return cvGetReal2D(img,y,x);
-}
-
-//@-node:aleator.20051109111547:Pixel accessors
-//@+node:aleator.20070827150608:Haar Filters
-
-// Simple routines for calculating pixelwise
-// haar responses
-
-void haarFilter(IplImage *intImg, 
-                int x1, int y1, int x2, int y2,
-                IplImage *target)
-{
-  int i,j;
-  double s = 0;
-  double ratio = 1;
-  double desArea = (x2-x1)*(y1-y2);
-  double area = 0;
-  int rx1,rx2,ry1,ry2;
-  CvSize imageSize = cvGetSize(target);  
-  for(i=0; i<imageSize.width; ++i)
-    for(j=0; j<imageSize.height; ++j) {
-         rx1 = imax(0,imin(i+x1,imageSize.width-1));  
-         ry1 = imax(0,imin(j+y1,imageSize.height-1));
-         rx2 = imax(0,imin(i+x2,imageSize.width-1)); 
-         ry2 = imax(0,imin(j+y2,imageSize.height-1));
-         area = (float)((rx2-rx1)*(ry2-ry1));
-        // if (area > 0) ratio = fabs(desArea/area);
-        // else ratio=1;
-         //printf("Ratio(%d,%d) is %lf\n",rx1,ry1,ratio);
-         s = blurGet2D(intImg,rx1,ry1)
-             -blurGet2D(intImg,rx1,ry2)
-             -blurGet2D(intImg,rx2,ry1)
-             +blurGet2D(intImg,rx2,ry2);
-          cvSet2D(target,j,i,cvScalarAll(s/area));
-    }
-}
-
-double haar_at(IplImage *intImg, 
-                int x1, int y1, int w, int h)
-{
-  int i,j;
-  double s = 0;
-  s = blurGet2D(intImg,x1,y1)
-     -blurGet2D(intImg,x1,y1+h)
-     -blurGet2D(intImg,x1+w,y1)
-     +blurGet2D(intImg,x1+w,y1+h);
-  return s;
-}
-                
-//@nonl
-//@-node:aleator.20070827150608:Haar Filters
-//@+node:aleator.20070130144337:Statistics along a line
-#define SWAP(a,b) { \
-        int c = (a);    \
-        (a) = (b);      \
-        (b) = c;        \
-    }
-
-
-double average_of_line(int x0, int y0
-                     ,int x1, int y1
-                     ,IplImage *src) {
-     int steep = abs(y1 - y0) > abs(x1 - x0);
-     int deltax=0; int deltay=0;
-     int error=0;
-     int ystep=0;
-     int x=0; int y=0;
-     float sum=0; int len=0;
-
-     if (steep)   { SWAP(x0, y0); SWAP(x1, y1); }
-     if (x0 > x1) { SWAP(x0, x1); SWAP(y0, y1); }
-     deltax = x1 - x0;
-     deltay = abs(y1 - y0);
-     error  = 0;
-     y = y0;
-     if (y0 < y1) {ystep = 1;} else {ystep = -1;}
-     for (x=x0; x<x1; ++x) {
-         if (steep) {sum+=blurGet2D(src,y,x);
-                     ++len;} 
-                    // _plot(y,x);} 
-         else       {sum+=blurGet2D(src,x,y);
-                     ++len; } 
-                    //_plot(x,y);}
-         error = error + deltay;
-         if (2*error >= deltax) {
-             y = y + ystep;
-             error = error - deltax; }
-         }
-         return (sum/len);
-}
-
-//@-node:aleator.20070130144337:Statistics along a line
-//@+node:aleator.20051130130836:Taking square roots of images
-
-void sqrtImage(IplImage *src,IplImage *dst)
-{
-int i;int j;
-double result;
-CvSize size = cvGetSize(src);
-
-for(i=0;i<size.width;++i)
- for(j=0;j<size.height;++j)
-    {
-     result = cvSqrt(cvGetReal2D(src,j,i));
-     cvSetReal2D(dst,j,i,result);
-    }
-}
-//@-node:aleator.20051130130836:Taking square roots of images
-//@+node:aleator.20050930104348:Histogram Features
-#define HISTOGRAMSIZE 10
-
-double calculateMoment(int i,double arr[], int l)
-{
-int j=0;
-double result = 0;
-for(j=0; j<l; j++)
-  {  result += pow((j*1.0)/HISTOGRAMSIZE,i)*arr[j]; }
-return result;
-}
-
-double calculateAbsCentralMoment(int i,double arr[], int l)
-{
-int j=0;
-double m1 = calculateMoment(1,arr,l);
-double result = 0;
-for(j=0; j<l; j++)
- {
-  result += pow(fabs(((j*1.0)/HISTOGRAMSIZE)-m1),i)*arr[j];}
-return result;
-}
-
-double calculateCentralMoment(int i,double arr[], int l)
-{
-int j=0;
-double m1 = calculateMoment(1,arr, l);
-double result = 0;
-for(j=0; j<l; j++)
- {  
-    result += pow(((j*1.0)/HISTOGRAMSIZE)-m1,i)*arr[j];
-
- }
-return result;
-}
-//@+node:aleator.20050930104348.1:Central Moments
-
-IplImage* getNthCentralMoment(IplImage *src,int n, int w, int h)
-{
-
-CvSize size = cvGetSize(src);
-int iw = size.width-w;
-int ih = size.height-h;
-IplImage *target = wrapCreateImage32F(iw,ih,1);
-int x = 0;
-int y = 0;
-int i = 0;
-int j = 0;
-double histogram[HISTOGRAMSIZE]; 
-for (x=0; x<ih; x++)
- for (y=0; y<iw; y++)
- {
-memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
-double result = 0;
-
-// Calculate the local histogram
-for (i=0; i<w; i++)
- for (j=0; j<h; j++)
-    {
-     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
-     histogram[slot] += 1.0/(w*h*1.0);
-    }
-
-
-result = calculateCentralMoment(n,histogram,HISTOGRAMSIZE); 
-cvSet2D(target,x,y,cvScalarAll(result));
- }
-
-return target;
-}
-
-IplImage* getNthAbsCentralMoment(IplImage *src,int n, int w, int h)
-{
-
-CvSize size = cvGetSize(src);
-int iw = size.width-w;
-int ih = size.height-h;
-IplImage *target = wrapCreateImage32F(iw,ih,1);
-int x = 0;
-int y = 0;
-int i = 0;
-int j = 0;
-double histogram[HISTOGRAMSIZE]; 
-for (x=0; x<ih; x++)
- for (y=0; y<iw; y++)
- {
-memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
-double result = 0;
-
-// Calculate the local histogram
-for (i=0; i<w; i++)
- for (j=0; j<h; j++)
-    {
-     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
-     histogram[slot] += 1.0/(w*h*1.0);
-    }
-
-
-result = calculateAbsCentralMoment(n,histogram,HISTOGRAMSIZE); 
-cvSet2D(target,x,y,cvScalarAll(result));
- }
-
-return target;
-}
-
-IplImage* getNthMoment(IplImage *src,int n, int w, int h)
-{
-
-CvSize size = cvGetSize(src);
-int iw = size.width-w;
-int ih = size.height-h;
-IplImage *target = wrapCreateImage32F(iw,ih,1);
-int x = 0;
-int y = 0;
-int i = 0;
-int j = 0;
-double histogram[HISTOGRAMSIZE]; 
-for (x=0; x<ih; x++)
- for (y=0; y<iw; y++)
- {
-memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
-double result = 0;
-
-// Calculate the local histogram
-for (i=0; i<w; i++)
- for (j=0; j<h; j++)
-    {
-     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
-     histogram[slot] += 1.0/(w*h*1.0);
-    }
-
-result = calculateMoment(n,histogram,HISTOGRAMSIZE); 
-cvSet2D(target,x,y,cvScalarAll(result));
- }
-
-return target;
-}
-
-//@-node:aleator.20050930104348.1:Central Moments
-//@+node:aleator.20051103110155:SMAB
-   
-// Perform second moment adaptive binarization for a single pixel `x`
-// using given histogram.
-double max(double x,double y) {if (x<y) return y; else return x;}
-double min(double x,double y) {if (x>y) return y; else return x;}
-int SMABx(double x, CvHistogram *h,int binCount,double t)
-{
- int binnedX;  double leftSM=0;
- double rightSM=0;
- int i=0;
- binnedX = round(min(1,max(x,0))*(binCount-1));
-
- // Calculate left second moment:
- for(i=0; i<binnedX; i++)
-  { leftSM += pow(x - ((1.0*i)/(1.0*binCount)),2) * getHistValue(h,i); }
- for(i=binnedX; i<binCount; i++)
-  { rightSM += pow(x - ((1.0*i)/(1.0*binCount)),2) * getHistValue(h,i); }
- return (leftSM - (rightSM * t));
-}
-
-// Perform SMAB for image
-void smb(IplImage *image,double t)
-{
-int i;int j;
-double result;
-CvSize size = cvGetSize(image);
-CvHistogram *h = calculateHistogram(image,255);
-for(i=0;i<size.width;++i)
- for(j=0;j<size.height;++j)
- {
-     result = SMABx(cvGet2D(image,j,i).val[0],h,255,t);
-     cvSet2D(image,j,i,cvScalarAll(result));
- }
-}
-
-void smab(IplImage *image,int w, int h,double t)
-{
-int i;int j;
-int wi;int wj;
-double result;
-CvHistogram *histogram;
-CvRect roi;
-CvSize size = cvGetSize(image);
-roi.width = w;
-roi.height = h;
-
-for(i=0;i<size.width;++i)
- for(j=0;j<size.height;++j)
- {
-     roi.x = i-(w/2);
-     roi.y = j-(h/2);
-     cvSetImageROI(image,roi);
-     histogram = calculateHistogram(image,50);
-     cvResetImageROI(image);
-     result = SMABx(cvGetReal2D(image,j,i),histogram,50,t);
-     cvReleaseHist(&histogram);
-     cvSet2D(image,j,i,cvScalarAll(result));
- }
-}
-//@-node:aleator.20051103110155:SMAB
-//@+node:aleator.20051108093248:Skewness
-
-//@-node:aleator.20051108093248:Skewness
-//@-node:aleator.20050930104348:Histogram Features
-//@+node:aleator.20050926095227:Susan
-/* 
- Susan (Smallest Univalue Segmenting Nucleus) is 
- family of image processing methods, including
- edge preserving noise reduction.
-*/
-//@+node:aleator.20050926095227.1:Susan Smoothing Function
-
-/* 
- Calculate susan smoothing for `src` around `x`,`y` coordinates.
- `t` determines brightness treshold and sigma controls scale of
- spatial smoothing. `w` and `h` determine window size.
-*/
-
-inline double calcSusanSmooth(IplImage* src, int x, int y
-                      ,double t,double sigma,int w, int h)
-{
-
-int i = 0;
-int j = 0;
-
-long double numerator = 0;
-long double denominator = 0;
-for (i = 0; i<w; i++)
- for (j = 0; j<h; j++)
-    {
-    if (i==w/2 && j==h/2) continue;
-    double r2 = i*i+j*j;
-    double expFrac = (cvGet2D(src,x+i,y+j).val[0] 
-                     - cvGet2D(src,x,y).val[0]);
-    expFrac *= expFrac;
-
-    double exponential = exp(  (-r2/(2*sigma*sigma)) - (expFrac/(t*t))  );
-
-    numerator   += cvGet2D(src,x+i,y+j).val[0] * exponential;
-    denominator += exponential;
-    }
-return numerator/denominator;
-}
-//@-node:aleator.20050926095227.1:Susan Smoothing Function
-//@+node:aleator.20050926100856:Susan Smoothing
-
-IplImage* susanSmooth(IplImage *src, int w, int h
-                     ,double t, double sigma)
-
-{
-
-CvSize size = cvGetSize(src);
-int iw = size.width-w;
-int ih = size.height-h;
-IplImage *target = wrapCreateImage32F(iw,ih,1);
-int x = 0;
-int y = 0;
-double result = 0;
-
-
-for (x=0; x<iw; x++)
- for (y=0; y<ih; y++)
- {
-  result = calcSusanSmooth(src,y,x,t,sigma,h,w);
-  cvSet2D(target,y,x,cvScalarAll(result));
- }
-return target;
-}
-//@-node:aleator.20050926100856:Susan Smoothing
-//@+node:aleator.20050927083244:Susan Edge
-/* 
- Susan Edge Detector.
-*/
-
-// susan threshold function
-inline double susanC(double r, double r0,double t)
-{
- return exp(-((r-r0)/t));
-}
-
-inline double susanValue(IplImage *src,int x, int y
-                        ,int w, int h, double t)
-{
-int i; int j;
-double geometricTreshold = (3*(w*h)) / 4;
-double sum = 0;
-
-for (i = 0; i<w; i++)
- for (j = 0; j<h; j++)
-    {
-     sum += susanC(cvGet2D(src,x+i,y+j).val[0]
-                  ,cvGet2D(src,x,y).val[0]
-                  ,t);
-    }
-if (sum < geometricTreshold)
-    return geometricTreshold - sum;
-else return 0;
-}
-
-IplImage* susanEdge(IplImage *src,int w,int h,double t)
-{
-CvSize size = cvGetSize(src);
-int iw = size.width-w;
-int ih = size.height-h;
-IplImage *target = wrapCreateImage32F(iw,ih,1);
-int x = 0;
-int y = 0;
-double result = 0;
-
-
-for (x=0; x<iw; x++)
- for (y=0; y<ih; y++)
- {
-  result = susanValue(src,y,x,h,w,t);
-  cvSet2D(target,y,x,cvScalarAll(result));
- }
-return target;
-
-}
-//@-node:aleator.20050927083244:Susan Edge
-//@-node:aleator.20050926095227:Susan
-//@+node:aleator.20050908112008:Gabors
-/* 
- Gabor functions are modulated gaussians which bear some resemblance
- to human visual cortex neurons. */
-//@+node:aleator.20050908104238:gabor function in C
-/* This function calculates value of simple gabor function
-  at given x,y coordinates. Parameters for the gabor are:
-  
-  stdX  - standard deviation in oscillation direction
-  stdY  - standard deviation tangential to stdX
-  theta - angle (in radians) of the gabor
-  phase - phase of the gabor
-
-
-*/
-double calcGabor(double x, double y
-                ,double stdX, double stdY
-                ,double theta, double phase
-                ,double cycles)
-{
- double xth = x*cos(theta)  - y*sin(theta);
- double yth = x*sin(theta)  + y*cos(theta);
- double oscillationPart = cos(2*M_PI*xth/cycles+phase);
- double gaussianPart    = exp((-0.5*xth*xth)/(stdX*stdX))
-                         *exp((-0.5*yth*yth)/(stdY*stdY));
- 
- return gaussianPart * oscillationPart;
-}
-
-double calc1DGabor(double x
-                ,double sigma
-                ,double phase, double center
-                ,double cycles)
-{
- double oscillationPart = cos(2*M_PI*(x-center)/cycles+phase);
- double gaussianPart    = exp((-0.5*(x-center)*(x-center))
-                              /(sigma*sigma));
- 
- return gaussianPart * oscillationPart;
-}
-
-
-//@-node:aleator.20050908104238:gabor function in C
-//@+node:aleator.20050908112116:rendering gabors to arrays
-void renderGabor(CvArr *dst,int width, int height
-                ,double dx, double dy
-                ,double stdX, double stdY
-                ,double theta, double phase
-                ,double cycles)
-
-{
- int i,j;
- int mx = width/2;
- int my = height/2;
- for (i=0; i<width; i++)
-  for (j=0; j<height; j++) // TODO: This might be a bug
-   cvSet2D(dst,i,j,cvScalarAll(calcGabor(i-dx,j-dy,stdX,stdY
-                                        ,theta,phase,cycles)));
-}
-
-void render_gaussian(IplImage *dst
-                   ,double stdX, double stdY)
-
-{
- int i,j;
- double distX;
- double distY;
- CvSize size = cvGetSize(dst);
- double centerX = size.width/2.0;
- double centerY = size.height/2.0;
- for (i=0; i<size.width-1; i++)
-  for (j=0; j<size.height-1; j++)
-   { distX = ((centerX-i*1.0)*(centerX-i*1.0)) / (2*stdX*stdX);
-     distY = ((centerY-j*1.0)*(centerY-j*1.0)) / (2*stdY*stdY);
-  //   printf("w: %d, h: %d, i: %d, j:%d,dx: %e,dy: %e,exp:%e\n",size.width,size.height,i,j,distX,distY,exp(-distX-distY));
-     fflush(stdout);
-     cvSet2D(dst,j,i,cvScalarAll( exp(-distX-distY) ));
-  }
-}
-
-
-void renderRadialGabor(CvArr *dst,int width, int height
-                ,double sigma
-                ,double phase, double center
-                ,double cycles)
-
-{
- int i,j;
- int mx = width/2;
- int my = height/2;
- double rad = 0;
- for (i=0; i<width; i++)
-  for (j=0; j<width; j++)
-   {
-   rad = sqrt((i-mx)*(i-mx)+(j-my)*(j-my));
-   cvSet2D(dst,i,j,cvScalarAll(calc1DGabor(rad,sigma
-                                          ,phase,center,cycles)));
-   }
-}
-
-void wrapMinMaxLoc(const IplImage* target, int* minx, int* miny, int* maxx, int* maxy, double *minval, double *maxval)
-{
-	CvPoint maxPoint;
-	CvPoint minPoint;
-	cvMinMaxLoc(target,minval,maxval,&minPoint, &maxPoint, NULL);
-    *maxx = maxPoint.x ;
-    *maxy = maxPoint.y ;
-    *minx = minPoint.x ;
-    *miny = minPoint.y ;
-} 
-
-void simpleMatchTemplate(const IplImage* target, const IplImage* template, int* x, int* y, double *val,int type)
-{
-	int rw = cvGetSize(target).width-cvGetSize(template).width+1;
-	int rh = cvGetSize(target).height-cvGetSize(template).height+1;
-	IplImage* result = wrapCreateImage32F(rw,rh,1);
-	cvMatchTemplate(target,template,result,type);
-	double min,max;
-	CvPoint maxPoint;
-	maxPoint.x=-1;
-	maxPoint.y=-1;
-	min =0;
-	max =0;
-	cvMinMaxLoc(result,&min,&max,NULL, &maxPoint, NULL);
-	*x = maxPoint.x;+rw/2;
-	*y = maxPoint.y;+rh/2;
-	*val = max;
-	cvReleaseImage(&result);
-	} 
-
-IplImage* templateImage(const IplImage* target, const IplImage* template)
-{
-	int rw = cvGetSize(target).width-cvGetSize(template).width+1;
-	int rh = cvGetSize(target).height-cvGetSize(template).height+1;
-	IplImage* result = wrapCreateImage32F(rw,rh,1);
-	cvMatchTemplate(target,template,result,CV_TM_CCORR);
-	return result;
-	} 
-
-
-//@-node:aleator.20050908112116:rendering gabors to arrays
-//@+node:aleator.20050908101148:gabor filter using cvFilter2D
-void gaborFilter(const CvArr *src, CvArr *dst
-                ,int maskWidth, int maskHeight
-                ,double stdX, double stdY
-                ,double theta,double phase
-                ,double cycles)
-
-{
- int mx = maskWidth/2;
- int my = maskHeight/2;
- CvMat *kernel = cvCreateMat(maskWidth,maskHeight,CV_32F);
- renderGabor(kernel,maskWidth,maskHeight,mx,my,stdX,stdY
-             ,theta,phase,cycles);
- cvFilter2D(src,dst,kernel,cvPoint(-1,-1));
-}
-
-void radialGaborFilter(const CvArr *src, CvArr *dst
-                ,int maskWidth, int maskHeight
-                ,double sigma
-                ,double phase,double center
-                ,double cycles)
-
-{
- CvMat *kernel = cvCreateMat(maskWidth,maskHeight,CV_32F);
- renderRadialGabor(kernel,maskWidth,maskHeight,sigma
-               ,phase,center,cycles);
- cvFilter2D(src,dst,kernel,cvPoint(-1,-1));
-}
-
-
-//@-node:aleator.20050908101148:gabor filter using cvFilter2D
-//@-node:aleator.20050908112008:Gabors
-//@+node:aleator.20070511142414:Adaboost Learning
-// This doesn't really work properly yet.. No
-// time to do anything about it really.
-//@nonl
-//@+node:aleator.20070511142414.1:Fitness
-// In the following the class is encoded bit
-// differently. 0 is one class and +1 is another.
-// if target is gray it is considered null area.
-
-double adaFitness1(IplImage *target
-                 ,IplImage *weigths
-                 ,IplImage *test)
-{
-CvSize size = cvGetSize(target);
-int i,j;
-int width  = size.width;
-int height = size.height;
-double result=0;
-double tij=0,wij=0,testij=0,rij=0; 
-for (i=0; i<width; i++)
- for (j=0; j<height; j++)
- { 
-   tij = cvGetReal2D(target,j,i);
-   wij = cvGetReal2D(weigths,j,i);
-   testij = cvGetReal2D(test,j,i);
-   rij=wij;
-   if (((tij < 0.2) && (testij < 0.2)) || ((tij > 0.8) && (testij > 0.8))) 
-    {rij=0;} 
-   result += rij;
- }
- 
-return result;
-}
-//@-node:aleator.20070511142414.1:Fitness
-//@+node:aleator.20070511145251:Updating distributions
-
-// This function is used to update distribution.
-// Notice that alpha_t must be calculated separately
-// and normalization is not applied.
-IplImage* adaUpdateDistrImage(IplImage *target
-                          ,IplImage *weigths
-                          ,IplImage *test
-                          ,double at)
-{
-CvSize size = cvGetSize(target);
-int i,j;
-int width  = size.width;
-int height = size.height;
-double tij=0,wij=0,testij=0,rij=0; 
-IplImage *result = wrapCreateImage32F(width,height,1);
-for (i=0; i<width; i++)
- for (j=0; j<height; j++)
- { 
-   tij = cvGetReal2D(target,j,i);
-   wij = cvGetReal2D(weigths,j,i);
-   testij = cvGetReal2D(test,j,i);
-   if ( (tij>0.2) && (tij<0.8) ) continue;
-   if (((tij < 0.2) && (testij < 0.2)) 
-      || ((tij > 0.8) && (testij > 0.8))) 
-    {rij = wij*exp(-at);
-     cvSetReal2D(result,j,i,rij); }
-   else 
-    {rij = wij*exp(at);
-     cvSetReal2D(result,j,i,rij); }
- }
- 
-return result;
-}
-
-//@-node:aleator.20070511145251:Updating distributions
-//@-node:aleator.20070511142414:Adaboost Learning
-//@+node:aleator.20051207074905:LBP
-
-void get_weighted_histogram(IplImage *src, IplImage *weights, 
-                       double start, double end, 
-                       int bins, double *histo)
-{
-  int i,j,index;
-  double value,weight;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=0;i<bins;++i) histo[i]=0;
-  for(i=0; i<imageSize.width-1; ++i)
-    for(j=0; j<imageSize.height-1; ++j)
-        {
-         value = cvGetReal2D(src,j,i);
-         weight = cvGetReal2D(weights,j,i);
-         index = floor(bins*((value - start)/(end - start)));
-         //printf("Adding weight %e to index %d\n",weight,index);
-         if (index<0 || index>=bins) continue;
-         histo[index] += weight;
-        }
-  
-}
-
-// Calculate local binary pattern for image. 
-// LBP is outgoing array
-// of (preallocated) 256 bytes that are assumed to be 0.
-void localBinaryPattern(IplImage *src, int *LBP)
-{
-  int i,j;
-  int pattern = 0;
-  double center = 0;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=1; i<imageSize.width-1; ++i)
-    for(j=1; j<imageSize.height-1; ++j)
-        {
-         center = cvGetReal2D(src,j,i);
-
-         pattern += (blurGet2D(src,i-1,j-1) > center) *1;
-         pattern += (blurGet2D(src,i,j-1)   > center) *2;
-         pattern += (blurGet2D(src,i+1,j-1) > center) *4;
-         
-         pattern += (blurGet2D(src,i-1,j)   > center) *8;
-         pattern += (blurGet2D(src,i+1,j)   > center) *16;
-         
-         pattern += (blurGet2D(src,i-1,j+1) > center) *32;
-         pattern += (blurGet2D(src,i,j+1)   > center) *64;
-         pattern += (blurGet2D(src,i+1,j+1) > center) *128;
-         LBP[pattern]++;
-         pattern = 0;
-        }
-}
-
-void localBinaryPattern3(IplImage *src, int *LBP)
-{
-  int i,j;
-  int pattern = 0;
-  double center = 0;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=1; i<imageSize.width-1; ++i)
-    for(j=1; j<imageSize.height-1; ++j)
-        {
-         center = cvGetReal2D(src,j,i);
-
-         pattern += (blurGet2D(src,i-2,j-2) > center) *1;
-         pattern += (blurGet2D(src,i,j-3)   > center) *2;
-         pattern += (blurGet2D(src,i+2,j-2) > center) *4;
-         
-         pattern += (blurGet2D(src,i-3,j)   > center) *8;
-         pattern += (blurGet2D(src,i+3,j)   > center) *16;
-         
-         pattern += (blurGet2D(src,i-2,j+2) > center) *32;
-         pattern += (blurGet2D(src,i,j+3)   > center) *64;
-         pattern += (blurGet2D(src,i+2,j+2) > center) *128;
-         LBP[pattern]++;
-         pattern = 0;
-        }
-}
-void localBinaryPattern5(IplImage *src, int *LBP)
-{
-  int i,j;
-  int pattern = 0;
-  double center = 0;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=1; i<imageSize.width-1; ++i)
-    for(j=1; j<imageSize.height-1; ++j)
-        {
-         center = cvGetReal2D(src,j,i);
-
-         pattern += (blurGet2D(src,i-4,j-4) > center) *1;
-         pattern += (blurGet2D(src,i,j-5)   > center) *2;
-         pattern += (blurGet2D(src,i+4,j-4) > center) *4;
-         
-         pattern += (blurGet2D(src,i-5,j)   > center) *8;
-         pattern += (blurGet2D(src,i+5,j)   > center) *16;
-         
-         pattern += (blurGet2D(src,i-4,j+4) > center) *32;
-         pattern += (blurGet2D(src,i,j+5)   > center) *64;
-         pattern += (blurGet2D(src,i+4,j+4) > center) *128;
-         LBP[pattern]++;
-         pattern = 0;
-        }
-}
-
-void weighted_localBinaryPattern(IplImage *src,int offsetX,int offsetXY
-                                , IplImage* weights, double *LBP)
-{
-  int i,j;
-  int pattern = 0;
-  double center = 0;
-  double weight = 0;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=1; i<imageSize.width-1; ++i)
-    for(j=1; j<imageSize.height-1; ++j)
-        {
-         center = cvGetReal2D(src,j,i);
-         weight = cvGetReal2D(weights,j,i);
-
-         pattern += (blurGet2D(src,i-offsetXY,j-offsetXY) > center) *1;
-         pattern += (blurGet2D(src,i,j-offsetX)   > center) *2;
-         pattern += (blurGet2D(src,i+offsetXY,j-offsetXY) > center) *4;
-         
-         pattern += (blurGet2D(src,i-offsetX,j)   > center) *8;
-         pattern += (blurGet2D(src,i+offsetX,j)   > center) *16;
-         
-         pattern += (blurGet2D(src,i-offsetXY,j+offsetXY) > center) *32;
-         pattern += (blurGet2D(src,i,j+offsetX)   > center) *64;
-         pattern += (blurGet2D(src,i+offsetXY,j+offsetXY) > center) *128;
-         LBP[pattern] += weight;
-         pattern = 0;
-        }
-}
-
-void localHorizontalBinaryPattern(IplImage *src, int *LBP)
-{
-  int i,j;
-  int pattern = 0;
-  double center = 0;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=0; i<imageSize.width-1; ++i)
-    for(j=0; j<imageSize.height-1; ++j)
-        {
-         center = cvGetReal2D(src,j,i);
-
-         pattern += (blurGet2D(src,i-4,j) > center) *1;
-         pattern += (blurGet2D(src,i-3,j) > center) *2;
-         pattern += (blurGet2D(src,i-2,j) > center) *4;
-         pattern += (blurGet2D(src,i-1,j) > center) *8;
-         pattern += (blurGet2D(src,i+1,j) > center) *16;
-         pattern += (blurGet2D(src,i+2,j) > center) *32;
-         pattern += (blurGet2D(src,i+3,j) > center) *64;
-         pattern += (blurGet2D(src,i+4,j) > center) *128;
-         LBP[pattern]++;
-         pattern = 0;
-        }
-}
-
-void localVerticalBinaryPattern(IplImage *src, int *LBP)
-{
-  int i,j;
-  int pattern = 0;
-  double center = 0;
-  CvSize imageSize = cvGetSize(src);  
-  for(i=0; i<imageSize.width-1; ++i)
-    for(j=0; j<imageSize.height-1; ++j)
-        {
-         center = cvGetReal2D(src,j,i);
-
-         pattern += (blurGet2D(src,i,j-4) > center) *1;
-         pattern += (blurGet2D(src,i,j-3) > center) *2;
-         pattern += (blurGet2D(src,i,j-2) > center) *4;
-         pattern += (blurGet2D(src,i,j-1) > center) *8;
-         pattern += (blurGet2D(src,i,j+1) > center) *16;
-         pattern += (blurGet2D(src,i,j+2) > center) *32;
-         pattern += (blurGet2D(src,i,j+3) > center) *64;
-         pattern += (blurGet2D(src,i,j+4) > center) *128;
-         LBP[pattern]++;
-         pattern = 0;
-        }
-}
-
-
-//@-node:aleator.20051207074905:LBP
-//@+node:aleator.20051109102750:Selective Average
-// Assuming grayscale image calculate local selective average of point x y 
-inline double calcSelectiveAvg(IplImage *img,double t
-                                   ,int x, int y
-                                   ,int wwidth, int wheight)
-{
-int i,j;
-double accum=0; 
-double count=0;
-double centerValue; double processed=0;
-CvSize size = cvGetSize(img);
-centerValue = blurGet2D(img,x,y);
-
-for (i=-wwidth; i<wwidth;++i)
- for (j=-wheight; j<wheight;++j)
-  { 
-   if (  x+i<0 || x+i>=size.width
-      || y+j<0 || y+j>=size.height)
-      continue;
-      
-   processed = blurGet2D(img,x+i,y+j);
-   if (fabs(processed-centerValue)<t)
-        {accum+=processed;++count;}
-  }
-return accum/count;
-}
-
-
-IplImage* selectiveAvgFilter(IplImage *src,double t
-                            ,int wwidth, int wheight)
-{
-CvSize size = cvGetSize(src);
-int i,j;
-int width  = size.width;
-int height = size.height;
-double result;
-
-IplImage *target = wrapCreateImage32F(width,height,1);
-for (i=0; i<width; i++)
- for (j=0; j<height; j++)
- {
-  result = calcSelectiveAvg(src,t,i,j,wwidth,wheight);
-  cvSetReal2D(target,j,i,result);
- }
- 
-return target;
-}
-
-//@-node:aleator.20051109102750:Selective Average
-//@+node:aleator.20060104154125:AcquireImage
-
-// Copy array into single channel iplImage
-IplImage *acquireImageSlow(int w, int h, double *d)
-{
- IplImage *img;
- int i,j;
- img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
- for (i=0; i<h; i++) {
-   for (j=0; j<w; j++) { 
-         //printf("(%d,%d) => %d is %f\n",j,i,(i+j*h),d[i+j*h]);
-         FGET(img,j,i) = d[j*h+i]; 
-         }
-    }
- return img;
-}
-
-IplImage *acquireImageSlowF(int w, int h, float *d)
-{
- IplImage *img;
- int i,j;
- img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
- for (i=0; i<h; i++) {
-   for (j=0; j<w; j++) { 
-         //printf("(%d,%d) => %d is %f\n",j,i,(i+j*h),d[i+j*h]);
-         FGET(img,j,i) = d[j*h+i]; 
-         }
-    }
- return img;
-}
-
-#define BLUE = 0
-#define GREEN = 1
-#define RED = 2
-
-
-
-IplImage *acquireImageSlow8URGB(int w, int h, uint8_t *d)
-{
- IplImage *img;
- int i,j;
- img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,3);
- for (i=0; i<h; i++) {
-   for (j=0; j<w; j++) { 
-         UGETC(img,0,j,i) = *d; d++; 
-         UGETC(img,1,j,i) = *d; d++; 
-         UGETC(img,2,j,i) = *d; d++; 
-         }
-    }
- return img;
-}
-
-IplImage *acquireImageSlowComplex(int w, int h, complex double *d)
-{
- IplImage *img;
- int i,j;
- img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
- for (i=0; i<h; i++) {
-   for (j=0; j<w; j++) { 
-         FGET(img,j,i) = (float)(creal(d[j*h+i])); 
-         }
-    }
- return img;
-}
-
-void exportImageSlowComplex(IplImage *img, complex double *d)
-{
- int i,j;
- CvSize s= cvGetSize(img);
- for (i=0; i<s.height; i++) {
-   for (j=0; j<s.width; j++) { 
-         d[j*s.height+i] = (complex float)(FGET(img,j,i) + 0*I); 
-         }
-    }
-}
-
-void exportImageSlow(IplImage *img, double *d)
-{
- int i,j;
- CvSize s= cvGetSize(img);
- for (i=0; i<s.height; i++) {
-   for (j=0; j<s.width; j++) { 
-         d[j*s.height+i] = FGET(img,j,i); 
-         }
-    }
-}
-void exportImageSlowF(IplImage *img, float *d)
-{
- int i,j;
- CvSize s= cvGetSize(img);
- for (i=0; i<s.height; i++) {
-   for (j=0; j<s.width; j++) { 
-         d[j*s.height+i] = FGET(img,j,i); 
-         }
-    }
-}
-//@-node:aleator.20060104154125:AcquireImage
-//@-node:aleator.20050908100314.3:Utilities
-//@+node:aleator.20060413093124:Connected components
-//@+node:aleator.20071016114634:Contours
-
-
-void free_found_contours(FoundContours *f)
-{
- cvReleaseMemStorage(&(f->storage));
- free(f);
- 
-}
-
-int reset_contour(FoundContours *f)
-{ 
- f->contour = f->start;
-}
-
-int cur_contour_size(FoundContours *f)
-{ 
- return f->contour->total;
-}
-
-double contour_area(FoundContours *f)
-{ 
- return cvContourArea(f->contour,CV_WHOLE_SEQ,0);
-}
-
-CvMoments* contour_moments(FoundContours *f)
-{ 
- CvMoments* moments = (CvMoments*) malloc(sizeof(CvMoments));
- cvMoments(f->contour,moments,0);
- return moments;
-}
-
-double contour_perimeter(FoundContours *f)
-{ 
- return cvContourPerimeter(f->contour);
-}
-
-int more_contours(FoundContours *f)
-{ 
- if (f->contour != 0)
-  {return 1;}
-  {return 0;} // no more contours
-}
-
-int next_contour(FoundContours *f)
-{ 
- if (f->contour != 0)
-  {f->contour = f->contour->h_next; return 1;}
-  {return 0;} // no more contours
-}
-
-void contour_points(FoundContours *f, int *xs, int *ys)
-{
- if (f->contour==0) {printf("unavailable contour\n"); exit(1);}
- 
- CvPoint *pt=0;
- int total,i=0;
- total = f->contour->total;
- for (i=0; i<total;i++) 
-  {
-   pt = (CvPoint*)cvGetSeqElem(f->contour,i);
-   if (pt==0) {printf("point out of contour\n"); exit(1);}
-   xs[i] = pt->x;
-   ys[i] = pt->y;
-  } 
-    
-}
-
-void print_contour(FoundContours *fc)
-{
-  int i=0;
-  CvPoint *pt=0;
-   for (i=0; i<fc->contour->total;++i) 
-    {
-     pt = (CvPoint*)cvGetSeqElem(fc->contour,i);
-     printf("PT=%d,%d\n",pt->x,pt->y);
-    }
-}
-
-/* void draw_contour(FoundContours *fc,double color
-                 , IplImage *img, IplImage *dst)
-{
- cvDrawContours( dst, fc->start, color, color, -1, 0, 8
-               , cvPoint(0,0));
-} */
-
-
-FoundContours* get_contours(IplImage *src1)
-{
- CvSize size;
- IplImage *src = ensure8U(src1);
- //int dstDepth = IPL_DEPTH_8U;
- //size = cvGetSize(src1);
- //src = cvCreateImage(size,dstDepth,1);
- //cvCopy(src1,src,NULL);
- 
- 
- CvPoint* pt=0;
- int i=0;
- 
- CvMemStorage *storage=0;
- CvSeq *contour=0;
- FoundContours* result = (FoundContours*)malloc(sizeof(FoundContours));
- storage = cvCreateMemStorage(0);
-       
- cvFindContours( src,storage
-               , &contour
-               , sizeof(CvContour) 
-               ,CV_RETR_EXTERNAL 
-            //,CV_RETR_CCOMP 
-               ,CV_CHAIN_APPROX_NONE
-               ,cvPoint(0,0) );
-
-// result->contour = cvApproxPoly( result->contour, sizeof(CvContour)
-//                                , result->storage, CV_POLY_APPROX_DP
-//                                , 3, 1 );
- result->start = contour;
- result->contour = contour;
- result->storage = storage;
-
- cvReleaseImage(&src);
- return result;
-    
- }
-//@-node:aleator.20071016114634:Contours
-//@+node:aleator.20070814123008:moments
-CvMoments* getMoments(IplImage *src, int isBinary)
-{
- CvMoments* moments = (CvMoments*) malloc(sizeof(CvMoments));
- cvMoments( src, moments, isBinary);
- return moments;
-}
-
-void freeCvMoments(CvMoments *x)
-{
- free(x);
-}
-
-
-void getHuMoments(CvMoments *src,double *hu)
-{
- CvHuMoments* hu_moments = (CvHuMoments*) malloc(sizeof(CvHuMoments));
- cvGetHuMoments( src, hu_moments);
- *hu = hu_moments->hu1; ++hu;
- *hu = hu_moments->hu2; ++hu;
- *hu = hu_moments->hu3; ++hu;
- *hu = hu_moments->hu4; ++hu;
- *hu = hu_moments->hu5; ++hu;
- *hu = hu_moments->hu6; ++hu;
- *hu = hu_moments->hu7; 
- return;
-}
-
-void freeCvHuMoments(CvHuMoments *x)
-{
- free(x);
-}
-//@-node:aleator.20070814123008:moments
-//@+node:aleator.20060727102514:blobCount
-int blobCount(IplImage *src)
-{
-    int contourCount=0;
-    CvMemStorage* storage = cvCreateMemStorage(0);
-    CvSeq* contour = 0;
-
-    contourCount = cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
-
-    cvReleaseMemStorage(&storage);
-    return contourCount;
-}
-
-//@-node:aleator.20060727102514:blobCount
-//@+node:aleator.20060413093124.1:sizeFilter
-IplImage* sizeFilter(IplImage *src, double minSize, double maxSize)
-{
-    IplImage* dst = cvCreateImage( cvGetSize(src), IPL_DEPTH_32F, 1 );
-    CvMemStorage* storage = cvCreateMemStorage(0);
-    CvSeq* contour = 0;
-
-    cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
-    cvZero( dst );
-
-    for( ; contour != 0; contour = contour->h_next )
-    {
-        double area=fabs(cvContourArea(contour,CV_WHOLE_SEQ,0));
-        if (area <=minSize || area >= maxSize) continue;
-        CvScalar color = cvScalar(1,1,1,1);
-        cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8,
-            cvPoint(0,0));
-    }
-    cvReleaseMemStorage(&storage);
-    return dst;
-}
-//@-node:aleator.20060413093124.1:sizeFilter
-//@-node:aleator.20060413093124:Connected components
-//@+node:aleator.20050908101148.1:function for rotating image
-IplImage* rotateImage(IplImage* src,double scale,double angle)
-{
-
-  IplImage* dst = cvCloneImage( src );
-  angle = angle * (180 / CV_PI);
-  int w = src->width;
-  int h = src->height;
-  CvMat *M;
-  M = cvCreateMat(2,3,CV_32FC1);
-  CvPoint2D32f center = cvPoint2D32f(w/2.0,h/2.0);
-  CvMat *N = cv2DRotationMatrix(center,angle,scale,M);
-  cvWarpAffine( src, dst, N, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS
-              , cvScalarAll(0)); 
-  return dst;
-  cvReleaseMat(&M);
-}
-
-
-inline double cubicInterpolate(
-   double y0,double y1,
-   double y2,double y3,
-   double mu)
-{
-   double a0,a1,a2,a3,mu2;
-
-   mu2 = mu*mu;
-   a0 = y3 - y2 - y0 + y1;
-   a1 = y0 - y1 - a0;
-   a2 = y2 - y0;
-   a3 = y1;
-   return(a0*mu*mu2+a1*mu2+a2*mu+a3);
-}
-
-double bilinearInterp(IplImage *tex, double u, double v) {
-   CvSize s = cvGetSize(tex);
-   int x = floor(u);
-   int y = floor(v);
-   double u_ratio = u - x;
-   double v_ratio = v - y;
-   double u_opposite = 1 - u_ratio;
-   double v_opposite = 1 - v_ratio;
-   double result = ((x+1 >= s.width) || (y+1 >= s.height)) ? FGET(tex,x,y) :
-                   (FGET(tex,x,y)   * u_opposite  + FGET(tex,x+1,y)   * u_ratio) * v_opposite + 
-                   (FGET(tex,x,y+1) * u_opposite  + FGET(tex,x+1,y+1) * u_ratio) * v_ratio;
-   return result;
- }
-
-// TODO: Check boundaries! #SAFETY
-double bicubicInterp(IplImage *tex, double u, double v) {
-   CvSize s = cvGetSize(tex);
-   int x = floor(u);
-   int y = floor(v);
-   double u_ratio = u - x;
-   double v_ratio = v - y;
-   double p[4][4] = {FGET(tex,x-1,y-1),  FGET(tex,x,y-1),  FGET(tex,x+1,y-1),  FGET(tex,x+2,y-1),
-                     FGET(tex,x-1,y),    FGET(tex,x,y),    FGET(tex,x+1,y),    FGET(tex,x+2,y),
-                     FGET(tex,x-1,y+1),  FGET(tex,x,y+1),  FGET(tex,x+1,y+1),  FGET(tex,x+2,y+1),
-                     FGET(tex,x-1,y+2),  FGET(tex,x,y+2),  FGET(tex,x+1,y+2),  FGET(tex,x+2,y+2)
-                     };
-    double a00 = p[1][1];
-	double a01 = -p[1][0] + p[1][2];
-	double a02 = 2*p[1][0] - 2*p[1][1] + p[1][2] - p[1][3];
-	double a03 = -p[1][0] + p[1][1] - p[1][2] + p[1][3];
-	double a10 = -p[0][1] + p[2][1];
-	double a11 = p[0][0] - p[0][2] - p[2][0] + p[2][2];
-	double a12 = -2*p[0][0] + 2*p[0][1] - p[0][2] + p[0][3] + 2*p[2][0] - 2*p[2][1] 
-                 + p[2][2] - p[2][3];
-	double a13 = p[0][0] - p[0][1] + p[0][2] - p[0][3] - p[2][0] + p[2][1] - p[2][2] + p[2][3];
-	double a20 = 2*p[0][1] - 2*p[1][1] + p[2][1] - p[3][1];
-	double a21 = -2*p[0][0] + 2*p[0][2] + 2*p[1][0] - 2*p[1][2] - p[2][0] + p[2][2] 
-                 + p[3][0] - p[3][2];
-	double a22 = 4*p[0][0] - 4*p[0][1] + 2*p[0][2] - 2*p[0][3] - 4*p[1][0] + 4*p[1][1] 
-                 - 2*p[1][2] + 2*p[1][3] + 2*p[2][0] - 2*p[2][1] + p[2][2] - p[2][3] 
-                 - 2*p[3][0] + 2*p[3][1] - p[3][2] + p[3][3];
-	double a23 = -2*p[0][0] + 2*p[0][1] - 2*p[0][2] + 2*p[0][3] + 2*p[1][0] - 2*p[1][1] 
-                 + 2*p[1][2] - 2*p[1][3] - p[2][0] + p[2][1] - p[2][2] + p[2][3] + p[3][0] 
-                 - p[3][1] + p[3][2] - p[3][3];
-	double a30 = -p[0][1] + p[1][1] - p[2][1] + p[3][1];
-	double a31 = p[0][0] - p[0][2] - p[1][0] + p[1][2] + p[2][0] - p[2][2] - p[3][0] + p[3][2];
-	double a32 = -2*p[0][0] + 2*p[0][1] - p[0][2] + p[0][3] + 2*p[1][0] - 2*p[1][1] 
-                 + p[1][2] - p[1][3] - 2*p[2][0] + 2*p[2][1] - p[2][2] + p[2][3] + 2*p[3][0] 
-                 - 2*p[3][1] + p[3][2] - p[3][3];
-	double a33 = p[0][0] - p[0][1] + p[0][2] - p[0][3] - p[1][0] + p[1][1] - p[1][2] 
-                 + p[1][3] + p[2][0] - p[2][1] + p[2][2] - p[2][3] - p[3][0] + p[3][1] 
-                 - p[3][2] + p[3][3];
-
-	double x2 = u_ratio * u_ratio;
-	double x3 = x2 * u_ratio;
-	double y2 = v_ratio * v_ratio;
-	double y3 = y2 * v_ratio;
-
-	return a00 + a01 * v_ratio + a02 * y2 + a03 * y3 +
-	       a10 * u_ratio + a11 * u_ratio * v_ratio + a12 * u_ratio * y2 + a13 * u_ratio * y3 +
-	       a20 * x2 + a21 * x2 * v_ratio + a22 * x2 * y2 + a23 * x2 * y3 +
-	       a30 * x3 + a31 * x3 * v_ratio + a32 * x3 * y2 + a33 * x3 * y3;
- }
-
-void radialRemap(IplImage *source, IplImage *dest, double k)
-{
-    int i,j;
-    CvSize s = cvGetSize(dest);
-    double x,y,cx,cy,nx,ny,r2;
-    cx = s.width/2.0;
-    cy = s.height/2.0;
-    for (i=0; i<s.height; i++)
-       for (j=0; j<s.width; j++) {
-           nx = (j-cx)/s.width;
-           ny = (i-cy)/s.height;
-           r2 = nx*nx+ny*ny;
-           nx = nx*(1+k*r2);
-           ny = ny*(1+k*r2);
-           x = (nx+0.5)*s.width;
-           y = (ny+0.5)*s.height;
-           if (x<0 || x>=s.width || y<0 || y>=s.height) 
-            { FGET(dest,j,i) = 0; 
-             continue;}
-           FGET(dest,j,i) = bilinearInterp(source,x,y);
-           }
-
-
-}
-
-
-//@-node:aleator.20050908101148.1:function for rotating image
-//@+node:aleator.20051220091717:Matrix multiplication
-
-void wrapMatMul(int w, int h, double *mat
-               , double *vec, double *t)
-{
-
-CvMat matrix;
-CvMat vector;
-CvMat target;
-cvInitMatHeader(&matrix,w,h,CV_64FC1,mat,CV_AUTOSTEP);
-cvInitMatHeader(&vector,h,1,CV_64FC1,vec,CV_AUTOSTEP);
-cvInitMatHeader(&target,w,1,CV_64FC1,t,CV_AUTOSTEP);
-cvMatMul(&matrix,&vector,&target);
-}
-
-void maximal_covering_circle(int ox,int oy, double or, IplImage *distmap
-                            ,int *max_x, int *max_y, double *max_r)
-{
- double distance,radius;
-
- *max_x = ox;
- *max_y = oy;
- *max_r  = or;
-
- CvSize s = cvGetSize(distmap);
- for(int i=0; i<s.width; i++) // TODO: Limit with max_r
-  for(int j=0; j<s.height; j++)
-   {
-    distance = sqrt((i-ox)*(i-ox) + (j-oy)*(j-oy));
-    radius   = FGET(distmap,i,j);
-    if (radius > *max_r && radius >= or+distance )
-         { *max_x=i; *max_y=j; *max_r=radius;}
-   }
-}
-
-double juliaF(double a, double b,double x, double y) {
-     int limit = 1000;
-     double complex z;
-     int i=0;
-     double complex c;
-     double cr,ci;
-     c = a + b*I;
-     z = x+y*I;
-     for (i=0;i<limit;i++)
-        {
-         cr=creal(z); ci=cimag(i);
-         if (cr*cr+ci*ci>4) return (i*1.0)/limit;
-         z=z*z+c;
-        }
-    return 0;
-    }
-
-CvVideoWriter* wrapCreateVideoWriter(char *fn, int fourcc,
-                                     double fps,int w, int h,
-                                     int color) 
- {
-   CvVideoWriter *res = cvCreateVideoWriter(fn,CV_FOURCC('M','P','G','4'),fps,cvSize(w,h), color);
-   return res;
- }
-
-//@-node:aleator.20051220091717:Matrix multiplication
-//@-all
-//@-node:aleator.20050908100314:@thin cvWrapLEO.c
-//@-leo
diff --git a/CV/cvWrapLEO.h b/CV/cvWrapLEO.h
deleted file mode 100644
--- a/CV/cvWrapLEO.h
+++ /dev/null
@@ -1,282 +0,0 @@
-//@+leo-ver=4-thin
-//@+node:aleator.20050908101148.2:@thin cvWrapLEO.h
-//@@language c
-#ifndef __CVWRAP__
-#define __CVWRAP__
-
-#ifndef M_PI
-#define M_PI           3.14159265358979323846
-#endif
-
-#include <opencv/cv.h>
-#include <opencv/cxcore.h>
-#include <opencv/highgui.h>
-#include <complex.h>
-
-IplImage* wrapCreateImage32F(const int width, const int height, const int channels);
-IplImage* wrapCreateImage64F(const int width, const int height, const int channels);
-
-IplImage* wrapCreateImage8U(const int width, const int height, const int channels);
-
-void wrapSubRS(const CvArr *src, double s,CvArr *dst);
-void wrapSubS(const CvArr *src, double s,CvArr *dst);
-void wrapAddS(const CvArr *src, double s, CvArr *dst);
-
-double wrapAvg(const CvArr *src);
-double wrapStdDev(const CvArr *src);
-double wrapStdDevMask(const CvArr *src,const CvArr *mask);
-double wrapSum(const CvArr *src);
-void wrapMinMax(const CvArr *src,const CvArr *mask
-               ,double *minVal, double *maxVal);
-void wrapAbsDiffS(const CvArr *src, double s, CvArr *dst);
-
-void wrapSetImageROI(IplImage *i,int x, int y, int w, int h);
-
-IplImage* wrapSobel(IplImage *src,int dx
-                   ,int dy,int size);
-
-IplImage* wrapLaplace(IplImage *src,int size);
-
-IplImage* ensure8U(const IplImage *src);
-IplImage* ensure32F(const IplImage *src);
-
-void wrapSet32F2D(CvArr *arr, int x, int y, double value);
-double wrapGet32F2D(CvArr *arr, int x, int y);
-uint8_t wrapGet8U2DC(IplImage *arr, int x, int y,int c);
-
-void wrapDrawCircle(CvArr *img, int x, int y, int radius, float r,float g,float b, int thickness);
-
-void wrapDrawLine(CvArr *img, int x, int y, int x1, int y1, double r, double g, double b, int thickness);
-
-void wrapFillPolygon(IplImage *img, int pc, int *xs, int *ys, float r, float g, float b);
-
-void wrapMatMul(int w, int h, double *mat
-               , double *vec, double *t);
-
-// Utils. Place them in another file
-IplImage* rotateImage(IplImage* src,double scale,double angle);
-CvHistogram* calculateHistogram(IplImage *img,int bins);
-void wrapReleaseHist(CvHistogram *hist);
-double getHistValue(CvHistogram *h,int bin);
-void get_histogram(IplImage *img,IplImage *mask
-                 ,float a, float b,int isCumulative
-                 ,int binCount
-                 ,double *values);
-
-//void get_weighted_histogram(IplImage *img,IplImage *mask);
-//                 ,float a, float b
-//                 ,int binCount
-//                 ,double *values);
-
-IplImage* getSubImage(IplImage *img, int sx,int sy,int w,int h);
-int getImageHeight(IplImage *img);
-int getImageWidth(IplImage *img);
-
-
-IplImage* susanSmooth(IplImage *src, int w, int h
-                     ,double t, double sigma);
-
-IplImage* susanEdge(IplImage *src,int w,int h,double t);
-IplImage* getNthCentralMoment(IplImage *src, int n, int w, int h);
-IplImage* getNthAbsCentralMoment(IplImage *src, int n, int w, int h);
-IplImage* getNthMoment(IplImage *src, int n, int w, int h);
-
-double calcGabor(double x, double y
-                ,double stdX, double stdY
-                ,double theta, double phase
-                ,double cycles);
-
-void gaborFilter(const CvArr *src, CvArr *dst
-                ,int maskWidth, int maskHeight
-                ,double stdX, double stdY
-                ,double theta,double phase
-                ,double cycles);
-
-void radialGaborFilter(const CvArr *src, CvArr *dst
-                ,int maskWidth, int maskHeight
-                ,double sigma
-                ,double phase,double center
-                ,double cycles);
-
-void renderRadialGabor(CvArr *dst,int width, int height
-                ,double sigma
-                ,double phase, double center
-                ,double cycles);
-
-void render_gaussian(IplImage *dst
-                   ,double stdX, double stdY);
-
-void renderGabor(CvArr *dst,int width, int height
-                ,double dx, double dy
-                ,double stdX, double stdY
-                ,double theta, double phase
-                ,double cycles);
-
-void smb(IplImage *image,double t);
-void smab(IplImage *image,int w, int h,double t);
-
-IplImage* selectiveAvgFilter(IplImage *src,double t
-                            ,int wwidth, int wheight);
-
-IplImage* wrapFilter2D(IplImage *src, int ax,int ay, 
-                    int w, int h, double *kernel);
-IplImage* wrapFilter2DImg(IplImage *src
-                         ,IplImage *mask
-                         ,int ax,int ay);
-
-void wrapFloodFill(IplImage *i, int x, int y, double c
-                  ,double low, double high,int fixed);
-
-void sqrtImage(IplImage *src,IplImage *dst);
-
-void weighted_localBinaryPattern(IplImage *src,int offsetX,int offsetXY
-                                , IplImage* weights, double *LBP);
-
-void localBinaryPattern(IplImage *src, int *LBP);
-void localBinaryPattern3(IplImage *src, int *LBP);
-void localBinaryPattern5(IplImage *src, int *LBP);
-void localHorizontalBinaryPattern(IplImage *src, int *LBP);
-void localVerticalBinaryPattern(IplImage *src, int *LBP);
-
-void get_weighted_histogram(IplImage *src, IplImage *weights, 
-                       double start, double end, 
-                       int bins, double *histo);
-
-
-void eigenValsViaSVD(double *A, int size, double *eVals
-                    ,double *eVects);
-
-IplImage* sizeFilter(IplImage *src, double minSize, double maxSize);
-int blobCount(IplImage *src);
-
-
-IplImage *acquireImage(int w, int h, double *d);
-
-void wrapProbHoughLines(IplImage *img, double rho, double theta
-                       , int threshold, double minLength
-                       , double gapLength
-                       , int *maxLines
-                       , int *xs, int *ys
-                       , int *xs1, int *ys1);
-
-
-double average_of_line(int x0, int y0
-                     ,int x1, int y1
-                     ,IplImage *src);
-                     
-IplImage* adaUpdateDistrImage(IplImage *target
-                          ,IplImage *weigths
-                          ,IplImage *test
-                          ,double at);
-
-double adaFitness1(IplImage *target
-                 ,IplImage *weigths
-                 ,IplImage *test);
-           
-CvMoments* getMoments(IplImage *src, int isBinary);
-
-void freeCvMoments(CvMoments *x);
-
-void getHuMoments(CvMoments *src,double *hu);
-
-void freeCvHuMoments(CvHuMoments *x);
-
-void haarFilter(IplImage *intImg, 
-                int a, int b, int c, int d,
-                IplImage *target);
-
-double haar_at(IplImage *intImg, 
-                int x1, int y1, int w, int h);
-
-void wrapDrawRectangle(CvArr *img, int x1, int y1, 
-                       int x2, int y2, float r, float g, float b,
-                       int thickness);
-
-void calculateAtan(IplImage *src, IplImage *dst);
-void calculateAtan2(IplImage *src1,IplImage *src2, IplImage *dst);
-
-
-// Contours
-typedef struct {
-  CvMemStorage *storage;
-  CvSeq *contour;
-  CvSeq *start;
-  
-} FoundContours;
-
-CvMoments* contour_moments(FoundContours *f);
-void contour_points(FoundContours *f, int *xs, int *ys);
-CvMoments* contour_Moments(FoundContours *f);
-int cur_contour_size(FoundContours *f);
-double contour_area(FoundContours *f);
-double contour_perimeter(FoundContours *f);
-int more_contours(FoundContours *f);
-int next_contour(FoundContours *f);
-int reset_contour(FoundContours *f);
-void free_found_contours(FoundContours *f);
-void get_next_contour(FoundContours *fc);
-void print_contour(FoundContours *fc);
-FoundContours* get_contours(IplImage *src);
-
-double juliaF(double a, double b,double x, double y);
-void simpleMatchTemplate(const IplImage* target, const IplImage* template, int* x, int* y, double *val, int type);
-IplImage* templateImage(const IplImage* target, const IplImage* template);
-IplImage* simpleMergeImages(IplImage *a, IplImage *b,int offset_x, int offset_y);
-
-void alphaBlit(IplImage *a, IplImage *aAlpha, IplImage *b, IplImage *bAlpha, int offset_x, int offset_y);
-void blitImg(IplImage *a, IplImage *b,int offset_x, int offset_y);
-IplImage* fadedEdges(int w, int h, int edgeW);
-IplImage* rectangularDistance(int w, int h);
-void radialRemap(IplImage *source, IplImage *dest, double k);
-void plainBlit(IplImage *a, IplImage *b, int offset_y, int offset_x);
-void wrapMinMaxLoc(const IplImage* target, int* minx, int* miny, int* maxx, int* maxy, double *minval, double *maxval);
-void incrImageC(void);
-IplImage* vignettingModelCos4(int w, int h) ;
-IplImage* vignettingModelCos4XCyl(int w, int h) ;
-IplImage* vignettingModelX2Cyl(int w, int h,double m, double s, double c);
-void wrapDrawText(CvArr *img, char *text, float s, int x, int y,float r,float g,float b);
-
-IplImage* vignettingModelB3(int w, int h,double b1, double b2, double b3);
-inline CvPoint2D64f toNormalizedCoords(CvSize area, CvPoint from);
-inline CvPoint fromNormalizedCoords(CvSize area, CvPoint2D64f from);
-inline double eucNorm(CvPoint2D64f p);
-IplImage* vignettingModelP(int w, int h,double scalex, double scaley, double max);
-IplImage* wrapPerspective(IplImage* src, double a1, double a2, double a3
-                                       , double a4, double a5, double a6
-                                       , double a7, double a8, double a9);
-IplImage* simplePerspective(double k,IplImage *src);
-double bilinearInterp(IplImage *tex, double u, double v);
-inline CvPoint2D64f fromNormalizedCoords64f(CvSize area, CvPoint2D64f from);
-void findHomography(double* srcPts, double *dstPts, int noPts, double *homography);
-void masked_merge(IplImage *src1, IplImage *mask, IplImage *src2, IplImage *dst);
-IplImage* makeEvenUp(IplImage *src);
-IplImage* padUp(IplImage *src,int right, int bottom);
-IplImage* makeEvenDown(IplImage *src);
-void vertical_average(IplImage *src1, IplImage *dst);
-
-IplImage* composeMultiChannel(IplImage* img0
-                             ,IplImage* img1
-                             ,IplImage* img2
-                             ,IplImage* img3
-                             ,const int channels);
-
-IplImage *acquireImageSlow(int w, int h, double *d);
-IplImage *acquireImageSlowF(int w, int h, float *d);
-void exportImageSlow(IplImage *img, double *d);
-void exportImageSlowF(IplImage *img, float *d);
-
-IplImage *acquireImageSlowComplex(int w, int h, complex double *d);
-void exportImageSlowComplex(IplImage *img, complex double *d);
-void subpixel_blit(IplImage *a, IplImage *b, double offset_y, double offset_x);
-double bicubicInterp(IplImage *tex, double u, double v);
-
-CvVideoWriter* wrapCreateVideoWriter(char *fn, int fourcc, double fps,int w, int h, int color); 
-
-double wrapGet32F2DC(CvArr *arr, int x, int y,int c);
-void maximal_covering_circle(int ox,int oy, double or, IplImage *distmap
-                            ,int *max_x, int *max_y, double *max_r);
-
-
-#endif
-//@-node:aleator.20050908101148.2:@thin cvWrapLEO.h
-//@-leo
diff --git a/Utils/Function.hs b/Utils/Function.hs
new file mode 100644
--- /dev/null
+++ b/Utils/Function.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE PatternGuards #-}
+module Utils.Function where
+
+both f (x,y) = (f x, f y)
+
+with f = \x -> (x, f x)
+
+under a b = \x y -> a (b x y)
+
+-- Numerical functions
+
+affine1d (toA,toB) (fromA,fromB) x = x1
+    where
+     x0 = (x - toA)/(toB-toA)
+     x1 = x0*(fromB-fromA) + fromA
+
+mkFst f a = (f a, a)
+mkSnd f a = (a, f a)
+
+
+-- For Ord. Find a proper location for these
+
+minBy :: (a -> a -> Ordering) -> a -> a -> a
+minBy op a b | LT <- op a b = a
+             | EQ <- op a b = a
+             | GT <- op a b = b
+
+maxBy :: (a -> a -> Ordering) -> a -> a -> a
+maxBy op a b | LT <- op a b = b
+             | EQ <- op a b = a
+             | GT <- op a b = a
diff --git a/Utils/List.hs b/Utils/List.hs
new file mode 100644
--- /dev/null
+++ b/Utils/List.hs
@@ -0,0 +1,264 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Utils.List where
+
+import Data.List
+import Data.Function
+import Data.Maybe
+import Control.Arrow ((&&&))
+import qualified Data.Map as M
+import Test.QuickCheck
+
+
+-- | Group list into indevidual pairs: [1,2,3,4] => [(1,2),(3,4)]. 
+--   Works only with even number of elements
+pairs [] = []
+pairs [x] = error "Non-even list for pair function"
+pairs (x:y:xs) = (x,y):pairs xs
+
+-- | Undo pairs function
+fromPairs [] = []
+fromPairs ((x,y):xs) = x:y:fromPairs xs
+
+prop_pairsFromTo xs = even (length xs) ==> xs == fromPairs (pairs xs)
+
+-- | Group list into pairs: [1,2,3] => [(1,2),(2,3)]. 
+--   Works with non null lists
+
+pairs1 x = zip x (tail x)
+
+-- | Undo pairs1 function
+fromPairs1 [] = []
+fromPairs1 [(x,y)] = [x,y]
+fromPairs1 ((x,y):xs) = x:fromPairs1 (xs)
+
+prop_pairsFromTo1 xs = length xs > 1 ==> xs == fromPairs1 (pairs1 xs)
+
+crease op = map (uncurry op) . pairs1
+creaseM op = sequence . (crease op)
+
+ranks f xs = map fst $ rankBy f xs
+
+rankBy f xs = map (\(rank,(orig,val)) -> (rank,val))
+              . sortBy (compare`on`(fst.snd))
+              . zip [1..] 
+              . sortBy (f`on`snd) 
+              . zip [1..] 
+              $ xs
+
+clusterBy :: Ord b => (a -> b) -> [a] -> [[a]]
+clusterBy f = M.elems . M.map reverse . M.fromListWith (++)
+            . map (f &&& return)
+
+
+groupItems b a items = map ( (b . head) &&& map a) 
+                       . groupBy ((==)`on` b)
+                       . sortBy (comparing b) $ items 
+
+-- Assoc-list lookup with default value
+lookupDef d a lst = fromMaybe d $ lookup a lst
+
+-- get all consecutive pairs of a list: 
+--pairings "kissa"
+-- => [('k','i'),('i','s'),('s','s'),('s','a')]
+
+pairings [] = []
+pairings [x,y] = [(x,y)]
+pairings (x:y:ys) = (x,y):pairings (y:ys)
+
+-- Perform an operation for each in lst
+forEach fun lst = unfoldr op ([],lst)
+    where
+     op (start,[]) = Nothing
+     op (start,a:as) = Just (start++(fun a):as
+                            ,(start++[a],as)) 
+
+forPairs fun lst lst2 = map (map fst) 
+                         $ forEach (\(a,b)->(fun a b,b))
+                         $ zip lst lst2
+
+-- 
+replicateList n l = concat $ replicate n l
+--
+
+concatZipNub (a:as) (b:bs) 
+    | a == b = a:concatZipNub as bs
+    | a /= b = a:b:concatZipNub as bs                    
+concatZipNub [] _ = []
+concatZipNub _ [] = []
+
+histogram binWidth values = (map len grouped)
+    where
+     len x = (snap (head x), fromIntegral (length x)) 
+     min = minimum values
+     max = maximum values
+     grouped = group sorted
+     sorted = sort $ map snap values
+     snap x = binWidth*(fromIntegral $ floor (x/binWidth))
+
+binList binWidth op ivs = zip bins (map op values) 
+    where
+     values = map (map snd) grouped
+     bins = map (fst.head) grouped 
+     grouped = groupBy (\(a,_) (b,_) -> a == b ) sorted
+     sorted = sortBy (comparing fst) $ map snapIndex ivs
+     snapIndex (i,v) = (binWidth*(i`div`binWidth),v)
+     
+
+
+-- Map numeric list so it becomes zeromean
+zeroMean lst = map (\x -> x - mean) lst 
+    where mean = average lst
+
+-- Take n best elements according to fitnesses
+
+takeNAccordingTo n (fitnesses,elements) = 
+                take n
+              $ sortBy (comparing fst)
+              $ zip fitnesses elements
+
+-- Zip two lists by selection function
+select c = zipWith (\a b -> if c a b then a else b)
+
+-- Take half
+
+takeHalf lst = take (length lst `div` 2) lst
+
+splitToNParts n lst | n <= 0    = error "splitToNParts n <= 0"
+                    | otherwise = takeLengths (lengths (length lst) n) lst
+        where
+        lengths len n = zipWith (+) (replicate n (len`div`n)) (replicate (len`mod`n) 1++repeat 0)
+
+prop_splitEq n xs = n>0 ==> concat (splitToNParts n xs) == xs
+prop_splitLen n xs = n>0 && n<= (length xs) ==> length (splitToNParts n xs) == n
+
+-- Count elements that match predicate p
+count p = foldl (\sum i -> if p i then sum+1 else sum) 0 
+
+-- Count frequencies of elements in list
+frequencies lst = map (\x -> (head x,genericLength x)) $ group $ sort lst
+normalizeFrequencies ls = map (\(a,b) -> (a,b/sum (map snd ls))) ls
+-- Count average of list
+average s = sum s / (genericLength $ s) 
+
+-- Take n smallest given op
+smallestBy  op n lst = smallestBy' op n lst [] 
+smallestBy' op n [] o = o
+smallestBy' op n (i:input) [] = smallestBy' op n input [i]
+smallestBy' op n (i:input) output@(o:os) 
+     = smallestBy' op n input (take n $ insertBy op i output)
+-- (sloppily) Count median of list
+median s | odd len = sorted !! middle
+         | otherwise = ((sorted !! middle) + 
+                       (sorted !! (middle -1))) / 2
+    where
+     middle = len `div` 2
+     sorted = sort s
+     len = length s
+
+takeTail n lst = reverse $ take n $ reverse lst
+
+-- Count standard deviation of a list 
+stdDev l = sqrt (sum (map (\x -> (x - avg)^2) l)  
+                 / genericLength l)
+        where avg = average l
+
+-- Transform a list so that nth element is sum of n first elements
+cumulate [] = []
+cumulate values = tail $ scanl (+) 0 values
+
+schwartzianTransform :: (Ord a,Ord b) => (a -> b) -> [a] -> [a]
+schwartzianTransform f = map snd . sort . map (\x -> (f x, x))
+
+sortVia f = map snd . sortBy cmp . map (\x -> (f x , x))
+    where cmp (a1,a2) (b1,b2) = compare a1 b1
+
+comparing p a b = compare (p a) (p b)
+
+-- Pick element that has majority in the list
+majority lst = head $ maximumBy (comparing length) $ group $ sort lst
+
+-- Get all possible k-sized neighbourhoods in the list
+getKNeighbourhoods k p = get (length p) pknot
+    where 
+        pknot = p++pknot
+        get 0 p = []
+        get i p = take k p:get (i-1) (tail p)
+
+prop_headIdentical_KN n xs = 1 <= n && length xs >= 1 ==>
+                    map head (getKNeighbourhoods n xs)
+                    ==
+                    xs
+
+-- Split a list to `l` length pieces.
+splitToLength l lst = unfoldr split lst
+    where
+     split [] = Nothing
+     split lst = Just (take l lst, drop l lst) 
+
+-- Take n pieces of given lengths
+--takeLengths :: [Int] -> [a] -> [[a]]
+takeLengths [] lst = []
+takeLengths (l:ls) lst = take l lst:takeLengths ls (drop l lst) 
+
+prop_takeLen ls xs = all (>=0) ls &&  sum ls < length xs ==> length (takeLengths ls xs) == length ls
+prop_takeLens ls xs = all (>=0) ls &&  sum ls < length xs ==> map length (takeLengths ls xs) == ls
+
+-- From LicencedPreludeExts (hawiki)
+splitBy :: (a->Bool) -> [a] -> [[a]]
+splitBy _ [] = []
+splitBy f list =  first : splitBy f (dropWhile f rest)
+   where
+     (first, rest) = break f list
+
+--splitBetween :: ((a,a) -> Bool) -> [a] -> [[a]]
+splitBetween c acc [] = [reverse acc] 
+splitBetween c acc [a] = [reverse $ a:acc] 
+splitBetween c acc (a:b:cs) | c a b = (reverse $ a:acc):splitBetween c [] (b:cs)
+                            | otherwise = splitBetween c (a:acc) (b:cs)
+
+-- split list into subsets matching predicate
+tear op l = (filter (not.op) l, filter op l)
+
+swapEverywhere a b = concat $ zipWith merge (inits a) (tails a)
+    where
+     merge i [] = []
+     merge i (t:ts) = map (\x -> i++[x]++ts) b
+
+
+takeWhile2 op lst = reverse $ tw op [head lst] (tail lst)
+ where
+    tw _  l [] = []
+    tw op l (x:xs) = if op (head l) x 
+                              then tw op (x:l) xs
+                              else l
+
+applyMap val ops = map (\op -> op val) ops 
+applyMapM :: (Monad m) => a -> [a -> m b] -> m [b]
+applyMapM val ops = mapM (\op -> op val) ops 
+changesM :: (Monad m) => [a -> m b] -> a -> m [b]
+changesM = flip applyMapM
+
+rollList (a:xs) = xs ++[a]
+roll = rollList
+
+mergeList a b = a ++ drop (length a) b
+
+takeWhile1 test [] = []
+takeWhile1 test (x:xs) | test x = x:takeWhile1 test xs
+                       | otherwise =  [x]
+
+
+-- Modify each element in list with function that has knowledge of already
+-- modified elements
+editingMap f l = editingTrav f [] l
+
+editingTrav fun [] l@(x:xs) = editingTrav fun [(fun l x)] xs
+editingTrav fun a [] = reverse a
+editingTrav fun ss l@(x:xs) = editingTrav fun
+                                         (fun (reverse ss++l) x:ss)
+                                         xs
+
+
+-- Rotations of list
+rotate (x:xs) = xs++[x]
+cycles x = take (length x) $ iterate rotate x
diff --git a/Utils/Point.hs b/Utils/Point.hs
new file mode 100644
--- /dev/null
+++ b/Utils/Point.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
+module Utils.Point where
+
+type Pt a = (a,a)
+
+instance Num a => Num (Pt a) where
+    (x1,x2) + (y1,y2) = (x1+y1,x2+y2) 
+    (x1,x2) * (y1,y2) = (x1*y1,x2*y2) 
+    (x1,x2) - (y1,y2) = (x1-y1,x2-y2) 
+    negate (x1,x2) = (negate x1,negate x2) 
+    abs (x1,x2) = (abs x1, abs x2) -- Not really mathematical, but the type must be same
+    signum (x1,x2) = (signum x1, signum x2) -- Ditto
+    fromInteger x = (fromInteger x,fromInteger x) -- As well
+
+norm2 :: (Num a) => Pt a -> a
+norm2 (a,b) = a*a+b*b
+
+norm = sqrt . norm2
+
+(a,b) >/ (c,d) = (a `div` c, b `div` d)
diff --git a/Utils/Rectangle.hs b/Utils/Rectangle.hs
new file mode 100644
--- /dev/null
+++ b/Utils/Rectangle.hs
@@ -0,0 +1,120 @@
+module Utils.Rectangle where
+import Test.LazySmallCheck
+
+import Utils.Point
+import Control.DeepSeq
+
+newtype Rectangle a = Rectangle ((a,a),(a,a)) deriving (Eq,Show)
+
+a `s` b = rnf a `seq` b 
+
+instance (NFData a) => NFData (Rectangle a) where
+    rnf (Rectangle ((a,b),(c,d))) = (a `s` b `s` c `s` d) `seq` ()
+
+left   (Rectangle ((x,y),(w,h))) = x
+right  (Rectangle ((x,y),(w,h))) = x+w
+top    (Rectangle ((x,y),(w,h))) = y
+bottom (Rectangle ((x,y),(w,h))) = y+h
+topLeft  (Rectangle ((x,y),(w,h))) = (x,y)
+topRight (Rectangle ((x,y),(w,h))) = (x+w,y)  
+bottomLeft (Rectangle ((x,y),(w,h))) = (x,y+h)  
+bottomRight (Rectangle ((x,y),(w,h))) = (x+w,y+h)  
+vertices r = [topLeft r, topRight r, bottomLeft r, bottomRight r]
+rSize (Rectangle ((x,y),(w,h))) = (w,h)
+rArea r = let (w,h) = rSize r in (w*h)
+
+-- TODO: Add documentation #Cleanup
+
+instance (Num a, Ord a , Serial a) => Serial (Rectangle a) where
+    series = cons4 $ \a b c d -> mkRectangle (a,b) (c,d)
+
+-- | Create rectangle around point (x,y)
+around (x,y) (w,h) = mkRectangle (x', y') (w,h)
+    where (x',y') = (x-(w/2),y-(h/2))
+
+mkRectangle (x,y) (w,h) = Rectangle ((x-negW,y-negH),(abs w,abs h))
+    where
+     negH | h<0  = abs h
+          | h>=0 = 0
+     negW | w<0  = abs w
+          | w>=0 = 0
+
+mkRectCorners (x1,y1) (x2,y2) = Rectangle ((x,y),(w,h))
+ where
+    x = min x1 x2
+    y = min y1 y2
+    w = abs (x1-x2)
+    h = abs (y1-y2)
+
+prop_Corners :: (Int,Int) -> (Int,Int) -> Bool
+prop_Corners p w = mkRectCorners p (p+w) == mkRectangle p w
+
+mkRec = uncurry mkRectangle
+
+-- | Return rectangle r2 in coordinate system defined by r1
+inCoords r1 r2@(Rectangle (pos,size)) = Rectangle (pos-topLeft r1,size )
+
+-- | Return a point in coordinates of given rectangle
+inCoords' r1 pt = pt - topLeft r1
+
+-- | Adjust the size of the rectangle to be divisible by 2^n.
+enlargeToNthPower n (Rectangle ((x,y),(w,h))) = Rectangle ((x,y),(w2,h2))
+    where
+     (w2,h2) = (pad w, pad h)
+     pad x = x + (np - x `mod` np)
+     np = 2^n
+
+intersection r1 r2 
+    = mkRectCorners (max (left r1)   (left r2)
+                    ,max (top r1)    (top r2))
+                    (min (right r1)  (right r2)
+                    ,min (bottom r1) (bottom r2))
+
+propIntersectionArea r1 r2 
+    = (intersects r1 r2) 
+       ==> rArea (intersection r1 r2) <= rArea r1 &&
+           rArea (intersection r1 r2) <= rArea r2
+
+propIntersectionCommutes r1 r2 
+    = (intersects r1 r2) 
+       ==> (intersection r1 r2) == (intersection r2 r1) 
+
+intersects rect1 rect2 
+    = intersect1D (left rect1, right rect1) (left rect2, right rect2) && 
+      intersect1D (top rect1, bottom rect1) (top rect2, bottom rect2)
+
+contains a b = left a <= left b 
+                && top a <= top b 
+                && bottom a >= bottom b
+                && right a >= right b
+
+intersect1D (x,y) (u,w) = 
+    not $ (x < min u w && y < min u w) || (x > max u w && y > max u w) 
+
+prop_intersect1DCommutes a b 
+    = intersect1D  a b == intersect1D b a
+
+prop_intersectsCommutes sa@(_,(s1,s2)) sb@(b,(s3,s4)) 
+    = intersects (mkRec sa) (mkRec sb) == intersects (mkRec sb) (mkRec sa)
+
+-- | Create a tiling of a rectangles. 
+tile tilesize overlap r = [mkRectangle ((x,y)-overlap) tilesize 
+                          | x <- [startx,startx+fst tilesize..endx]
+                          , y <- [starty,starty+fst tilesize..endy] ]
+    where
+     startx = left r-fst overlap
+     starty = top  r-snd overlap
+     endx = right  r+fst overlap
+     endy = bottom r+snd overlap
+
+-- | Scale a rectangle
+scale (a,b) (Rectangle ((x,y),(s1,s2))) 
+    = mkRectangle (round (a*fromIntegral x),round (b*fromIntegral y))
+                  (round (a*fromIntegral s1),round (b*fromIntegral s2))
+
+
+toInt (Rectangle (p, s)) 
+    = Rectangle (both round p 
+                ,both round s)
+ where both f (a,b) = (f a , f b)
+
diff --git a/Utils/Stream.hs b/Utils/Stream.hs
new file mode 100644
--- /dev/null
+++ b/Utils/Stream.hs
@@ -0,0 +1,185 @@
+module Utils.Stream where
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans
+
+-- This module provides Monadic streams.
+
+-- | Stream of monadic values
+data Stream m a = Terminated | Value (m (a,Stream m a))
+
+-- | Attaching side effects
+sideEffect :: (Monad m) => (a -> m ()) -> Stream m a -> Stream m a
+sideEffect p Terminated = Terminated
+sideEffect p (Value next) = Value renext
+	where 
+	  renext = do
+                (r,n) <- next
+                p r
+                return (r,sideEffect p n)
+
+-- | Repeating stream
+listToStream [] = Terminated
+listToStream (l:lst) = Value (return (l,listToStream lst))
+repeatS x = Value (return (x,repeatS x))
+repeatSM x = sequenceS (repeatS x) 
+-- | Create a stream by iterating a monadic action
+iterateS op n = Value cont
+	where 
+         cont = do
+		 r <- op n
+		 return $ (n,iterateS op r) 
+
+-- | Pure and monadic left fold over a stream
+foldS op i Terminated = return i
+foldS op i (Value xs) = xs >>= \(x,xn) -> foldS op (op i x) xn
+
+foldSM op i Terminated = return i
+foldSM op i (Value xs) = xs >>= \(x,xn) -> op i x >>= \opix -> foldSM op opix xn
+
+-- | Merge two (time)streams
+time (a,_) = a
+value (_,a) = a
+mergeTimeStreams starta startb  a b = mergeE (starta,startb) (mergeS a b)
+mergeTimeStreamsWith sa sb op a b = fmap (\(t,(a,b)) -> (t,(op a b))) $ mergeTimeStreams sa sb a b
+mergeManyW starts op streams = snd $ foldl1 (\(s,m) (s1,n) -> ((op s s1),mergeTimeStreamsWith s s1 op m n)) (zip starts streams)
+
+mergeS Terminated _ = Terminated
+mergeS _ Terminated = Terminated
+mergeS _ Terminated = Terminated
+mergeS (Value xs) (Value ys) = Value renext
+    where
+        renext = do
+            (x,xn) <- xs
+            (y,yn) <- ys
+            case compare (time x) (time y) of
+                LT -> return (L x,mergeS xn (push y yn))
+                EQ -> return (B (time x,(value x,value y)),mergeS xn yn)
+                GT -> return (R y,mergeS (push x xn) yn)
+
+data LRB a b c = L a | B b |  R c  deriving (Show)
+
+mergeE _ Terminated = Terminated
+mergeE (l,r) (Value xs) = Value renext
+    where
+        renext = do
+                   (x,xn) <- xs
+                   case x of
+                    L (t,a) -> return ((t,(a,r)),mergeE (a,r) xn)
+                    B (t,(a,b)) -> return ((t,(a,b)),mergeE (a,b) xn)
+                    R (t,b) -> return ((t,(l,b)),mergeE (l,b) xn)
+
+push x Terminated = Value (return (x,Terminated))
+push x xs = Value (return (x,xs))
+ 
+
+-- | Map over a stream
+instance (Monad m) => Functor (Stream m) where
+    fmap _ Terminated   = Terminated
+    fmap f (Value next) = Value renext
+	where 
+	  renext = do
+		    (r,n) <- next
+		    return (f r,fmap f n)
+
+instance (Monad m) => Applicative (Stream m) where
+    pure f  = repeatS f
+    Terminated <*> _ = Terminated
+    _ <*> Terminated = Terminated
+    (Value a) <*> (Value b) = Value renext 
+      where 
+      renext = do
+        (fun,anext) <- a
+        (br,bnext)  <- b
+        return (fun br,anext<*>bnext)
+		
+zipS a b = (,) <$> a <*> b
+                
+--
+sequenceS :: (Monad m) => Stream m (m a) -> (Stream m a)
+sequenceS Terminated = Terminated
+sequenceS (Value next) = Value $ do
+			    (op,n) <- next
+			    r <- op	
+		            return (r,sequenceS n)
+
+mapMS :: (Monad m) => (a -> m b) -> Stream m a -> Stream m b
+mapMS op s = sequenceS . fmap op $ s
+
+-- |Drop elements from the stream. Due to stream structure, this operation cannot
+--  fail gracefully when dropping more elements than what is found in the stream
+dropS :: (Monad m) => Int -> Stream m a -> Stream m a
+dropS _ Terminated = Terminated
+dropS n next = Value renext
+	where
+         drop 0 s = return s
+         drop _ Terminated = return Terminated
+         drop n (Value next) =  do
+            (r,ne) <- next 
+            drop (n-1) ne
+         renext = do
+            r <- drop n next
+            case r of
+                Terminated -> error "Not enough elements to drop"
+                Value x -> x
+
+takeS :: (Monad m) => Int -> Stream m a -> Stream m a
+takeS _ Terminated = Terminated
+takeS n (Value next) = Value renext
+	where
+         renext = do
+		   (r,ne) <- next
+		   if n<1 then return (r,Terminated)
+		   	     else return (r,takeS (n-1) ne)
+
+takeWhileS _ Terminated = Terminated
+takeWhileS c (Value next) = Value renext
+	where
+         renext = do
+		   (r,ne) <- next
+		   if not . c $ r then return (r,Terminated)
+		   	      else return (r,takeWhileS c ne)
+
+consS a Terminated = Value (return (a, Terminated))
+consS a s  = Value (return (a, s))
+
+-- pairS is safe only for infinite streams
+pairS :: (Monad m) => Stream m a -> Stream m (a,a)
+pairS Terminated = Terminated
+pairS (Value next) = Value renext
+	where
+         renext = do
+            (val1,nexts2) <- next
+            case nexts2 of
+                Terminated    -> return (undefined,Terminated)
+                (Value next2) -> do (val2,next3) <- next2
+                                    return ((val1,val2),pairS (consS val2 next3))
+
+
+terminateOn :: (Monad m) => (a -> Bool) -> Stream m a -> Stream m a
+terminateOn cond Terminated = Terminated
+terminateOn cond (Value next) = Value renext
+	where
+         renext = do
+		   (r,n) <- next
+		   if cond r then return (r,Terminated)
+		   	     else return (r,terminateOn cond n)
+
+runStream Terminated  = return []
+runStream (Value s) = do
+			 (n,next) <- s
+			 r<-runStream next
+			 return (n:r)
+
+runStream_ Terminated  = return ()
+runStream_ (Value s) = do
+			 (n,next) <- s
+			 runStream_ next
+
+runLast l Terminated  = return l
+runLast l (Value s) = do
+   	 (n,next) <- s
+   	 runLast n next
+
+runLast1 s = runLast (error "Empty Stream") s
+			 
diff --git a/cbits/cvWrapLEO.c b/cbits/cvWrapLEO.c
new file mode 100644
--- /dev/null
+++ b/cbits/cvWrapLEO.c
@@ -0,0 +1,2344 @@
+//@+leo-ver=4-thin
+//@+node:aleator.20050908100314:@thin cvWrapLEO.c
+//@@language c
+
+//@+all
+//@+node:aleator.20050908100314.1:Includes
+#include "cvWrapLEO.h"
+#include <stdio.h>
+#include <complex.h>
+#include <stdint.h>
+
+//@-node:aleator.20050908100314.1:Includes
+//@+node:aleator.20050908100314.2:Wrappers
+
+#define FGET(img,x,y) (((float *)((img)->imageData + (y)*(img)->widthStep))[(x)])
+#define UGETC(img,color,x,y) (((uint8_t *)((img)->imageData + (y)*(img)->widthStep))[(x)*3+(color)])
+
+size_t images;
+
+void incrImageC(void)
+{
+ images++;
+}
+
+void wrapReleaseImage(IplImage *t)
+{
+ // printf("%d ",images);
+ cvReleaseImage(&t);
+ images--;
+}
+
+void wrapReleaseCapture(CvCapture *t)
+{
+ cvReleaseCapture(&t);
+}
+
+void wrapReleaseVideoWriter(CvCapture *t)
+{
+ cvReleaseCapture(&t);
+}
+
+void wrapReleaseStructuringElement(IplConvKernel *t)
+{
+ cvReleaseStructuringElement(&t);
+}
+
+IplImage* wrapLaplace(IplImage *src,int size)
+{
+IplImage *res;
+IplImage *tmp;
+tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
+res = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
+cvLaplace(src,tmp,size);
+cvConvertScale(tmp,res,1,0);
+return res;
+}
+
+IplImage* wrapSobel(IplImage *src,int dx
+                   ,int dy,int size)
+{
+IplImage *res;
+IplImage *tmp;
+tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
+res = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
+cvSobel(src,tmp,dx,dy,size);
+cvConvertScale(tmp,res,1,0);
+cvReleaseImage(&tmp);
+return res;
+}
+
+IplImage* wrapCreateImage32F(const int width
+                         ,const int height
+                         ,const int channels)
+{
+ CvSize s;
+ IplImage *r;
+ s.width = width; s.height = height;
+ r = cvCreateImage(s,IPL_DEPTH_32F,channels);
+ cvSetZero(r);
+ return r;
+}
+
+IplImage* wrapCreateImage64F(const int width
+                         ,const int height
+                         ,const int channels)
+{
+ CvSize s;
+ IplImage *r;
+ s.width = width; s.height = height;
+ r = cvCreateImage(s,IPL_DEPTH_64F,channels);
+ cvSetZero(r);
+ return r;
+}
+
+
+IplImage* wrapCreateImage8U(const int width
+                         ,const int height
+                         ,const int channels)
+{
+ CvSize s;
+ IplImage *r;
+ s.width = width; s.height = height;
+ r = cvCreateImage(s,IPL_DEPTH_8U,channels);
+ cvSetZero(r);
+ return r;
+}
+
+IplImage* composeMultiChannel(IplImage* img0
+                             ,IplImage* img1
+                             ,IplImage* img2
+                             ,IplImage* img3
+                             ,const int channels)
+{
+ CvSize s;
+ IplImage *r;
+ s = cvGetSize(img0);
+ r = cvCreateImage(s,img0->depth,channels);
+ cvSetZero(r);
+ cvMerge(img0,img1,img2,img3,r);
+ return r;
+}
+void wrapSubRS(const CvArr *src, double s, CvArr *dst)
+{
+ cvSubRS(src,cvRealScalar(s),dst,0);
+}
+
+void wrapSubS(const CvArr *src, double s, CvArr *dst)
+{
+ cvSubS(src,cvRealScalar(s),dst,0);
+}
+
+void wrapAddS(const CvArr *src, double s, CvArr *dst)
+{
+ cvAddS(src,cvRealScalar(s),dst,0);
+}
+
+void wrapAbsDiffS(const CvArr *src, double s, CvArr *dst)
+{
+ cvAbsDiffS(src,dst,cvScalarAll(s));
+}
+
+double wrapAvg(const CvArr *src)
+{
+ CvScalar avg = cvAvg(src,0);
+ return avg.val[0];
+}
+
+double wrapStdDev(const CvArr *src)
+{
+ CvScalar dev;
+ cvAvgSdv(src,0,&dev,0);
+ return dev.val[0];
+}
+
+double wrapStdDevMask(const CvArr *src,const CvArr *mask)
+{
+ CvScalar dev;
+ IplImage *mask8 = ensure8U(mask);
+ cvAvgSdv(src,0,&dev,mask8);
+ cvReleaseImage(&mask8); 
+ return dev.val[0];
+}
+double wrapMeanMask(const CvArr *src,const CvArr *mask)
+{
+ CvScalar mean;
+ IplImage *mask8 = ensure8U(mask);
+ cvAvgSdv(src,&mean,0,mask8);
+ cvReleaseImage(&mask8); 
+ return mean.val[0];
+}
+
+double wrapSum(const CvArr *src)
+{
+ CvScalar sum = cvSum(src);
+ return sum.val[0];
+}
+
+void wrapMinMax(const CvArr *src,const CvArr *mask
+               ,double *minVal, double *maxVal)
+{
+ //cvMinMaxLoc(src,minVal,maxVal,NULL,NULL,NULL);
+ int i,j;
+ int minx,miny,maxx,maxy;
+ double pixel;
+ double maskP;
+ int t;
+ double min=100000,max=-100000; // Some problem with DBL_MIN.
+
+ CvSize s = cvGetSize(src);
+ for(i=0; i<s.width; i++)
+  for(j=0; j<s.height; j++)
+   {
+   pixel = cvGetReal2D(src,j,i);
+   maskP = mask != 0 ? cvGetReal2D(mask,j,i) : 1;
+   // TODO: Fix below.. 
+   min   = (maskP >0.5 ) && (pixel < min) ? pixel : min; 
+   max   = (maskP >0.5 ) && (pixel > max) ? pixel : max; 
+   }
+ (*minVal) = min; (*maxVal) = max; 
+}
+
+void wrapSetImageROI(IplImage *i,int x, int y, int w, int h)
+{
+ CvRect r = cvRect(x,y,w,h);
+ cvSetImageROI(i,r);
+}
+
+
+// Return image that is IPL_DEPTH_8U version of 
+// given src
+IplImage* ensure8U(const IplImage *src)
+{
+ CvSize size;
+ IplImage *result;
+ int channels = src->nChannels;
+ int dstDepth = IPL_DEPTH_8U;
+ size = cvGetSize(src);
+ result = cvCreateImage(size,dstDepth,channels);
+
+ switch(src->depth) {
+  case IPL_DEPTH_32F:
+  case IPL_DEPTH_64F:
+   cvConvertScale(src,result,255.0,0); // Scale the values to [0,255]
+   return result;
+  case IPL_DEPTH_8U:
+   cvConvertScale(src,result,1,0);
+   return result;
+  default:
+   printf("Cannot convert to floating image");
+   abort();
+   
+ }
+}
+
+// Return image that is IPL_DEPTH_32F version of 
+// given src
+IplImage* ensure32F(const IplImage *src)
+{
+ CvSize size;
+ IplImage *result;
+ int channels = src->nChannels;
+ int dstDepth = IPL_DEPTH_32F;
+ size = cvGetSize(src);
+ result = cvCreateImage(size,dstDepth,channels);
+
+ switch(src->depth) {
+  case IPL_DEPTH_32F:
+  case IPL_DEPTH_64F:
+   cvConvertScale(src,result,1,0); // Scale the values to [0,255]
+   return result;
+  case IPL_DEPTH_8U:
+  case IPL_DEPTH_8S:
+   cvConvertScale(src,result,1.0/255.0,0);
+   return result;
+  case IPL_DEPTH_16S:
+   cvConvertScale(src,result,1.0/65535.0,0);
+   return result;
+  case IPL_DEPTH_32S:
+   cvConvertScale(src,result,1.0/4294967295.0,0);
+   return result;
+  default:
+   printf("Cannot convert to floating image");
+   abort();
+   
+ }
+}
+
+void wrapSet32F2D(CvArr *arr, int x, int y, double value)
+{ 
+ cvSet2D(arr,x,y,cvRealScalar(value)); 
+}
+
+
+double wrapGet32F2D(CvArr *arr, int x, int y)
+{ 
+ CvScalar r;
+ r = cvGet2D(arr,x,y); 
+ return r.val[0];
+}
+
+double wrapGet32F2DC(CvArr *arr, int x, int y,int c)
+{ 
+ CvScalar r;
+ r = cvGet2D(arr,x,y); 
+ return r.val[c];
+}
+
+uint8_t wrapGet8U2DC(IplImage *arr, int x, int y,int c)
+{ 
+ return UGETC(arr,c,y,x);
+}
+
+
+void wrapDrawCircle(CvArr *img, int x, int y, int radius, float r,float g,float b, int thickness)
+{
+ cvCircle(img,cvPoint(x,y),radius,CV_RGB(r,g,b),thickness,8,0);
+}
+
+void wrapDrawText(CvArr *img, char *text, float s, int x, int y,float r,float g,float b)
+{
+CvFont font; //?
+cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, s, s, 0, 2, 8);
+cvPutText(img, text, cvPoint(x,y), &font, CV_RGB(r,g,b));
+}
+
+void wrapDrawRectangle(CvArr *img, int x1, int y1, 
+                       int x2, int y2, float r, float g, float b,
+                       int thickness)
+{
+ cvRectangle(img,cvPoint(x1,y1),cvPoint(x2,y2),CV_RGB(r,g,b),thickness,8,0);
+}
+
+
+void wrapDrawLine(CvArr *img, int x, int y, int x1, int y1, double r, double g, double b, int thickness)
+{
+ cvLine(img,cvPoint(x,y),cvPoint(x1,y1),CV_RGB(r,g,b),thickness,4,0);
+}
+
+void wrapFillPolygon(IplImage *img, int pc, int *xs, int *ys, float r, float g, float b)
+{ 
+ int i=0;
+ int pSizes[] = {pc};
+ CvPoint *pts = (CvPoint*)malloc(pc*sizeof(CvPoint));
+ for (i=0; i<pc; ++i)
+    {pts[i].x = xs[i]; 
+     pts[i].y = ys[i]; 
+     }
+ cvFillPoly(img, &pts, pSizes, 1, CV_RGB(r,g,b), 8, 0 );
+ free(pts);
+}
+
+
+
+int getImageWidth(IplImage *img)
+{
+ return cvGetSize(img).width;
+}
+int getImageHeight(IplImage *img)
+{
+ return cvGetSize(img).height;
+}
+
+IplImage* getSubImage(IplImage *img, int sx,int sy,int w,int h)
+{
+ CvRect r;
+ CvSize s;
+ IplImage *newImage;
+ 
+ r.x = sx; r.y = sy;
+ r.width = w; r.height = h;
+ s.width = w; s.height = h;
+ 
+ cvSetImageROI(img,r);
+ newImage = cvCreateImage(s,img->depth,img->nChannels);
+ cvCopy(img, newImage,0);
+ cvResetImageROI(img);
+ return newImage;
+}
+
+IplImage* simpleMergeImages(IplImage *a, IplImage *b,int offset_x, int offset_y)
+{
+ CvSize aSize = cvGetSize(a);
+ CvSize bSize = cvGetSize(b);
+ int startx = 0 < offset_x ? 0 : offset_x;
+ int endx = aSize.width > bSize.width+offset_x ? aSize.width : bSize.width+offset_x ;
+
+ int starty = 0 < offset_y ? 0 : offset_y;
+ int endy = aSize.height > bSize.height+offset_y ? aSize.height : bSize.height+offset_y ;
+
+ CvSize size;
+ size.width  = endx-startx;
+ size.height = endy-starty;
+
+ CvRect aPos = cvRect(offset_x<0?-offset_x:0
+                     ,offset_y<0?-offset_y:0
+                     ,aSize.width
+                     ,aSize.height);
+
+ CvRect bPos = cvRect(offset_x<0?0:offset_x
+                     ,offset_y<0?0:offset_y
+                     ,bSize.width
+                     ,bSize.height);
+
+ IplImage *resultImage = cvCreateImage(size,a->depth,a->nChannels);
+
+ // Blit the images into bigger result image using cvCopy
+ cvSetImageROI(resultImage,aPos);
+ cvCopy(a,resultImage,NULL);
+ cvSetImageROI(resultImage,bPos);
+ cvCopy(b,resultImage,NULL);
+ cvResetImageROI(resultImage);
+ return resultImage;
+}
+
+void blitImg(IplImage *a, IplImage *b,int offset_x, int offset_y)
+{
+ CvSize bSize = cvGetSize(b);
+ CvRect pos = cvRect(offset_x
+                    ,offset_y
+                    ,bSize.width
+                    ,bSize.height);
+
+ // Blit the images b into a using cvCopy
+ printf("Doing a blit\n"); fflush(stdout);
+ cvSetImageROI(a,pos);
+ cvCopy(b,a,NULL);
+ cvResetImageROI(a);
+ printf("Done!\n"); fflush(stdout);
+}
+
+IplImage* makeEvenDown(IplImage *src)
+{
+ CvSize size = cvGetSize(src);
+ int w = size.width-(size.width % 2);
+ int h = size.height-(size.height % 2);
+ IplImage *result = wrapCreateImage32F(w,h,1);    
+ CvRect pos = cvRect(0
+                    ,0
+                    ,size.width
+                    ,size.height);
+ // Blit the images b into a using cvCopy
+ cvSetImageROI(src,pos);
+ cvCopy(src,result,NULL);
+ cvResetImageROI(result);
+ return result;
+}
+
+IplImage* makeEvenUp(IplImage *src)
+{
+ CvSize size = cvGetSize(src);
+ int w = size.width+(size.width % 2);
+ int h = size.height+(size.height % 2);
+ int j;
+ IplImage *result = wrapCreateImage32F(w,h,1);    
+ CvRect pos = cvRect(0
+                    ,0
+                    ,size.width
+                    ,size.height);
+ // Blit the images b into a using cvCopy
+ cvSetImageROI(result,pos);
+ cvCopy(src,result,NULL);
+ cvResetImageROI(result);
+ if (size.width % 2 == 1)
+      {for (j=0; j<=size.height; j++) {
+          FGET(result,size.width,j) = FGET(result,size.width-1,j); } }
+ if (size.width % 2 == 1)
+      {for (j=0; j<=size.width; j++) {
+          FGET(result,j,(size.height)) = FGET(result,j,(size.height-1)); } }
+ return result;
+}
+
+IplImage* padUp(IplImage *src,int right, int bottom)
+{
+ CvSize size = cvGetSize(src);
+ int w = size.width + (right  ? 1 : 0);
+ int h = size.height+ (bottom ? 1 : 0);
+ int j;
+ IplImage *result = wrapCreateImage32F(w,h,1);    
+ CvRect pos = cvRect(0
+                    ,0
+                    ,size.width
+                    ,size.height);
+ // Blit the images b into a using cvCopy
+ cvSetImageROI(result,pos);
+ cvCopy(src,result,NULL);
+ cvResetImageROI(result);
+ if (right)
+      {for (j=0; j<=size.height; j++) {
+          FGET(result,size.width,j) = 2*FGET(result,size.width-1,j)
+                                       -FGET(result,size.width-2,j); } }
+ if (bottom)
+      {for (j=0; j<=size.width; j++) {
+
+          FGET(result,j,(size.height)) = 2*FGET(result,j,(size.height-1))
+                                          -FGET(result,j,(size.height-2)); 
+                                          } }
+ return result;
+}
+
+void masked_merge(IplImage *src1, IplImage *mask, IplImage *src2, IplImage *dst)
+{
+ int i,j;
+ CvSize size = cvGetSize(dst);
+ for (i=0; i<size.width; i++)
+    for (j=0; j<size.height; j++) {
+       FGET(dst,i,j) =  FGET(src1,i,j)*FGET(mask,i,j) 
+                        +FGET(src2,i,j)*(1-FGET(mask,i,j));
+     }
+}
+
+void vertical_average(IplImage *src, IplImage *dst)
+{
+ int i,j;
+ double avg;
+ CvSize size = cvGetSize(dst);
+ for (i=0; i<size.width; i++) {
+    avg = 0;
+    for (j=0; j<size.height; j++) { avg += FGET(src,i,j); }
+    avg = avg / size.height;
+    for (j=0; j<size.height; j++) { FGET(dst,i,j) = avg; }
+    }
+}
+
+
+IplImage* fadedEdges(int w, int h, int edgeW) {
+    IplImage *result;
+    int i,j;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+           float dx = i < (h/2.0) ? i : h-i ;
+           float dy = j < (w/2.0) ? j : w-j ;
+           float x = dx > edgeW ? 1 : dx/edgeW;
+           float y = dy > edgeW ? 1 : dy/edgeW;
+           FGET(result,j,i) = x*y;
+           }
+    return result;
+}
+
+IplImage* rectangularDistance(int w, int h) {
+    IplImage *result;
+    int i,j;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+           float dx = i < (h/2.0) ? i/(h*1.0) : (h-i)/(h*1.0) ;
+           float dy = j < (w/2.0) ? j/(w*1.0) : (w-j)/(w*1.0) ;
+           FGET(result,j,i) = dx<dy?dx:dy;
+           }
+    return result;
+}
+IplImage* vignettingModelCos4(int w, int h) {
+    IplImage *result;
+    int i,j;
+    double nx,ny;
+    double r;
+    const double x0 = w/2.0;
+    const double y0 = h/2.0;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+            nx = (y0-i)/h;
+            ny = (x0-j)/w;
+            r = sqrt(nx*nx+ny*ny);
+            FGET(result,j,i) = pow(cos (r),4);
+           }
+    return result;
+}
+
+IplImage* vignettingModelCos4XCyl(int w, int h) {
+    IplImage *result;
+    int i,j;
+    double r;
+    const double x0 = w/2.0;
+    const double y0 = h/2.0;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+            r = fabs((i-y0)/y0) ;
+            FGET(result,j,i) = pow(cos (r),4);
+           }
+    return result;
+}
+
+IplImage* vignettingModelX2Cyl(int w, int h,double m, double s, double c) {
+    IplImage *result;
+    int i,j;
+    double r;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+            FGET(result,j,i) = -((i-c)*s)*((i-c)*s)-m;
+           }
+    return result;
+}
+inline double eucNorm(CvPoint2D64f p) {return (p.x*p.x+p.y*p.y);}
+
+IplImage* vignettingModelB3(int w, int h,double b1, double b2, double b3) {
+    IplImage *result;
+    int i,j;
+    double r;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+            CvPoint2D64f nor = toNormalizedCoords(cvSize(w,h),cvPoint(j,i));
+            r = eucNorm(nor);
+            FGET(result,j,i) = b3*pow(r,6)+b2*pow(r,4)+b3*pow(r,2)+1;
+           }
+    return result;
+}
+IplImage* vignettingModelP(int w, int h,double scalex, double scaley, double max) {
+    IplImage *result;
+    int i,j;
+    double r;
+    double mx = w/2.0;
+    double my = w/2.0;
+    result = wrapCreateImage32F(w,h,1);    
+    for (i=0; i<h; i++)
+       for (j=0; j<w; j++) {
+            FGET(result,j,i) =-((i-my)*scaley)*((i-my)*scaley)*((j-mx)*scalex)*((j-mx)*scalex)-max ;
+           }
+    return result;
+}
+
+IplImage* simplePerspective(double k,IplImage *src) {
+    IplImage *result;
+    int i,j;
+    double r;
+    result = cvCloneImage(src);    
+    int h = cvGetSize(src).height;
+    int w = cvGetSize(src).width;
+    CvPoint2D32f srcPts[4] = {{0,0},{w-1,0},{w-1,h-1},{0,h-1}};
+    CvPoint2D32f dstPts[4] = {{-k,0},{w-1+k,0},{w-1,h-1},{0,h-1}};
+    CvMat* M = cvCreateMat(3,3,CV_32FC1);
+    cvGetPerspectiveTransform(srcPts, dstPts, M);
+    cvWarpPerspective(src, result, M, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
+    cvReleaseMat(&M);
+    return result;
+}
+
+IplImage* wrapPerspective(IplImage* src, double a1, double a2, double a3
+                                       , double a4, double a5, double a6
+                                       , double a7, double a8, double a9)
+{
+    IplImage *res = cvCloneImage(src);
+    double a[] = { a1,a2,a3,
+                   a4,a5,a6,
+                   a7,a8,a9};
+
+    CvMat M = cvMat(3,3,CV_64FC1,a);
+    cvWarpPerspective(src, res, &M, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
+    return res;
+}
+
+void findHomography(double* srcPts, double *dstPts, int noPts, double *homography)
+{
+CvMat src = cvMat(noPts, 2, CV_64FC1, srcPts);
+CvMat dst = cvMat(noPts, 2, CV_64FC1, dstPts);
+CvMat *hmg = cvCreateMat(3,3,CV_32FC1);
+int i;
+cvFindHomography(&src, &dst, hmg, 0, 0, 0);
+for (i=0;i<3*3;++i)
+        homography[i] = cvmGet(hmg,i/3,i%3);
+cvReleaseMat(&hmg);
+}
+
+inline CvPoint2D64f toNormalizedCoords(CvSize area, CvPoint from)
+{
+    CvPoint2D64f res;
+    res.x = (from.x-area.width/2.0)/area.width;
+    res.y = (from.y-area.height/2.0)/area.height;   
+    return res;
+}
+
+inline CvPoint fromNormalizedCoords(CvSize area, CvPoint2D64f from)
+{
+    CvPoint res;
+    res.x = (from.x+0.5)*area.width;
+    res.y = (from.y+0.5)*area.height;   
+    return res;
+}
+
+inline CvPoint2D64f fromNormalizedCoords64f(CvSize area, CvPoint2D64f from)
+{
+    CvPoint2D64f res;
+    res.x = (from.x+0.5)*area.width;
+    res.y = (from.y+0.5)*area.height;   
+    return res;
+}
+
+void alphaBlit(IplImage *a, IplImage *aAlpha, IplImage *b, IplImage *bAlpha, int offset_y, int offset_x)
+{
+    // TODO: Add checks for image type and size
+ int i,j;
+ CvSize bSize = cvGetSize(b);
+ CvSize aSize = cvGetSize(a);
+ CvRect pos = cvRect(offset_x
+                    ,offset_y
+                    ,bSize.width
+                    ,bSize.height);
+ for (i=0; i<bSize.height; i++)
+    for (j=0; j<bSize.width; j++) {
+       float aA, bA,fV;
+       if (j+offset_x>=aSize.width || i+offset_y>=aSize.height || i+offset_y < 0 || j+offset_x<0) continue;
+
+       aA = FGET(aAlpha,j+offset_x,i+offset_y);
+       bA = FGET(bAlpha,j,i);
+       fV = aA+bA > 0 ? (FGET(b,j,i)*bA+FGET(a,j+offset_x,i+offset_y)*aA)/(aA+bA) : FGET(b,j,i) ;
+       FGET(a,j+offset_x,i+offset_y) =fV;
+       FGET(aAlpha,j+offset_x,i+offset_y) =aA+bA;
+    }
+}
+
+
+void plainBlit(IplImage *a, IplImage *b, int offset_y, int offset_x)
+{
+    // TODO: Add checks for image type and size
+ int i,j;
+ CvSize aSize = cvGetSize(a);
+ CvSize bSize = cvGetSize(b);
+ for (i=0; i<bSize.height; i++) {
+    for (j=0; j<bSize.width; j++) {
+       if (j+offset_x<0 || j+offset_x>=aSize.width || i+offset_y<0 || i+offset_y>=aSize.height ) continue;
+       if (a->nChannels == 1) 
+            {FGET(a,j+offset_x,i+offset_y) =FGET(b,j,i);}
+        else if (a->nChannels ==3) 
+            {
+             int dx = j+offset_x; int dy = i+offset_y;
+             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 0] =
+              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 0] ; // B
+             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 1] =
+              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 1] ; // G
+             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 2] =
+              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 2] ; // R
+            }
+             else {printf("Can't blit this - pic weird number of channels\n"); abort();}
+
+    }}
+}
+
+void subpixel_blit(IplImage *a, IplImage *b, double offset_y, double offset_x)
+{
+    // TODO: Add checks for image type and size
+ int i,j;
+ CvSize aSize = cvGetSize(a);
+ CvSize bSize = cvGetSize(b);
+ for (i=0; i<aSize.height; i++)
+    for (j=0; j<aSize.width; j++) {
+       double x_at_b=j-offset_x;
+       double y_at_b=i-offset_y;
+       if (x_at_b <0 || x_at_b >= bSize.width
+           || y_at_b <0 || y_at_b >= bSize.height) continue;
+       FGET(a,j,i) =bilinearInterp(b,x_at_b,y_at_b);
+        // TODO: Check boundaries! #SAFETY
+
+    }
+}
+
+
+// Histograms.
+void wrapReleaseHist(CvHistogram *hist)
+{
+ cvReleaseHist(&hist);
+}
+
+CvHistogram* calculateHistogram(IplImage *img,int bins)
+{
+ float st_range[] = {-1,1};
+ float *ranges[]  = {st_range};
+ int hist_size[] = {bins};
+ CvHistogram *result = cvCreateHist(1,hist_size,CV_HIST_ARRAY,ranges,1);
+ cvCalcHist(&img,result,0,0);
+ return result;
+}
+
+void get_histogram(IplImage *img,IplImage *mask
+                 ,float a, float b,int isCumulative
+                 ,int binCount
+                 ,double *values)
+{
+ int i=0;
+ float st_range[] = {a,b};
+ float *ranges[]  = {st_range};
+ int hist_size[] = {binCount};
+ CvHistogram *result = cvCreateHist(1,hist_size,CV_HIST_ARRAY
+                                   ,ranges,1);
+ cvCalcHist(&img,result,isCumulative,mask);
+ for (i=0;i<binCount;++i)
+    {
+     *values = cvQueryHistValue_1D(result,i); values++;
+    }
+ cvReleaseHist(&result);
+ return;
+}
+
+
+double getHistValue(CvHistogram *h,int bin)
+{
+ return *cvGetHistValue_1D(h,bin);
+}
+
+// Convolutions
+IplImage* wrapFilter2D(IplImage *src, int ax,int ay, 
+                    int w, int h, double *kernel){
+int i,j;
+IplImage *target = cvCloneImage(src);
+CvMat *kernelMat = cvCreateMat(w,h,CV_32FC1);
+for(i=0;i<w*h;i++)
+  cvSetReal2D(kernelMat,i%w,i/w,kernel[i]); 
+cvFilter2D(src,target,kernelMat,cvPoint(ay,ax));
+cvReleaseMat(&kernelMat);
+return target;
+}
+
+IplImage* wrapFilter2DImg(IplImage *src
+                         ,IplImage *mask
+                         ,int ax,int ay)
+{
+int i,j;
+IplImage *target = cvCloneImage(src);
+CvSize size = cvGetSize(mask);
+CvMat *kernelMat = cvCreateMat(size.width,size.height,CV_32FC1);
+for(i=0;i<size.width;i++)
+ for(j=0;j<size.height;j++)
+  cvSetReal2D(kernelMat,i,j,cvGetReal2D(mask,j,i)); 
+cvFilter2D(src,target,kernelMat,cvPoint(ay,ax));
+cvReleaseMat(&kernelMat);
+return target;
+}
+
+// Connected components
+
+void wrapFloodFill(IplImage *i, int x, int y, double c
+                  ,double low, double high,int fixed)
+{
+ int flag = 8 | (fixed ? CV_FLOODFILL_FIXED_RANGE : 0);
+ cvFloodFill(i,cvPoint(x,y),cvRealScalar(c),cvRealScalar(low)
+            ,cvRealScalar(high),NULL,flag,NULL);
+}
+                  
+// hough-lines
+
+void wrapProbHoughLines(IplImage *img, double rho, double theta
+                       , int threshold, double minLength
+                       , double gapLength
+                       , int *maxLines
+                       , int *xs, int *ys
+                       , int *xs1, int *ys1)
+{
+ IplImage *tmp;
+ CvSeq *lines = 0;
+ int i;
+ CvMemStorage *storage = cvCreateMemStorage(0); 
+ 
+ tmp = ensure8U(img);
+
+ lines = cvHoughLines2(tmp,storage,CV_HOUGH_PROBABILISTIC
+                     ,rho,theta,threshold,minLength,gapLength);
+ for( i = 0; i < MIN(lines->total,*maxLines); i++ )
+        {
+            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
+            xs[i] = line[0].x; xs1[i] = line[1].x;
+            ys[i] = line[0].y; ys1[i] = line[1].y; 
+        }
+ *maxLines = MIN(lines->total,*maxLines);
+
+ cvReleaseImage(&tmp);
+ cvReleaseMemStorage(&storage);
+ 
+}
+                       
+
+
+//@-node:aleator.20050908100314.2:Wrappers
+//@+node:aleator.20050908100314.3:Utilities
+/* These are utilities that operate on opencv primitives but
+  are not really wrappers.. Due to the fact that I seem to
+  be incapable to link multiple objects including openCV
+  headers this seems to be the next best solution.
+
+  Watch out for name collisions!
+
+*/
+//@+node:aleator.20070906153003:Trigonometric operations
+
+void calculateAtan(IplImage *src, IplImage *dst)
+{
+  CvSize imageSize = cvGetSize(dst);
+  double r=0; int i; int j;
+  for(i=0; i<imageSize.width; ++i)
+    for(j=0; j<imageSize.height; ++j) {
+          r = FGET(src,j,i); //// cvGetReal2D(src,j,i);
+          FGET(dst,j,i) = atan(r);
+          //cvSet2D(dst,j,i,cvScalarAll(atan(r)));
+    }
+}
+
+void calculateAtan2(IplImage *src1,IplImage *src2, IplImage *dst)
+{
+  CvSize imageSize = cvGetSize(dst);
+  for(int i=0; i<imageSize.width; ++i)
+    for(int j=0; j<imageSize.height; ++j) {
+          double a = FGET(src1,j,i);
+          double b = FGET(src2,j,i);
+          FGET(dst,j,i) = atan2(a,b);
+    }
+}
+
+//@nonl
+//@-node:aleator.20070906153003:Trigonometric operations
+//@+node:aleator.20051109111547:Pixel accessors
+// All these will work only on grayscale.
+inline int imax(int x, int y) {return (x>y) ? x:y;}
+inline int imin(int x, int y) {return (x<y) ? x:y;}
+inline double blurGet2D(IplImage *img,int x, int y)
+{
+ CvSize size = cvGetSize(img);
+ x = imax(0,imin(x,size.width-1));
+ y = imax(0,imin(y,size.height-1));
+
+ return cvGetReal2D(img,y,x);
+}
+
+//@-node:aleator.20051109111547:Pixel accessors
+//@+node:aleator.20070827150608:Haar Filters
+
+// Simple routines for calculating pixelwise
+// haar responses
+
+void haarFilter(IplImage *intImg, 
+                int x1, int y1, int x2, int y2,
+                IplImage *target)
+{
+  int i,j;
+  double s = 0;
+  double ratio = 1;
+  double desArea = (x2-x1)*(y1-y2);
+  double area = 0;
+  int rx1,rx2,ry1,ry2;
+  CvSize imageSize = cvGetSize(target);  
+  for(i=0; i<imageSize.width; ++i)
+    for(j=0; j<imageSize.height; ++j) {
+         rx1 = imax(0,imin(i+x1,imageSize.width-1));  
+         ry1 = imax(0,imin(j+y1,imageSize.height-1));
+         rx2 = imax(0,imin(i+x2,imageSize.width-1)); 
+         ry2 = imax(0,imin(j+y2,imageSize.height-1));
+         area = (float)((rx2-rx1)*(ry2-ry1));
+        // if (area > 0) ratio = fabs(desArea/area);
+        // else ratio=1;
+         //printf("Ratio(%d,%d) is %lf\n",rx1,ry1,ratio);
+         s = blurGet2D(intImg,rx1,ry1)
+             -blurGet2D(intImg,rx1,ry2)
+             -blurGet2D(intImg,rx2,ry1)
+             +blurGet2D(intImg,rx2,ry2);
+          cvSet2D(target,j,i,cvScalarAll(s/area));
+    }
+}
+
+double haar_at(IplImage *intImg, 
+                int x1, int y1, int w, int h)
+{
+  int i,j;
+  double s = 0;
+  s = blurGet2D(intImg,x1,y1)
+     -blurGet2D(intImg,x1,y1+h)
+     -blurGet2D(intImg,x1+w,y1)
+     +blurGet2D(intImg,x1+w,y1+h);
+  return s;
+}
+                
+//@nonl
+//@-node:aleator.20070827150608:Haar Filters
+//@+node:aleator.20070130144337:Statistics along a line
+#define SWAP(a,b) { \
+        int c = (a);    \
+        (a) = (b);      \
+        (b) = c;        \
+    }
+
+
+double average_of_line(int x0, int y0
+                     ,int x1, int y1
+                     ,IplImage *src) {
+     int steep = abs(y1 - y0) > abs(x1 - x0);
+     int deltax=0; int deltay=0;
+     int error=0;
+     int ystep=0;
+     int x=0; int y=0;
+     float sum=0; int len=0;
+
+     if (steep)   { SWAP(x0, y0); SWAP(x1, y1); }
+     if (x0 > x1) { SWAP(x0, x1); SWAP(y0, y1); }
+     deltax = x1 - x0;
+     deltay = abs(y1 - y0);
+     error  = 0;
+     y = y0;
+     if (y0 < y1) {ystep = 1;} else {ystep = -1;}
+     for (x=x0; x<x1; ++x) {
+         if (steep) {sum+=blurGet2D(src,y,x);
+                     ++len;} 
+                    // _plot(y,x);} 
+         else       {sum+=blurGet2D(src,x,y);
+                     ++len; } 
+                    //_plot(x,y);}
+         error = error + deltay;
+         if (2*error >= deltax) {
+             y = y + ystep;
+             error = error - deltax; }
+         }
+         return (sum/len);
+}
+
+//@-node:aleator.20070130144337:Statistics along a line
+//@+node:aleator.20051130130836:Taking square roots of images
+
+void sqrtImage(IplImage *src,IplImage *dst)
+{
+int i;int j;
+double result;
+CvSize size = cvGetSize(src);
+
+for(i=0;i<size.width;++i)
+ for(j=0;j<size.height;++j)
+    {
+     result = cvSqrt(cvGetReal2D(src,j,i));
+     cvSetReal2D(dst,j,i,result);
+    }
+}
+//@-node:aleator.20051130130836:Taking square roots of images
+//@+node:aleator.20050930104348:Histogram Features
+#define HISTOGRAMSIZE 10
+
+double calculateMoment(int i,double arr[], int l)
+{
+int j=0;
+double result = 0;
+for(j=0; j<l; j++)
+  {  result += pow((j*1.0)/HISTOGRAMSIZE,i)*arr[j]; }
+return result;
+}
+
+double calculateAbsCentralMoment(int i,double arr[], int l)
+{
+int j=0;
+double m1 = calculateMoment(1,arr,l);
+double result = 0;
+for(j=0; j<l; j++)
+ {
+  result += pow(fabs(((j*1.0)/HISTOGRAMSIZE)-m1),i)*arr[j];}
+return result;
+}
+
+double calculateCentralMoment(int i,double arr[], int l)
+{
+int j=0;
+double m1 = calculateMoment(1,arr, l);
+double result = 0;
+for(j=0; j<l; j++)
+ {  
+    result += pow(((j*1.0)/HISTOGRAMSIZE)-m1,i)*arr[j];
+
+ }
+return result;
+}
+//@+node:aleator.20050930104348.1:Central Moments
+
+IplImage* getNthCentralMoment(IplImage *src,int n, int w, int h)
+{
+
+CvSize size = cvGetSize(src);
+int iw = size.width-w;
+int ih = size.height-h;
+IplImage *target = wrapCreateImage32F(iw,ih,1);
+int x = 0;
+int y = 0;
+int i = 0;
+int j = 0;
+double histogram[HISTOGRAMSIZE]; 
+for (x=0; x<ih; x++)
+ for (y=0; y<iw; y++)
+ {
+memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
+double result = 0;
+
+// Calculate the local histogram
+for (i=0; i<w; i++)
+ for (j=0; j<h; j++)
+    {
+     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
+     histogram[slot] += 1.0/(w*h*1.0);
+    }
+
+
+result = calculateCentralMoment(n,histogram,HISTOGRAMSIZE); 
+cvSet2D(target,x,y,cvScalarAll(result));
+ }
+
+return target;
+}
+
+IplImage* getNthAbsCentralMoment(IplImage *src,int n, int w, int h)
+{
+
+CvSize size = cvGetSize(src);
+int iw = size.width-w;
+int ih = size.height-h;
+IplImage *target = wrapCreateImage32F(iw,ih,1);
+int x = 0;
+int y = 0;
+int i = 0;
+int j = 0;
+double histogram[HISTOGRAMSIZE]; 
+for (x=0; x<ih; x++)
+ for (y=0; y<iw; y++)
+ {
+memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
+double result = 0;
+
+// Calculate the local histogram
+for (i=0; i<w; i++)
+ for (j=0; j<h; j++)
+    {
+     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
+     histogram[slot] += 1.0/(w*h*1.0);
+    }
+
+
+result = calculateAbsCentralMoment(n,histogram,HISTOGRAMSIZE); 
+cvSet2D(target,x,y,cvScalarAll(result));
+ }
+
+return target;
+}
+
+IplImage* getNthMoment(IplImage *src,int n, int w, int h)
+{
+
+CvSize size = cvGetSize(src);
+int iw = size.width-w;
+int ih = size.height-h;
+IplImage *target = wrapCreateImage32F(iw,ih,1);
+int x = 0;
+int y = 0;
+int i = 0;
+int j = 0;
+double histogram[HISTOGRAMSIZE]; 
+for (x=0; x<ih; x++)
+ for (y=0; y<iw; y++)
+ {
+memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
+double result = 0;
+
+// Calculate the local histogram
+for (i=0; i<w; i++)
+ for (j=0; j<h; j++)
+    {
+     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
+     histogram[slot] += 1.0/(w*h*1.0);
+    }
+
+result = calculateMoment(n,histogram,HISTOGRAMSIZE); 
+cvSet2D(target,x,y,cvScalarAll(result));
+ }
+
+return target;
+}
+
+//@-node:aleator.20050930104348.1:Central Moments
+//@+node:aleator.20051103110155:SMAB
+   
+// Perform second moment adaptive binarization for a single pixel `x`
+// using given histogram.
+double max(double x,double y) {if (x<y) return y; else return x;}
+double min(double x,double y) {if (x>y) return y; else return x;}
+int SMABx(double x, CvHistogram *h,int binCount,double t)
+{
+ int binnedX;  double leftSM=0;
+ double rightSM=0;
+ int i=0;
+ binnedX = round(min(1,max(x,0))*(binCount-1));
+
+ // Calculate left second moment:
+ for(i=0; i<binnedX; i++)
+  { leftSM += pow(x - ((1.0*i)/(1.0*binCount)),2) * getHistValue(h,i); }
+ for(i=binnedX; i<binCount; i++)
+  { rightSM += pow(x - ((1.0*i)/(1.0*binCount)),2) * getHistValue(h,i); }
+ return (leftSM - (rightSM * t));
+}
+
+// Perform SMAB for image
+void smb(IplImage *image,double t)
+{
+int i;int j;
+double result;
+CvSize size = cvGetSize(image);
+CvHistogram *h = calculateHistogram(image,255);
+for(i=0;i<size.width;++i)
+ for(j=0;j<size.height;++j)
+ {
+     result = SMABx(cvGet2D(image,j,i).val[0],h,255,t);
+     cvSet2D(image,j,i,cvScalarAll(result));
+ }
+}
+
+void smab(IplImage *image,int w, int h,double t)
+{
+int i;int j;
+int wi;int wj;
+double result;
+CvHistogram *histogram;
+CvRect roi;
+CvSize size = cvGetSize(image);
+roi.width = w;
+roi.height = h;
+
+for(i=0;i<size.width;++i)
+ for(j=0;j<size.height;++j)
+ {
+     roi.x = i-(w/2);
+     roi.y = j-(h/2);
+     cvSetImageROI(image,roi);
+     histogram = calculateHistogram(image,50);
+     cvResetImageROI(image);
+     result = SMABx(cvGetReal2D(image,j,i),histogram,50,t);
+     cvReleaseHist(&histogram);
+     cvSet2D(image,j,i,cvScalarAll(result));
+ }
+}
+//@-node:aleator.20051103110155:SMAB
+//@+node:aleator.20051108093248:Skewness
+
+//@-node:aleator.20051108093248:Skewness
+//@-node:aleator.20050930104348:Histogram Features
+//@+node:aleator.20050926095227:Susan
+/* 
+ Susan (Smallest Univalue Segmenting Nucleus) is 
+ family of image processing methods, including
+ edge preserving noise reduction.
+*/
+//@+node:aleator.20050926095227.1:Susan Smoothing Function
+
+/* 
+ Calculate susan smoothing for `src` around `x`,`y` coordinates.
+ `t` determines brightness treshold and sigma controls scale of
+ spatial smoothing. `w` and `h` determine window size.
+*/
+
+inline double calcSusanSmooth(IplImage* src, int x, int y
+                      ,double t,double sigma,int w, int h)
+{
+
+int i = 0;
+int j = 0;
+
+long double numerator = 0;
+long double denominator = 0;
+for (i = 0; i<w; i++)
+ for (j = 0; j<h; j++)
+    {
+    if (i==w/2 && j==h/2) continue;
+    double r2 = i*i+j*j;
+    double expFrac = (cvGet2D(src,x+i,y+j).val[0] 
+                     - cvGet2D(src,x,y).val[0]);
+    expFrac *= expFrac;
+
+    double exponential = exp(  (-r2/(2*sigma*sigma)) - (expFrac/(t*t))  );
+
+    numerator   += cvGet2D(src,x+i,y+j).val[0] * exponential;
+    denominator += exponential;
+    }
+return numerator/denominator;
+}
+//@-node:aleator.20050926095227.1:Susan Smoothing Function
+//@+node:aleator.20050926100856:Susan Smoothing
+
+IplImage* susanSmooth(IplImage *src, int w, int h
+                     ,double t, double sigma)
+
+{
+
+CvSize size = cvGetSize(src);
+int iw = size.width-w;
+int ih = size.height-h;
+IplImage *target = wrapCreateImage32F(iw,ih,1);
+int x = 0;
+int y = 0;
+double result = 0;
+
+
+for (x=0; x<iw; x++)
+ for (y=0; y<ih; y++)
+ {
+  result = calcSusanSmooth(src,y,x,t,sigma,h,w);
+  cvSet2D(target,y,x,cvScalarAll(result));
+ }
+return target;
+}
+//@-node:aleator.20050926100856:Susan Smoothing
+//@+node:aleator.20050927083244:Susan Edge
+/* 
+ Susan Edge Detector.
+*/
+
+// susan threshold function
+inline double susanC(double r, double r0,double t)
+{
+ return exp(-((r-r0)/t));
+}
+
+inline double susanValue(IplImage *src,int x, int y
+                        ,int w, int h, double t)
+{
+int i; int j;
+double geometricTreshold = (3*(w*h)) / 4;
+double sum = 0;
+
+for (i = 0; i<w; i++)
+ for (j = 0; j<h; j++)
+    {
+     sum += susanC(cvGet2D(src,x+i,y+j).val[0]
+                  ,cvGet2D(src,x,y).val[0]
+                  ,t);
+    }
+if (sum < geometricTreshold)
+    return geometricTreshold - sum;
+else return 0;
+}
+
+IplImage* susanEdge(IplImage *src,int w,int h,double t)
+{
+CvSize size = cvGetSize(src);
+int iw = size.width-w;
+int ih = size.height-h;
+IplImage *target = wrapCreateImage32F(iw,ih,1);
+int x = 0;
+int y = 0;
+double result = 0;
+
+
+for (x=0; x<iw; x++)
+ for (y=0; y<ih; y++)
+ {
+  result = susanValue(src,y,x,h,w,t);
+  cvSet2D(target,y,x,cvScalarAll(result));
+ }
+return target;
+
+}
+//@-node:aleator.20050927083244:Susan Edge
+//@-node:aleator.20050926095227:Susan
+//@+node:aleator.20050908112008:Gabors
+/* 
+ Gabor functions are modulated gaussians which bear some resemblance
+ to human visual cortex neurons. */
+//@+node:aleator.20050908104238:gabor function in C
+/* This function calculates value of simple gabor function
+  at given x,y coordinates. Parameters for the gabor are:
+  
+  stdX  - standard deviation in oscillation direction
+  stdY  - standard deviation tangential to stdX
+  theta - angle (in radians) of the gabor
+  phase - phase of the gabor
+
+
+*/
+double calcGabor(double x, double y
+                ,double stdX, double stdY
+                ,double theta, double phase
+                ,double cycles)
+{
+ double xth = x*cos(theta)  - y*sin(theta);
+ double yth = x*sin(theta)  + y*cos(theta);
+ double oscillationPart = cos(2*M_PI*xth/cycles+phase);
+ double gaussianPart    = exp((-0.5*xth*xth)/(stdX*stdX))
+                         *exp((-0.5*yth*yth)/(stdY*stdY));
+ 
+ return gaussianPart * oscillationPart;
+}
+
+double calc1DGabor(double x
+                ,double sigma
+                ,double phase, double center
+                ,double cycles)
+{
+ double oscillationPart = cos(2*M_PI*(x-center)/cycles+phase);
+ double gaussianPart    = exp((-0.5*(x-center)*(x-center))
+                              /(sigma*sigma));
+ 
+ return gaussianPart * oscillationPart;
+}
+
+
+//@-node:aleator.20050908104238:gabor function in C
+//@+node:aleator.20050908112116:rendering gabors to arrays
+void renderGabor(CvArr *dst,int width, int height
+                ,double dx, double dy
+                ,double stdX, double stdY
+                ,double theta, double phase
+                ,double cycles)
+
+{
+ int i,j;
+ int mx = width/2;
+ int my = height/2;
+ for (i=0; i<width; i++)
+  for (j=0; j<height; j++) // TODO: This might be a bug
+   cvSet2D(dst,i,j,cvScalarAll(calcGabor(i-dx,j-dy,stdX,stdY
+                                        ,theta,phase,cycles)));
+}
+
+void render_gaussian(IplImage *dst
+                   ,double stdX, double stdY)
+
+{
+ int i,j;
+ double distX;
+ double distY;
+ CvSize size = cvGetSize(dst);
+ double centerX = size.width/2.0;
+ double centerY = size.height/2.0;
+ for (i=0; i<size.width-1; i++)
+  for (j=0; j<size.height-1; j++)
+   { distX = ((centerX-i*1.0)*(centerX-i*1.0)) / (2*stdX*stdX);
+     distY = ((centerY-j*1.0)*(centerY-j*1.0)) / (2*stdY*stdY);
+  //   printf("w: %d, h: %d, i: %d, j:%d,dx: %e,dy: %e,exp:%e\n",size.width,size.height,i,j,distX,distY,exp(-distX-distY));
+     fflush(stdout);
+     cvSet2D(dst,j,i,cvScalarAll( exp(-distX-distY) ));
+  }
+}
+
+
+void renderRadialGabor(CvArr *dst,int width, int height
+                ,double sigma
+                ,double phase, double center
+                ,double cycles)
+
+{
+ int i,j;
+ int mx = width/2;
+ int my = height/2;
+ double rad = 0;
+ for (i=0; i<width; i++)
+  for (j=0; j<width; j++)
+   {
+   rad = sqrt((i-mx)*(i-mx)+(j-my)*(j-my));
+   cvSet2D(dst,i,j,cvScalarAll(calc1DGabor(rad,sigma
+                                          ,phase,center,cycles)));
+   }
+}
+
+void wrapMinMaxLoc(const IplImage* target, int* minx, int* miny, int* maxx, int* maxy, double *minval, double *maxval)
+{
+	CvPoint maxPoint;
+	CvPoint minPoint;
+	cvMinMaxLoc(target,minval,maxval,&minPoint, &maxPoint, NULL);
+    *maxx = maxPoint.x ;
+    *maxy = maxPoint.y ;
+    *minx = minPoint.x ;
+    *miny = minPoint.y ;
+} 
+
+void simpleMatchTemplate(const IplImage* target, const IplImage* template, int* x, int* y, double *val,int type)
+{
+	int rw = cvGetSize(target).width-cvGetSize(template).width+1;
+	int rh = cvGetSize(target).height-cvGetSize(template).height+1;
+	IplImage* result = wrapCreateImage32F(rw,rh,1);
+	cvMatchTemplate(target,template,result,type);
+	double min,max;
+	CvPoint maxPoint;
+	maxPoint.x=-1;
+	maxPoint.y=-1;
+	min =0;
+	max =0;
+	cvMinMaxLoc(result,&min,&max,NULL, &maxPoint, NULL);
+	*x = maxPoint.x;+rw/2;
+	*y = maxPoint.y;+rh/2;
+	*val = max;
+	cvReleaseImage(&result);
+	} 
+
+IplImage* templateImage(const IplImage* target, const IplImage* template)
+{
+	int rw = cvGetSize(target).width-cvGetSize(template).width+1;
+	int rh = cvGetSize(target).height-cvGetSize(template).height+1;
+	IplImage* result = wrapCreateImage32F(rw,rh,1);
+	cvMatchTemplate(target,template,result,CV_TM_CCORR);
+	return result;
+	} 
+
+
+//@-node:aleator.20050908112116:rendering gabors to arrays
+//@+node:aleator.20050908101148:gabor filter using cvFilter2D
+void gaborFilter(const CvArr *src, CvArr *dst
+                ,int maskWidth, int maskHeight
+                ,double stdX, double stdY
+                ,double theta,double phase
+                ,double cycles)
+
+{
+ int mx = maskWidth/2;
+ int my = maskHeight/2;
+ CvMat *kernel = cvCreateMat(maskWidth,maskHeight,CV_32F);
+ renderGabor(kernel,maskWidth,maskHeight,mx,my,stdX,stdY
+             ,theta,phase,cycles);
+ cvFilter2D(src,dst,kernel,cvPoint(-1,-1));
+}
+
+void radialGaborFilter(const CvArr *src, CvArr *dst
+                ,int maskWidth, int maskHeight
+                ,double sigma
+                ,double phase,double center
+                ,double cycles)
+
+{
+ CvMat *kernel = cvCreateMat(maskWidth,maskHeight,CV_32F);
+ renderRadialGabor(kernel,maskWidth,maskHeight,sigma
+               ,phase,center,cycles);
+ cvFilter2D(src,dst,kernel,cvPoint(-1,-1));
+}
+
+
+//@-node:aleator.20050908101148:gabor filter using cvFilter2D
+//@-node:aleator.20050908112008:Gabors
+//@+node:aleator.20070511142414:Adaboost Learning
+// This doesn't really work properly yet.. No
+// time to do anything about it really.
+//@nonl
+//@+node:aleator.20070511142414.1:Fitness
+// In the following the class is encoded bit
+// differently. 0 is one class and +1 is another.
+// if target is gray it is considered null area.
+
+double adaFitness1(IplImage *target
+                 ,IplImage *weigths
+                 ,IplImage *test)
+{
+CvSize size = cvGetSize(target);
+int i,j;
+int width  = size.width;
+int height = size.height;
+double result=0;
+double tij=0,wij=0,testij=0,rij=0; 
+for (i=0; i<width; i++)
+ for (j=0; j<height; j++)
+ { 
+   tij = cvGetReal2D(target,j,i);
+   wij = cvGetReal2D(weigths,j,i);
+   testij = cvGetReal2D(test,j,i);
+   rij=wij;
+   if (((tij < 0.2) && (testij < 0.2)) || ((tij > 0.8) && (testij > 0.8))) 
+    {rij=0;} 
+   result += rij;
+ }
+ 
+return result;
+}
+//@-node:aleator.20070511142414.1:Fitness
+//@+node:aleator.20070511145251:Updating distributions
+
+// This function is used to update distribution.
+// Notice that alpha_t must be calculated separately
+// and normalization is not applied.
+IplImage* adaUpdateDistrImage(IplImage *target
+                          ,IplImage *weigths
+                          ,IplImage *test
+                          ,double at)
+{
+CvSize size = cvGetSize(target);
+int i,j;
+int width  = size.width;
+int height = size.height;
+double tij=0,wij=0,testij=0,rij=0; 
+IplImage *result = wrapCreateImage32F(width,height,1);
+for (i=0; i<width; i++)
+ for (j=0; j<height; j++)
+ { 
+   tij = cvGetReal2D(target,j,i);
+   wij = cvGetReal2D(weigths,j,i);
+   testij = cvGetReal2D(test,j,i);
+   if ( (tij>0.2) && (tij<0.8) ) continue;
+   if (((tij < 0.2) && (testij < 0.2)) 
+      || ((tij > 0.8) && (testij > 0.8))) 
+    {rij = wij*exp(-at);
+     cvSetReal2D(result,j,i,rij); }
+   else 
+    {rij = wij*exp(at);
+     cvSetReal2D(result,j,i,rij); }
+ }
+ 
+return result;
+}
+
+//@-node:aleator.20070511145251:Updating distributions
+//@-node:aleator.20070511142414:Adaboost Learning
+//@+node:aleator.20051207074905:LBP
+
+void get_weighted_histogram(IplImage *src, IplImage *weights, 
+                       double start, double end, 
+                       int bins, double *histo)
+{
+  int i,j,index;
+  double value,weight;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=0;i<bins;++i) histo[i]=0;
+  for(i=0; i<imageSize.width-1; ++i)
+    for(j=0; j<imageSize.height-1; ++j)
+        {
+         value = cvGetReal2D(src,j,i);
+         weight = cvGetReal2D(weights,j,i);
+         index = floor(bins*((value - start)/(end - start)));
+         //printf("Adding weight %e to index %d\n",weight,index);
+         if (index<0 || index>=bins) continue;
+         histo[index] += weight;
+        }
+  
+}
+
+// Calculate local binary pattern for image. 
+// LBP is outgoing array
+// of (preallocated) 256 bytes that are assumed to be 0.
+void localBinaryPattern(IplImage *src, int *LBP)
+{
+  int i,j;
+  int pattern = 0;
+  double center = 0;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=1; i<imageSize.width-1; ++i)
+    for(j=1; j<imageSize.height-1; ++j)
+        {
+         center = cvGetReal2D(src,j,i);
+
+         pattern += (blurGet2D(src,i-1,j-1) > center) *1;
+         pattern += (blurGet2D(src,i,j-1)   > center) *2;
+         pattern += (blurGet2D(src,i+1,j-1) > center) *4;
+         
+         pattern += (blurGet2D(src,i-1,j)   > center) *8;
+         pattern += (blurGet2D(src,i+1,j)   > center) *16;
+         
+         pattern += (blurGet2D(src,i-1,j+1) > center) *32;
+         pattern += (blurGet2D(src,i,j+1)   > center) *64;
+         pattern += (blurGet2D(src,i+1,j+1) > center) *128;
+         LBP[pattern]++;
+         pattern = 0;
+        }
+}
+
+
+void localBinaryPattern3(IplImage *src, int *LBP)
+{
+  int i,j;
+  int pattern = 0;
+  double center = 0;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=1; i<imageSize.width-1; ++i)
+    for(j=1; j<imageSize.height-1; ++j)
+        {
+         center = cvGetReal2D(src,j,i);
+
+         pattern += (blurGet2D(src,i-2,j-2) > center) *1;
+         pattern += (blurGet2D(src,i,j-3)   > center) *2;
+         pattern += (blurGet2D(src,i+2,j-2) > center) *4;
+         
+         pattern += (blurGet2D(src,i-3,j)   > center) *8;
+         pattern += (blurGet2D(src,i+3,j)   > center) *16;
+         
+         pattern += (blurGet2D(src,i-2,j+2) > center) *32;
+         pattern += (blurGet2D(src,i,j+3)   > center) *64;
+         pattern += (blurGet2D(src,i+2,j+2) > center) *128;
+         LBP[pattern]++;
+         pattern = 0;
+        }
+}
+void localBinaryPattern5(IplImage *src, int *LBP)
+{
+  int i,j;
+  int pattern = 0;
+  double center = 0;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=1; i<imageSize.width-1; ++i)
+    for(j=1; j<imageSize.height-1; ++j)
+        {
+         center = cvGetReal2D(src,j,i);
+
+         pattern += (blurGet2D(src,i-4,j-4) > center) *1;
+         pattern += (blurGet2D(src,i,j-5)   > center) *2;
+         pattern += (blurGet2D(src,i+4,j-4) > center) *4;
+         
+         pattern += (blurGet2D(src,i-5,j)   > center) *8;
+         pattern += (blurGet2D(src,i+5,j)   > center) *16;
+         
+         pattern += (blurGet2D(src,i-4,j+4) > center) *32;
+         pattern += (blurGet2D(src,i,j+5)   > center) *64;
+         pattern += (blurGet2D(src,i+4,j+4) > center) *128;
+         LBP[pattern]++;
+         pattern = 0;
+        }
+}
+
+void weighted_localBinaryPattern(IplImage *src,int offsetX,int offsetXY
+                                , IplImage* weights, double *LBP)
+{
+  int i,j;
+  int pattern = 0;
+  double center = 0;
+  double weight = 0;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=1; i<imageSize.width-1; ++i)
+    for(j=1; j<imageSize.height-1; ++j)
+        {
+         center = cvGetReal2D(src,j,i);
+         weight = cvGetReal2D(weights,j,i);
+
+         pattern += (blurGet2D(src,i-offsetXY,j-offsetXY) > center) *1;
+         pattern += (blurGet2D(src,i,j-offsetX)   > center) *2;
+         pattern += (blurGet2D(src,i+offsetXY,j-offsetXY) > center) *4;
+         
+         pattern += (blurGet2D(src,i-offsetX,j)   > center) *8;
+         pattern += (blurGet2D(src,i+offsetX,j)   > center) *16;
+         
+         pattern += (blurGet2D(src,i-offsetXY,j+offsetXY) > center) *32;
+         pattern += (blurGet2D(src,i,j+offsetX)   > center) *64;
+         pattern += (blurGet2D(src,i+offsetXY,j+offsetXY) > center) *128;
+         LBP[pattern] += weight;
+         pattern = 0;
+        }
+}
+
+
+void localHorizontalBinaryPattern(IplImage *src, int *LBP)
+{
+  int i,j;
+  int pattern = 0;
+  double center = 0;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=0; i<imageSize.width-1; ++i)
+    for(j=0; j<imageSize.height-1; ++j)
+        {
+         center = cvGetReal2D(src,j,i);
+
+         pattern += (blurGet2D(src,i-4,j) > center) *1;
+         pattern += (blurGet2D(src,i-3,j) > center) *2;
+         pattern += (blurGet2D(src,i-2,j) > center) *4;
+         pattern += (blurGet2D(src,i-1,j) > center) *8;
+         pattern += (blurGet2D(src,i+1,j) > center) *16;
+         pattern += (blurGet2D(src,i+2,j) > center) *32;
+         pattern += (blurGet2D(src,i+3,j) > center) *64;
+         pattern += (blurGet2D(src,i+4,j) > center) *128;
+         LBP[pattern]++;
+         pattern = 0;
+        }
+}
+
+void localVerticalBinaryPattern(IplImage *src, int *LBP)
+{
+  int i,j;
+  int pattern = 0;
+  double center = 0;
+  CvSize imageSize = cvGetSize(src);  
+  for(i=0; i<imageSize.width-1; ++i)
+    for(j=0; j<imageSize.height-1; ++j)
+        {
+         center = cvGetReal2D(src,j,i);
+
+         pattern += (blurGet2D(src,i,j-4) > center) *1;
+         pattern += (blurGet2D(src,i,j-3) > center) *2;
+         pattern += (blurGet2D(src,i,j-2) > center) *4;
+         pattern += (blurGet2D(src,i,j-1) > center) *8;
+         pattern += (blurGet2D(src,i,j+1) > center) *16;
+         pattern += (blurGet2D(src,i,j+2) > center) *32;
+         pattern += (blurGet2D(src,i,j+3) > center) *64;
+         pattern += (blurGet2D(src,i,j+4) > center) *128;
+         LBP[pattern]++;
+         pattern = 0;
+        }
+}
+
+
+//@-node:aleator.20051207074905:LBP
+//@+node:aleator.20051109102750:Selective Average
+// Assuming grayscale image calculate local selective average of point x y 
+inline double calcSelectiveAvg(IplImage *img,double t
+                                   ,int x, int y
+                                   ,int wwidth, int wheight)
+{
+int i,j;
+double accum=0; 
+double count=0;
+double centerValue; double processed=0;
+CvSize size = cvGetSize(img);
+centerValue = blurGet2D(img,x,y);
+
+for (i=-wwidth; i<wwidth;++i)
+ for (j=-wheight; j<wheight;++j)
+  { 
+   if (  x+i<0 || x+i>=size.width
+      || y+j<0 || y+j>=size.height)
+      continue;
+      
+   processed = blurGet2D(img,x+i,y+j);
+   if (fabs(processed-centerValue)<t)
+        {accum+=processed;++count;}
+  }
+return accum/count;
+}
+
+
+IplImage* selectiveAvgFilter(IplImage *src,double t
+                            ,int wwidth, int wheight)
+{
+CvSize size = cvGetSize(src);
+int i,j;
+int width  = size.width;
+int height = size.height;
+double result;
+
+IplImage *target = wrapCreateImage32F(width,height,1);
+for (i=0; i<width; i++)
+ for (j=0; j<height; j++)
+ {
+  result = calcSelectiveAvg(src,t,i,j,wwidth,wheight);
+  cvSetReal2D(target,j,i,result);
+ }
+ 
+return target;
+}
+
+//@-node:aleator.20051109102750:Selective Average
+//@+node:aleator.20060104154125:AcquireImage
+
+// Copy array into single channel iplImage
+IplImage *acquireImageSlow(int w, int h, double *d)
+{
+ IplImage *img;
+ int i,j;
+ img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
+ for (i=0; i<h; i++) {
+   for (j=0; j<w; j++) { 
+         //printf("(%d,%d) => %d is %f\n",j,i,(i+j*h),d[i+j*h]);
+         FGET(img,j,i) = d[j*h+i]; 
+         }
+    }
+ return img;
+}
+
+IplImage *acquireImageSlowF(int w, int h, float *d)
+{
+ IplImage *img;
+ int i,j;
+ img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
+ for (i=0; i<h; i++) {
+   for (j=0; j<w; j++) { 
+         //printf("(%d,%d) => %d is %f\n",j,i,(i+j*h),d[i+j*h]);
+         FGET(img,j,i) = d[j*h+i]; 
+         }
+    }
+ return img;
+}
+
+#define BLUE = 0
+#define GREEN = 1
+#define RED = 2
+
+
+IplImage *acquireImageSlow8U(int w, int h, uint8_t *d)
+{
+ IplImage *img;
+ int i,j;
+ img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,1);
+ for (i=0; i<h; i++) {
+   for (j=0; j<w; j++) { 
+         UGETC(img,0,j,i) = *d; d++; 
+         }
+    }
+ return img;
+}
+
+IplImage *acquireImageSlow8URGB(int w, int h, uint8_t *d)
+{
+ IplImage *img;
+ int i,j;
+ img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,3);
+ for (i=0; i<h; i++) {
+   for (j=0; j<w; j++) { 
+         UGETC(img,0,j,i) = *d; d++; 
+         UGETC(img,1,j,i) = *d; d++; 
+         UGETC(img,2,j,i) = *d; d++; 
+         }
+    }
+ return img;
+}
+
+IplImage *acquireImageSlow8UBGR(int w, int h, uint8_t *d)
+{
+ IplImage *img;
+ int i,j;
+ img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,3);
+ for (i=0; i<h; i++) {
+   for (j=0; j<w; j++) { 
+         UGETC(img,2,j,i) = *d; d++; 
+         UGETC(img,1,j,i) = *d; d++; 
+         UGETC(img,0,j,i) = *d; d++; 
+         }
+    }
+ return img;
+}
+
+IplImage *acquireImageSlowComplex(int w, int h, complex double *d)
+{
+ IplImage *img;
+ int i,j;
+ img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
+ for (i=0; i<h; i++) {
+   for (j=0; j<w; j++) { 
+         FGET(img,j,i) = (float)(creal(d[j*h+i])); 
+         }
+    }
+ return img;
+}
+
+void exportImageSlowComplex(IplImage *img, complex double *d)
+{
+ int i,j;
+ CvSize s= cvGetSize(img);
+ for (i=0; i<s.height; i++) {
+   for (j=0; j<s.width; j++) { 
+         d[j*s.height+i] = (complex float)(FGET(img,j,i) + 0*I); 
+         }
+    }
+}
+
+void exportImageSlow(IplImage *img, double *d)
+{
+ int i,j;
+ CvSize s= cvGetSize(img);
+ for (i=0; i<s.height; i++) {
+   for (j=0; j<s.width; j++) { 
+         d[j*s.height+i] = FGET(img,j,i); 
+         }
+    }
+}
+void exportImageSlowF(IplImage *img, float *d)
+{
+ int i,j;
+ CvSize s= cvGetSize(img);
+ for (i=0; i<s.height; i++) {
+   for (j=0; j<s.width; j++) { 
+         d[j*s.height+i] = FGET(img,j,i); 
+         }
+    }
+}
+//@-node:aleator.20060104154125:AcquireImage
+//@-node:aleator.20050908100314.3:Utilities
+//@+node:aleator.20060413093124:Connected components
+//@+node:aleator.20071016114634:Contours
+
+
+void free_found_contours(FoundContours *f)
+{
+ cvReleaseMemStorage(&(f->storage));
+ free(f);
+ 
+}
+
+int reset_contour(FoundContours *f)
+{ 
+ f->contour = f->start;
+}
+
+int cur_contour_size(FoundContours *f)
+{ 
+ return f->contour->total;
+}
+
+double contour_area(FoundContours *f)
+{ 
+ return cvContourArea(f->contour,CV_WHOLE_SEQ,0);
+}
+
+CvMoments* contour_moments(FoundContours *f)
+{ 
+ CvMoments* moments = (CvMoments*) malloc(sizeof(CvMoments));
+ cvMoments(f->contour,moments,0);
+ return moments;
+}
+
+double contour_perimeter(FoundContours *f)
+{ 
+ return cvContourPerimeter(f->contour);
+}
+
+int more_contours(FoundContours *f)
+{ 
+ if (f->contour != 0)
+  {return 1;}
+  {return 0;} // no more contours
+}
+
+int next_contour(FoundContours *f)
+{ 
+ if (f->contour != 0)
+  {f->contour = f->contour->h_next; return 1;}
+  {return 0;} // no more contours
+}
+
+void contour_points(FoundContours *f, int *xs, int *ys)
+{
+ if (f->contour==0) {printf("unavailable contour\n"); exit(1);}
+ 
+ CvPoint *pt=0;
+ int total,i=0;
+ total = f->contour->total;
+ for (i=0; i<total;i++) 
+  {
+   pt = (CvPoint*)cvGetSeqElem(f->contour,i);
+   if (pt==0) {printf("point out of contour\n"); exit(1);}
+   xs[i] = pt->x;
+   ys[i] = pt->y;
+  } 
+    
+}
+
+void print_contour(FoundContours *fc)
+{
+  int i=0;
+  CvPoint *pt=0;
+   for (i=0; i<fc->contour->total;++i) 
+    {
+     pt = (CvPoint*)cvGetSeqElem(fc->contour,i);
+     printf("PT=%d,%d\n",pt->x,pt->y);
+    }
+}
+
+/* void draw_contour(FoundContours *fc,double color
+                 , IplImage *img, IplImage *dst)
+{
+ cvDrawContours( dst, fc->start, color, color, -1, 0, 8
+               , cvPoint(0,0));
+} */
+
+
+FoundContours* get_contours(IplImage *src1)
+{
+ CvSize size;
+ IplImage *src = ensure8U(src1);
+ //int dstDepth = IPL_DEPTH_8U;
+ //size = cvGetSize(src1);
+ //src = cvCreateImage(size,dstDepth,1);
+ //cvCopy(src1,src,NULL);
+ 
+ 
+ CvPoint* pt=0;
+ int i=0;
+ 
+ CvMemStorage *storage=0;
+ CvSeq *contour=0;
+ FoundContours* result = (FoundContours*)malloc(sizeof(FoundContours));
+ storage = cvCreateMemStorage(0);
+       
+ cvFindContours( src,storage
+               , &contour
+               , sizeof(CvContour) 
+               ,CV_RETR_EXTERNAL 
+            //,CV_RETR_CCOMP 
+               ,CV_CHAIN_APPROX_NONE
+               ,cvPoint(0,0) );
+
+// result->contour = cvApproxPoly( result->contour, sizeof(CvContour)
+//                                , result->storage, CV_POLY_APPROX_DP
+//                                , 3, 1 );
+ result->start = contour;
+ result->contour = contour;
+ result->storage = storage;
+
+ cvReleaseImage(&src);
+ return result;
+    
+ }
+//@-node:aleator.20071016114634:Contours
+//@+node:aleator.20070814123008:moments
+CvMoments* getMoments(IplImage *src, int isBinary)
+{
+ CvMoments* moments = (CvMoments*) malloc(sizeof(CvMoments));
+ cvMoments( src, moments, isBinary);
+ return moments;
+}
+
+void freeCvMoments(CvMoments *x)
+{
+ free(x);
+}
+
+
+void getHuMoments(CvMoments *src,double *hu)
+{
+ CvHuMoments* hu_moments = (CvHuMoments*) malloc(sizeof(CvHuMoments));
+ cvGetHuMoments( src, hu_moments);
+ *hu = hu_moments->hu1; ++hu;
+ *hu = hu_moments->hu2; ++hu;
+ *hu = hu_moments->hu3; ++hu;
+ *hu = hu_moments->hu4; ++hu;
+ *hu = hu_moments->hu5; ++hu;
+ *hu = hu_moments->hu6; ++hu;
+ *hu = hu_moments->hu7; 
+ return;
+}
+
+void freeCvHuMoments(CvHuMoments *x)
+{
+ free(x);
+}
+//@-node:aleator.20070814123008:moments
+//@+node:aleator.20060727102514:blobCount
+int blobCount(IplImage *src)
+{
+    int contourCount=0;
+    CvMemStorage* storage = cvCreateMemStorage(0);
+    CvSeq* contour = 0;
+
+    contourCount = cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
+
+    cvReleaseMemStorage(&storage);
+    return contourCount;
+}
+
+//@-node:aleator.20060727102514:blobCount
+//@+node:aleator.20060413093124.1:sizeFilter
+IplImage* sizeFilter(IplImage *src, double minSize, double maxSize)
+{
+    IplImage* dst = cvCreateImage( cvGetSize(src), IPL_DEPTH_32F, 1 );
+    CvMemStorage* storage = cvCreateMemStorage(0);
+    CvSeq* contour = 0;
+
+    cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
+    cvZero( dst );
+
+    for( ; contour != 0; contour = contour->h_next )
+    {
+        double area=fabs(cvContourArea(contour,CV_WHOLE_SEQ,0));
+        if (area <=minSize || area >= maxSize) continue;
+        CvScalar color = cvScalar(1,1,1,1);
+        cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8,
+            cvPoint(0,0));
+    }
+    cvReleaseMemStorage(&storage);
+    return dst;
+}
+//@-node:aleator.20060413093124.1:sizeFilter
+//@-node:aleator.20060413093124:Connected components
+//@+node:aleator.20050908101148.1:function for rotating image
+IplImage* rotateImage(IplImage* src,double scale,double angle)
+{
+
+  IplImage* dst = cvCloneImage( src );
+  angle = angle * (180 / CV_PI);
+  int w = src->width;
+  int h = src->height;
+  CvMat *M;
+  M = cvCreateMat(2,3,CV_32FC1);
+  CvPoint2D32f center = cvPoint2D32f(w/2.0,h/2.0);
+  CvMat *N = cv2DRotationMatrix(center,angle,scale,M);
+  cvWarpAffine( src, dst, N, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS
+              , cvScalarAll(0)); 
+  return dst;
+  cvReleaseMat(&M);
+}
+
+
+inline double cubicInterpolate(
+   double y0,double y1,
+   double y2,double y3,
+   double mu)
+{
+   double a0,a1,a2,a3,mu2;
+
+   mu2 = mu*mu;
+   a0 = y3 - y2 - y0 + y1;
+   a1 = y0 - y1 - a0;
+   a2 = y2 - y0;
+   a3 = y1;
+   return(a0*mu*mu2+a1*mu2+a2*mu+a3);
+}
+
+double bilinearInterp(IplImage *tex, double u, double v) {
+   CvSize s = cvGetSize(tex);
+   int x = floor(u);
+   int y = floor(v);
+   double u_ratio = u - x;
+   double v_ratio = v - y;
+   double u_opposite = 1 - u_ratio;
+   double v_opposite = 1 - v_ratio;
+   double result = ((x+1 >= s.width) || (y+1 >= s.height)) ? FGET(tex,x,y) :
+                   (FGET(tex,x,y)   * u_opposite  + FGET(tex,x+1,y)   * u_ratio) * v_opposite + 
+                   (FGET(tex,x,y+1) * u_opposite  + FGET(tex,x+1,y+1) * u_ratio) * v_ratio;
+   return result;
+ }
+
+// TODO: Check boundaries! #SAFETY
+double bicubicInterp(IplImage *tex, double u, double v) {
+   CvSize s = cvGetSize(tex);
+   int x = floor(u);
+   int y = floor(v);
+   double u_ratio = u - x;
+   double v_ratio = v - y;
+   double p[4][4] = {FGET(tex,x-1,y-1),  FGET(tex,x,y-1),  FGET(tex,x+1,y-1),  FGET(tex,x+2,y-1),
+                     FGET(tex,x-1,y),    FGET(tex,x,y),    FGET(tex,x+1,y),    FGET(tex,x+2,y),
+                     FGET(tex,x-1,y+1),  FGET(tex,x,y+1),  FGET(tex,x+1,y+1),  FGET(tex,x+2,y+1),
+                     FGET(tex,x-1,y+2),  FGET(tex,x,y+2),  FGET(tex,x+1,y+2),  FGET(tex,x+2,y+2)
+                     };
+    double a00 = p[1][1];
+	double a01 = -p[1][0] + p[1][2];
+	double a02 = 2*p[1][0] - 2*p[1][1] + p[1][2] - p[1][3];
+	double a03 = -p[1][0] + p[1][1] - p[1][2] + p[1][3];
+	double a10 = -p[0][1] + p[2][1];
+	double a11 = p[0][0] - p[0][2] - p[2][0] + p[2][2];
+	double a12 = -2*p[0][0] + 2*p[0][1] - p[0][2] + p[0][3] + 2*p[2][0] - 2*p[2][1] 
+                 + p[2][2] - p[2][3];
+	double a13 = p[0][0] - p[0][1] + p[0][2] - p[0][3] - p[2][0] + p[2][1] - p[2][2] + p[2][3];
+	double a20 = 2*p[0][1] - 2*p[1][1] + p[2][1] - p[3][1];
+	double a21 = -2*p[0][0] + 2*p[0][2] + 2*p[1][0] - 2*p[1][2] - p[2][0] + p[2][2] 
+                 + p[3][0] - p[3][2];
+	double a22 = 4*p[0][0] - 4*p[0][1] + 2*p[0][2] - 2*p[0][3] - 4*p[1][0] + 4*p[1][1] 
+                 - 2*p[1][2] + 2*p[1][3] + 2*p[2][0] - 2*p[2][1] + p[2][2] - p[2][3] 
+                 - 2*p[3][0] + 2*p[3][1] - p[3][2] + p[3][3];
+	double a23 = -2*p[0][0] + 2*p[0][1] - 2*p[0][2] + 2*p[0][3] + 2*p[1][0] - 2*p[1][1] 
+                 + 2*p[1][2] - 2*p[1][3] - p[2][0] + p[2][1] - p[2][2] + p[2][3] + p[3][0] 
+                 - p[3][1] + p[3][2] - p[3][3];
+	double a30 = -p[0][1] + p[1][1] - p[2][1] + p[3][1];
+	double a31 = p[0][0] - p[0][2] - p[1][0] + p[1][2] + p[2][0] - p[2][2] - p[3][0] + p[3][2];
+	double a32 = -2*p[0][0] + 2*p[0][1] - p[0][2] + p[0][3] + 2*p[1][0] - 2*p[1][1] 
+                 + p[1][2] - p[1][3] - 2*p[2][0] + 2*p[2][1] - p[2][2] + p[2][3] + 2*p[3][0] 
+                 - 2*p[3][1] + p[3][2] - p[3][3];
+	double a33 = p[0][0] - p[0][1] + p[0][2] - p[0][3] - p[1][0] + p[1][1] - p[1][2] 
+                 + p[1][3] + p[2][0] - p[2][1] + p[2][2] - p[2][3] - p[3][0] + p[3][1] 
+                 - p[3][2] + p[3][3];
+
+	double x2 = u_ratio * u_ratio;
+	double x3 = x2 * u_ratio;
+	double y2 = v_ratio * v_ratio;
+	double y3 = y2 * v_ratio;
+
+	return a00 + a01 * v_ratio + a02 * y2 + a03 * y3 +
+	       a10 * u_ratio + a11 * u_ratio * v_ratio + a12 * u_ratio * y2 + a13 * u_ratio * y3 +
+	       a20 * x2 + a21 * x2 * v_ratio + a22 * x2 * y2 + a23 * x2 * y3 +
+	       a30 * x3 + a31 * x3 * v_ratio + a32 * x3 * y2 + a33 * x3 * y3;
+ }
+
+void radialRemap(IplImage *source, IplImage *dest, double k)
+{
+    int i,j;
+    CvSize s = cvGetSize(dest);
+    double x,y,cx,cy,nx,ny,r2;
+    cx = s.width/2.0;
+    cy = s.height/2.0;
+    for (i=0; i<s.height; i++)
+       for (j=0; j<s.width; j++) {
+           nx = (j-cx)/s.width;
+           ny = (i-cy)/s.height;
+           r2 = nx*nx+ny*ny;
+           nx = nx*(1+k*r2);
+           ny = ny*(1+k*r2);
+           x = (nx+0.5)*s.width;
+           y = (ny+0.5)*s.height;
+           if (x<0 || x>=s.width || y<0 || y>=s.height) 
+            { FGET(dest,j,i) = 0; 
+             continue;}
+           FGET(dest,j,i) = bilinearInterp(source,x,y);
+           }
+
+
+}
+
+
+//@-node:aleator.20050908101148.1:function for rotating image
+//@+node:aleator.20051220091717:Matrix multiplication
+
+void wrapMatMul(int w, int h, double *mat
+               , double *vec, double *t)
+{
+
+CvMat matrix;
+CvMat vector;
+CvMat target;
+cvInitMatHeader(&matrix,w,h,CV_64FC1,mat,CV_AUTOSTEP);
+cvInitMatHeader(&vector,h,1,CV_64FC1,vec,CV_AUTOSTEP);
+cvInitMatHeader(&target,w,1,CV_64FC1,t,CV_AUTOSTEP);
+cvMatMul(&matrix,&vector,&target);
+}
+
+void maximal_covering_circle(int ox,int oy, double or, IplImage *distmap
+                            ,int *max_x, int *max_y, double *max_r)
+{
+ double distance,radius;
+
+ *max_x = ox;
+ *max_y = oy;
+ *max_r  = or;
+
+ CvSize s = cvGetSize(distmap);
+ for(int i=0; i<s.width; i++) // TODO: Limit with max_r
+  for(int j=0; j<s.height; j++)
+   {
+    distance = sqrt((i-ox)*(i-ox) + (j-oy)*(j-oy));
+    radius   = FGET(distmap,i,j);
+    if (radius > *max_r && radius >= or+distance )
+         { *max_x=i; *max_y=j; *max_r=radius;}
+   }
+}
+
+double juliaF(double a, double b,double x, double y) {
+     int limit = 1000;
+     double complex z;
+     int i=0;
+     double complex c;
+     double cr,ci;
+     c = a + b*I;
+     z = x+y*I;
+     for (i=0;i<limit;i++)
+        {
+         cr=creal(z); ci=cimag(i);
+         if (cr*cr+ci*ci>4) return (i*1.0)/limit;
+         z=z*z+c;
+        }
+    return 0;
+    }
+
+CvVideoWriter* wrapCreateVideoWriter(char *fn, int fourcc,
+                                     double fps,int w, int h,
+                                     int color) 
+ {
+   CvVideoWriter *res = cvCreateVideoWriter(fn,CV_FOURCC('M','P','G','4'),fps,cvSize(w,h), color);
+   return res;
+ }
+
+int wrapFindChessBoardCorners(const void* image, int pw, int ph, CvPoint2D32f* corners, int* cornerCount, int flags)
+{
+ CvSize s = {pw,ph};
+ //for (int i=0; i<pw*ph; i++) {corners[i].x=i; corners[i].y=i+10;}
+ cvFindChessboardCorners(image,s,corners,cornerCount,flags);
+}
+
+int wrapDrawChessBoardCorners(void* image, int pw, int ph, CvPoint2D32f* corners, int cornerCount, int wasFound)
+{
+ CvSize s = {pw,ph};
+ cvDrawChessboardCorners(image,s,corners,cornerCount,wasFound);
+}
+
+double wrapCalibrateCamera2(const CvMat* objectPoints, const CvMat* imagePoints, const CvMat* pointCounts, CvSize *imageSize, CvMat* cameraMatrix, CvMat* distCoeffs, CvMat* rvecs, CvMat* tvecs, int flags)
+{
+return cvCalibrateCamera2(objectPoints, imagePoints, pointCounts, *imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags);
+};
+
+void wrapFindCornerSubPix(const CvArr* image, CvPoint2D32f* corners, int count, int winW, int winH, int zeroW, int zeroH, int tType, int maxIter, double epsilon) {
+ CvTermCriteria t = {tType,maxIter,epsilon};
+ CvSize searchWindow = {winW,winH};
+ CvSize zero = {winW,winH};
+ cvFindCornerSubPix(image, corners, count, searchWindow, zero, t);
+};
+
+
+//
+//@-node:aleator.20051220091717:Matrix multiplication
+//@-all
+//@-node:aleator.20050908100314:@thin cvWrapLEO.c
+//@-leo
diff --git a/cbits/cvWrapLEO.h b/cbits/cvWrapLEO.h
new file mode 100644
--- /dev/null
+++ b/cbits/cvWrapLEO.h
@@ -0,0 +1,287 @@
+//@+leo-ver=4-thin
+//@+node:aleator.20050908101148.2:@thin cvWrapLEO.h
+//@@language c
+#ifndef __CVWRAP__
+#define __CVWRAP__
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846
+#endif
+
+#include <opencv/cv.h>
+#include <opencv/cxcore.h>
+#include <opencv/highgui.h>
+#include <complex.h>
+
+IplImage* wrapCreateImage32F(const int width, const int height, const int channels);
+IplImage* wrapCreateImage64F(const int width, const int height, const int channels);
+
+IplImage* wrapCreateImage8U(const int width, const int height, const int channels);
+
+void wrapSubRS(const CvArr *src, double s,CvArr *dst);
+void wrapSubS(const CvArr *src, double s,CvArr *dst);
+void wrapAddS(const CvArr *src, double s, CvArr *dst);
+
+double wrapAvg(const CvArr *src);
+double wrapStdDev(const CvArr *src);
+double wrapStdDevMask(const CvArr *src,const CvArr *mask);
+double wrapSum(const CvArr *src);
+void wrapMinMax(const CvArr *src,const CvArr *mask
+               ,double *minVal, double *maxVal);
+void wrapAbsDiffS(const CvArr *src, double s, CvArr *dst);
+
+void wrapSetImageROI(IplImage *i,int x, int y, int w, int h);
+
+IplImage* wrapSobel(IplImage *src,int dx
+                   ,int dy,int size);
+
+IplImage* wrapLaplace(IplImage *src,int size);
+
+IplImage* ensure8U(const IplImage *src);
+IplImage* ensure32F(const IplImage *src);
+
+void wrapSet32F2D(CvArr *arr, int x, int y, double value);
+double wrapGet32F2D(CvArr *arr, int x, int y);
+uint8_t wrapGet8U2DC(IplImage *arr, int x, int y,int c);
+
+void wrapDrawCircle(CvArr *img, int x, int y, int radius, float r,float g,float b, int thickness);
+
+void wrapDrawLine(CvArr *img, int x, int y, int x1, int y1, double r, double g, double b, int thickness);
+
+void wrapFillPolygon(IplImage *img, int pc, int *xs, int *ys, float r, float g, float b);
+
+void wrapMatMul(int w, int h, double *mat
+               , double *vec, double *t);
+
+// Utils. Place them in another file
+IplImage* rotateImage(IplImage* src,double scale,double angle);
+CvHistogram* calculateHistogram(IplImage *img,int bins);
+void wrapReleaseHist(CvHistogram *hist);
+double getHistValue(CvHistogram *h,int bin);
+void get_histogram(IplImage *img,IplImage *mask
+                 ,float a, float b,int isCumulative
+                 ,int binCount
+                 ,double *values);
+
+//void get_weighted_histogram(IplImage *img,IplImage *mask);
+//                 ,float a, float b
+//                 ,int binCount
+//                 ,double *values);
+
+IplImage* getSubImage(IplImage *img, int sx,int sy,int w,int h);
+int getImageHeight(IplImage *img);
+int getImageWidth(IplImage *img);
+
+
+IplImage* susanSmooth(IplImage *src, int w, int h
+                     ,double t, double sigma);
+
+IplImage* susanEdge(IplImage *src,int w,int h,double t);
+IplImage* getNthCentralMoment(IplImage *src, int n, int w, int h);
+IplImage* getNthAbsCentralMoment(IplImage *src, int n, int w, int h);
+IplImage* getNthMoment(IplImage *src, int n, int w, int h);
+
+double calcGabor(double x, double y
+                ,double stdX, double stdY
+                ,double theta, double phase
+                ,double cycles);
+
+void gaborFilter(const CvArr *src, CvArr *dst
+                ,int maskWidth, int maskHeight
+                ,double stdX, double stdY
+                ,double theta,double phase
+                ,double cycles);
+
+void radialGaborFilter(const CvArr *src, CvArr *dst
+                ,int maskWidth, int maskHeight
+                ,double sigma
+                ,double phase,double center
+                ,double cycles);
+
+void renderRadialGabor(CvArr *dst,int width, int height
+                ,double sigma
+                ,double phase, double center
+                ,double cycles);
+
+void render_gaussian(IplImage *dst
+                   ,double stdX, double stdY);
+
+void renderGabor(CvArr *dst,int width, int height
+                ,double dx, double dy
+                ,double stdX, double stdY
+                ,double theta, double phase
+                ,double cycles);
+
+void smb(IplImage *image,double t);
+void smab(IplImage *image,int w, int h,double t);
+
+IplImage* selectiveAvgFilter(IplImage *src,double t
+                            ,int wwidth, int wheight);
+
+IplImage* wrapFilter2D(IplImage *src, int ax,int ay, 
+                    int w, int h, double *kernel);
+IplImage* wrapFilter2DImg(IplImage *src
+                         ,IplImage *mask
+                         ,int ax,int ay);
+
+void wrapFloodFill(IplImage *i, int x, int y, double c
+                  ,double low, double high,int fixed);
+
+void sqrtImage(IplImage *src,IplImage *dst);
+
+void weighted_localBinaryPattern(IplImage *src,int offsetX,int offsetXY
+                                , IplImage* weights, double *LBP);
+
+void localBinaryPattern(IplImage *src, int *LBP);
+void localBinaryPattern3(IplImage *src, int *LBP);
+void localBinaryPattern5(IplImage *src, int *LBP);
+void localHorizontalBinaryPattern(IplImage *src, int *LBP);
+void localVerticalBinaryPattern(IplImage *src, int *LBP);
+
+void get_weighted_histogram(IplImage *src, IplImage *weights, 
+                       double start, double end, 
+                       int bins, double *histo);
+
+
+void eigenValsViaSVD(double *A, int size, double *eVals
+                    ,double *eVects);
+
+IplImage* sizeFilter(IplImage *src, double minSize, double maxSize);
+int blobCount(IplImage *src);
+
+
+IplImage *acquireImage(int w, int h, double *d);
+
+void wrapProbHoughLines(IplImage *img, double rho, double theta
+                       , int threshold, double minLength
+                       , double gapLength
+                       , int *maxLines
+                       , int *xs, int *ys
+                       , int *xs1, int *ys1);
+
+
+double average_of_line(int x0, int y0
+                     ,int x1, int y1
+                     ,IplImage *src);
+                     
+IplImage* adaUpdateDistrImage(IplImage *target
+                          ,IplImage *weigths
+                          ,IplImage *test
+                          ,double at);
+
+double adaFitness1(IplImage *target
+                 ,IplImage *weigths
+                 ,IplImage *test);
+           
+CvMoments* getMoments(IplImage *src, int isBinary);
+
+void freeCvMoments(CvMoments *x);
+
+void getHuMoments(CvMoments *src,double *hu);
+
+void freeCvHuMoments(CvHuMoments *x);
+
+void haarFilter(IplImage *intImg, 
+                int a, int b, int c, int d,
+                IplImage *target);
+
+double haar_at(IplImage *intImg, 
+                int x1, int y1, int w, int h);
+
+void wrapDrawRectangle(CvArr *img, int x1, int y1, 
+                       int x2, int y2, float r, float g, float b,
+                       int thickness);
+
+void calculateAtan(IplImage *src, IplImage *dst);
+void calculateAtan2(IplImage *src1,IplImage *src2, IplImage *dst);
+
+
+// Contours
+typedef struct {
+  CvMemStorage *storage;
+  CvSeq *contour;
+  CvSeq *start;
+  
+} FoundContours;
+
+CvMoments* contour_moments(FoundContours *f);
+void contour_points(FoundContours *f, int *xs, int *ys);
+CvMoments* contour_Moments(FoundContours *f);
+int cur_contour_size(FoundContours *f);
+double contour_area(FoundContours *f);
+double contour_perimeter(FoundContours *f);
+int more_contours(FoundContours *f);
+int next_contour(FoundContours *f);
+int reset_contour(FoundContours *f);
+void free_found_contours(FoundContours *f);
+void get_next_contour(FoundContours *fc);
+void print_contour(FoundContours *fc);
+FoundContours* get_contours(IplImage *src);
+
+double juliaF(double a, double b,double x, double y);
+void simpleMatchTemplate(const IplImage* target, const IplImage* template, int* x, int* y, double *val, int type);
+IplImage* templateImage(const IplImage* target, const IplImage* template);
+IplImage* simpleMergeImages(IplImage *a, IplImage *b,int offset_x, int offset_y);
+
+void alphaBlit(IplImage *a, IplImage *aAlpha, IplImage *b, IplImage *bAlpha, int offset_x, int offset_y);
+void blitImg(IplImage *a, IplImage *b,int offset_x, int offset_y);
+IplImage* fadedEdges(int w, int h, int edgeW);
+IplImage* rectangularDistance(int w, int h);
+void radialRemap(IplImage *source, IplImage *dest, double k);
+void plainBlit(IplImage *a, IplImage *b, int offset_y, int offset_x);
+void wrapMinMaxLoc(const IplImage* target, int* minx, int* miny, int* maxx, int* maxy, double *minval, double *maxval);
+void incrImageC(void);
+IplImage* vignettingModelCos4(int w, int h) ;
+IplImage* vignettingModelCos4XCyl(int w, int h) ;
+IplImage* vignettingModelX2Cyl(int w, int h,double m, double s, double c);
+void wrapDrawText(CvArr *img, char *text, float s, int x, int y,float r,float g,float b);
+
+IplImage* vignettingModelB3(int w, int h,double b1, double b2, double b3);
+inline CvPoint2D64f toNormalizedCoords(CvSize area, CvPoint from);
+inline CvPoint fromNormalizedCoords(CvSize area, CvPoint2D64f from);
+inline double eucNorm(CvPoint2D64f p);
+IplImage* vignettingModelP(int w, int h,double scalex, double scaley, double max);
+IplImage* wrapPerspective(IplImage* src, double a1, double a2, double a3
+                                       , double a4, double a5, double a6
+                                       , double a7, double a8, double a9);
+IplImage* simplePerspective(double k,IplImage *src);
+double bilinearInterp(IplImage *tex, double u, double v);
+inline CvPoint2D64f fromNormalizedCoords64f(CvSize area, CvPoint2D64f from);
+void findHomography(double* srcPts, double *dstPts, int noPts, double *homography);
+void masked_merge(IplImage *src1, IplImage *mask, IplImage *src2, IplImage *dst);
+IplImage* makeEvenUp(IplImage *src);
+IplImage* padUp(IplImage *src,int right, int bottom);
+IplImage* makeEvenDown(IplImage *src);
+void vertical_average(IplImage *src1, IplImage *dst);
+
+IplImage* composeMultiChannel(IplImage* img0
+                             ,IplImage* img1
+                             ,IplImage* img2
+                             ,IplImage* img3
+                             ,const int channels);
+
+IplImage *acquireImageSlow(int w, int h, double *d);
+IplImage *acquireImageSlowF(int w, int h, float *d);
+void exportImageSlow(IplImage *img, double *d);
+void exportImageSlowF(IplImage *img, float *d);
+
+IplImage *acquireImageSlowComplex(int w, int h, complex double *d);
+void exportImageSlowComplex(IplImage *img, complex double *d);
+void subpixel_blit(IplImage *a, IplImage *b, double offset_y, double offset_x);
+double bicubicInterp(IplImage *tex, double u, double v);
+
+CvVideoWriter* wrapCreateVideoWriter(char *fn, int fourcc, double fps,int w, int h, int color); 
+
+double wrapGet32F2DC(CvArr *arr, int x, int y,int c);
+void maximal_covering_circle(int ox,int oy, double or, IplImage *distmap
+                            ,int *max_x, int *max_y, double *max_r);
+
+int wrapFindChessBoardCorners(const void* image, int pw, int ph, CvPoint2D32f* corners, int* cornerCount, int flags);
+
+int wrapDrawChessBoardCorners(void* image, int pw, int ph, CvPoint2D32f* corners, int cornerCount, int wasFound);
+
+double wrapCalibrateCamera2(const CvMat* objectPoints, const CvMat* imagePoints, const CvMat* pointCounts, CvSize *imageSize, CvMat* cameraMatrix, CvMat* distCoeffs, CvMat* rvecs, CvMat* tvecs, int flags);
+
+#endif
+//@-node:aleator.20050908101148.2:@thin cvWrapLEO.h
+//@-leo
diff --git a/examples/Chessboard.hs b/examples/Chessboard.hs
new file mode 100644
--- /dev/null
+++ b/examples/Chessboard.hs
@@ -0,0 +1,10 @@
+module Main where
+import CV.Image
+import CV.Calibration
+
+main = do
+    Just i <- loadColorImage "chess.png"
+    let corners = findChessboardCorners (unsafeImageTo8Bit i) (4,5) (FastCheck:defaultFlags)
+    let y = drawChessboardCorners (unsafeImageTo8Bit i) (4,5) corners
+    mapM_ print (corners)
+    saveImage "found_chessboard.png" y
diff --git a/examples/Monster.hs b/examples/Monster.hs
new file mode 100644
--- /dev/null
+++ b/examples/Monster.hs
@@ -0,0 +1,73 @@
+{-#LANGUAGE ViewPatterns#-}
+module Main where
+
+import CV.Image
+
+import CV.ColourUtils
+import CV.Morphology
+import CV.Filters
+import CV.Thresholding
+import CV.Edges
+import CV.ImageMathOp
+import qualified CV.ImageMath as IM
+import CV.FunnyStatistics
+import CV.ConnectedComponents
+import CV.Transforms
+import System.Environment
+import CV.Pixelwise
+import Graphics.Gnuplot.Simple
+import Data.List
+import Data.Ord
+
+hdef d (x:xs) = x
+hdef d _      = d
+
+horMax :: Image GrayScale D32 -> [Double]
+horMax (fromImage -> pixels) = [fromIntegral $ snd $ maximumBy (comparing value) [(i,j) | j<-[0..height-1]] | i <- [0..width-1] ]
+    where
+        value (x,y) = getPixel (x,y) pixels 
+        (width,height) = getSize pixels
+
+ntimes n op = (!! n) . iterate op
+
+smooth [x] = [x]
+smooth [x,y] = [(x+y) / 2]
+smooth (x:y:xs) = (x+y) / 2:smooth (y:xs)
+
+conv mask = map (prod mask) . tails
+    where 
+     prod xs ys = sum (zipWith (*) xs ys)
+
+-- TODO: Something is not type safe in this chain:
+main = do
+    Just x <- getArgs >>= loadImage . hdef (error "No file given!") >>= return . fmap (enlarge n )
+    let 
+        operR = unsafeImageTo32F . nibbly 1 0.01 . IM.abs . sobel (1,0) s3  -- nibbly 0.3 0.01
+        operL = unsafeImageTo32F . nibbly 1 0.01 . IM.abs . sobel (0,1) s3  -- nibbly 0.3 0.01
+        down oper = take n $ map oper $ iterate pyrDown x
+        up  oper = foldl1 (\a b -> (pyrUp a) `IM.min` b) $ reverse (down oper)
+        se = structuringElement (9,9) (4,4) EllipseShape
+        thd =  dilate se 2 . unsafeImageTo32F . nibbly 0.9 0.001 $ IM.invert x 
+        pyrd = stretchHistogram $  (up operL) #+ (up operR)-- $ sobel (1,0) s3 x -- $ (up operR)
+        clean :: Image GrayScale D8
+        clean = selectSizedComponents (10000) (10000000) $ IM.moreThan 0.2 $ thd #* (close se pyrd)
+        final = unsafeImageTo32F clean -- #* (IM.abs (sobel (1,0) s1 x) #+ IM.abs (sobel (0,1) s1 x))
+        rotated :: Image GrayScale D8
+        rotated = rotate (pi/4.5) final
+--        hm = (horMax rotated)
+--        shm = ntimes 100 smooth hm
+    saveImage "Combine.png" rotated
+--    print (length hm,getSize rotated, getSize (fromImage rotated)) 
+--    plotLists [YRange (-15,15)] [map (*100) $ nonMaxSupress 30 $ conv [-1,2,-1] $ shm, map (\x -> (x-400)/20) shm]
+ where n = 5
+
+nonMaxSupress w = reverse . nonMaxSupress' w . reverse . nonMaxSupress' w
+nonMaxSupress' w = map supress . map (take w) . tails 
+    where 
+        supress [] = 0 
+        supress [x] = x
+        supress (x:xs) | all (<x) xs = x
+                       | otherwise   = 0 
+
+threshold t x | x <t = 0
+              | otherwise = 10
diff --git a/examples/StupidConv.hs b/examples/StupidConv.hs
new file mode 100644
--- /dev/null
+++ b/examples/StupidConv.hs
@@ -0,0 +1,35 @@
+{-#LANGUAGE BangPatterns#-}
+import CV.Image
+import CV.ColourUtils
+import Control.Monad
+import qualified CV.ImageMath as IM
+
+{-#INLINE (×)#-}
+a × b = [(a',b') | a' <- a , b' <- b]
+
+stupidConv im m = do
+    res <- create (w-mw,h-mh)
+    forM_ ([0..w-1-mw] × [0..h-1-mh]) $ \(x,y) -> 
+     setPixel (x,y) (sum [getPixel (x+i,y+j) im * getPixel (i,j) m 
+                         | (i,j) <- [0..mw-1] × [0..mh-1]]) res
+    return res
+ where 
+    maskSize = IM.sum m
+    (!mw,!mh)  = getSize m
+    (!w,!h)    = getSize im
+
+main = do
+    Just x <- loadImage "smallLena.jpg"
+    m <- fromList (3,3) [-1,0,1
+                        ,-1,0,1
+                        ,-1,0,1] 
+    print (IM.sum x)
+    r <- stupidConv x m
+    print (IM.sum r)
+    saveImage "stupid.png" $ stretchHistogram r
+
+
+fromList (w,h) xs = do
+     i <- create (w,h)
+     forM_ (zip ([0..w-1] × [0..h-1]) xs) $ \(p,v) -> setPixel p v i 
+     return i
diff --git a/examples/chess.png b/examples/chess.png
new file mode 100644
Binary files /dev/null and b/examples/chess.png differ
diff --git a/examples/pixelwise.hs b/examples/pixelwise.hs
new file mode 100644
--- /dev/null
+++ b/examples/pixelwise.hs
@@ -0,0 +1,33 @@
+module Main where
+import CV.Image
+import CV.Edges
+import qualified CV.ImageMath as IM
+import CV.ColourUtils
+import CV.Pixelwise
+import CV.Filters
+import qualified CV.Transforms as T
+import Control.Applicative hiding ((<**>))
+
+main = do
+    Just x <- loadImage "smallLena.jpg"
+    let  y = T.flip T.Horizontal x
+         u = T.flip T.Vertical   y
+         z = T.flip T.Vertical   x
+    saveImage "PixelWise.png" $ montage (3,3) 5 
+        [x
+        ,y
+        ,{-#SCC "+" #-} stretchHistogram . toImage $ ((+) <$$> x <+> y)
+        
+        ,{-#SCC "++++" #-} stretchHistogram . toImage $ ((\a b c d -> a+b+c+d) <$$> x 
+                                                           <+> y
+                                                           <+> u
+                                                           <+> z)
+        ,{-#SCC "sin" #-}stretchHistogram . toImage $ fmap (sin . (*9)) . fromImage $ x 
+        ,stretchHistogram . toImage $ fmap log . fromImage $ x 
+        
+        ,stretchHistogram . gaussian (3,3) 
+                          . toImage $ atan2 <$$> (sobel (1,0) s5 x) 
+                                            <+>  (sobel (0,1) s5 x) 
+        ,toImage $ fmap (\x -> if x > 0.5 then 0 else 1) . fromImage $ x
+        ,toImage $ fmap (\x -> if x > 0.5 && x < 0.6 then 0 else 1) . fromImage $ x
+        ]
diff --git a/examples/readFrom.hs b/examples/readFrom.hs
new file mode 100644
--- /dev/null
+++ b/examples/readFrom.hs
@@ -0,0 +1,12 @@
+module Main where
+import CV.Image
+
+main = do
+    x1 <- readFromFile "smallLena.jpg" :: IO (Image GrayScale D32)
+    x2 <- readFromFile "smallLena.jpg" :: IO (Image GrayScale D8)
+    x3 <- readFromFile "smallLena.jpg" :: IO (Image RGB D32)
+    x4 <- readFromFile "smallLena.jpg" :: IO (Image RGB D8)
+    saveImage "x1.png" x1
+    saveImage "x2.png" x2
+    saveImage "x3.png" x3
+    saveImage "x4.png" x4
diff --git a/examples/testCalibrate.hs b/examples/testCalibrate.hs
new file mode 100644
--- /dev/null
+++ b/examples/testCalibrate.hs
@@ -0,0 +1,6 @@
+module Main where
+import CV.Image
+
+import CV.Calibration
+
+main = 
