content: {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE TypeFamilies     #-}
  module CV.Sampling where
  
  import CV.Image
  import Control.Monad.Primitive
  import Control.Monad
  import System.Random.MWC
  
  import Foreign.C.Types
  import qualified CV.ImageMath as IM
  import Data.List(partition)
  
  -- Get a patch around every pixel of given size for which it is 
  -- attainable (Enough far from edge)
  allPatches size image = [getRegion (x,y) size image 
                          | x <- [0..w-1], y <- [0..h-1]]
                      where
                       (wi,hi) = getSize image
                       (wp,hp) = size
                       (w,h) = (wi-wp,hi-hp)
  
  allButLast = reverse.tail.reverse 
  -- Get all non-overlapping patches of image
  getTiles size image = getOverlappedTiles size (0,0) image
  getTilesC size image = getOverlappedTilesC size (0,0) image
  
  -- Get Coordinates for overlapping tiles
  getOverlappedTileCoords size (xover,yover) image 
                      = [(x,y)
                        | x <- [0,wstep..wi-w-1]
                        , y <- [0,hstep..hi-h-1]]
                      where
                       (w,h) = size
                       (wi,hi) = getSize image
                       (wstep,hstep) = (floor $ fromIntegral w*(1-xover)
                                       ,floor $ fromIntegral h*(1-yover))
  
  -- Get overlapping tiles
  getOverlappedTiles s o i = map snd $ getOverlappedTilesC s o i  
  getOverlappedTilesC :: (Int,Int) -> (CDouble,CDouble) -> Image c d -> [((Int,Int),Image c d)]
  getOverlappedTilesC size overlap image 
                      = map (\c -> (both fromIntegral c,getRegion c size image))
                              $ getOverlappedTileCoords size 
                                  overlap image
  both f (a,b) = (f a, f b)
                      
  getMarkedAndUnmarkedTiles size overlap image marks = 
      (map fst markedTiles,map fst nonMarked)
      where
          samples = getOverlappedTiles size overlap image
          marked = getOverlappedTiles size overlap marks
          ismarked (_,m) = IM.maxValue m > 0.9
          (markedTiles,nonMarked)  = partition ismarked 
                                      $ zip samples marked
   
  
  -- get patches of image at `coords`
  getPatches size coords image = map (\c -> getRegion c size image) coords
  
  getCenteredPatches size coords image = map (\c -> getRegion (adjust c) 
                                                    size image) 
                                              coords
                                          where
                                           (w,h) = size
                                           adjust (x,y) = (x-w`div`2
                                                          ,y-h`div`2)
  
  ---- Make a random selections in IO monad
  --randomSelect lst = randomRIO (0,length lst -1) >>= \x ->
  --                              return (lst !! x)
                                
  -- select k lst = sequence $ replicate k (randomSelect lst)
  
  -- Discard coords around image borders. Useful for safely picking patches
  discardAroundEdges (iw,ih) (vb,hb) coords = filter inRange coords
      where 
       inRange (x,y) =  vb<x && x< iw-vb
                     && hb<y && y< ih-hb
  
  
  -- Retrive coordinates of white pixels (>0.9, arbitarily) of
  -- image `marks`
  getCoordsFromMarks marks = [(x,y) | x <- [0..w-1]
                                    , y <- [0..h-1]
                                    , getPixel (x,y) marks >0.9]
                          where (w,h) = getSize marks
  
  getMarkedPatches size source marks 
      | getSize source == getSize marks = getPatches size coords source
      | otherwise = error "Image sizes mismatch"                            
      where coords = getCoordsFromMarks marks
  
  
  -- Get some random image patches
  randomPatches size count image gen = do
      coords <- replicateM count $ randomCoord (w,h) gen
      return $ getPatches size coords image
   where
      (pwidth,pheight) = size
      (iwidth,iheight) = getSize image
      (w,h) = (iwidth - pwidth , iheight-pheight) 
  
  -- Get some random pixels from image
  -- randomPixels count image = do
  --    coords <- replicateM count $ randomCoord size
  --    return $ map (flip getPixel $ image) $ coords 
  --  where
  --   size = getSize image
  
  ---- Get some random coords from image
  --randomCoords :: MonadRandom m => Int -> (Int,Int) -> m [(Int,Int)]
  --randomCoords count area = replicateM count $ randomCoord area
  
  randomCoord :: PrimMonad m => (Int,Int) -> Gen (PrimState m) -> m (Int,Int)
  randomCoord (w,h) g = do
              x <- uniformR (0::Int,fromIntegral $ w-1) g
              y <- uniformR (0::Int,fromIntegral $ h-1) g
              return (x,y) 
  