cv-combinators-0.1.2.2: src/IntegratedTest.hs
{-# LANGUAGE FlexibleContexts #-}
module Main where
import qualified AI.CV.ImageProcessors as IP
import qualified Graphics.DrawingCombinators as Draw
import Graphics.DrawingCombinators((%%))
import qualified Graphics.GraphicsProcessors as GP
import qualified AI.CV.OpenCV.CV as CV
import qualified Control.Processor as Processor
import Control.Processor(DTime, DClock, scanlT, IOSource, IOProcessor)
import AI.CV.OpenCV.CxCore(CvRect(..), CvSize(..))
import Data.VectorSpace((*^), zeroV, (^+^), Scalar, VectorSpace)
import Prelude hiding ((.),id)
import Control.Arrow
import Control.Category
import Data.Monoid
resX, resY :: Num a => a
resX = 160
resY = 120
resizer :: IP.ImageProcessor
resizer = IP.resize resX resY CV.CV_INTER_LINEAR
faceDetect :: IOProcessor IP.Image [CvRect]
faceDetect = IP.haarDetect "/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml" 1.1 3 CV.cvHaarFlagNone (CvSize 20 20)
captureDev :: IP.ImageSource
--captureDev = videoFile "/tmp/video.flv" -- Many formats are supported, not just flv (FFMPEG-based, normally).
-- If you have a webcam, uncomment this, and comment the other definition.
captureDev = IP.camera 0
square :: Draw.Image Any
square = Draw.rotate (pi/4) %% Draw.regularPoly (4 :: Int)
drawCvRect :: CvRect -> Draw.Image Any
drawCvRect (CvRect x y w h) = tr %% Draw.tint (Draw.Color 0 1 0 0.5) square
where tr = Draw.translate (1 - (2*x'/resX + w'/resX), 1 - (2*y'/resY + h'/resY))
`mappend` (Draw.scale (2*w'/resX) (2*h'/resY))
w' = fromIntegral w
h' = fromIntegral h
x' = fromIntegral x
y' = fromIntegral y
--drawRects :: IP.ImageSink
--drawRects = arr (mconcat . drawCvRects) --fmap (mconcat . map drawCvRect) id
-- where drawCvRects = map drawCvRect
clock :: IO Double -- = DClock Double
clock = return 1 -- todo implement really in some module that wraps SDL, GLUT or whatever.
-- todo: ins't this just an n-step past memory? generalize a bit and move to Processor package?
movingAverage :: Int -> ([(DTime, b)] -> c) -> (DTime, b) -> c -> IOSource a b -> IOProcessor a c
movingAverage n f initA initB p = (scanlT clock f' (take n . repeat $ initA, initB) p) >>> arr snd
where f' _ y2 dt (lastNSamps, _) = (nextSamps, f nextSamps )
where nextSamps = (dt, y2) : (tail lastNSamps)
-- todo: this is a general function, perhaps move to a module?
averageV :: (Fractional (Scalar a), VectorSpace a) => [Scalar a] -> [a] -> a
averageV weights samps = ((1/n) *^) . foldr (^+^) zeroV $ zipWith (*^) weights samps
where n = fromIntegral (length weights)
-- todo: this is a general function, perhaps move to Processor package?
movingCvRectAverage :: (Fractional (Scalar v), VectorSpace v) => [Scalar v] -> IOProcessor a [v] -> IOProcessor a v
movingCvRectAverage weights pIn = movingAverage (length weights) (averageV weights . map snd) (0, zeroV) zeroV pIn'
where pIn' = pIn >>> arr headOrZero
headOrZero [] = zeroV
headOrZero xs = head xs
main :: IO ()
main = Processor.runUntil (captureDev >>> resizer >>> avgRect faceDetect >>> arr drawCvRect >>> sdlWindow) () (const . return $ False)
where avgRect = movingCvRectAverage [2,1,1,0]
sdlWindow = GP.sdlWindow resX resY