image - Filling the enclosed areas with random colors - Haskell - Friday -


i trying perform not complex image analysis try , find distinct shapes , calculate of parameters area , perimeter (in pixels) , trying in haskell (i wanted try , work functional programming language).

the first task in line count amount of spoons on image: image of 6 spoons using friday haskell package work images.

my idea use friday's edge detection , fill of enclosed areas it's fill function. first 1 require me iterate on image's pixels until i've stumbled upon black pixel. fill area , continue search in image (which has 1 of it's objects filled). color different objects random colors , associate these colors objects find areas , perimeters.

here how image looks after i've applied edge detection it: enter image description here

i unable find way of iterating on of pixels though. i've found read , readlinear functions in following package: https://hackage.haskell.org/package/friday-0.2.2.0/docs/vision-image-mutable.html#v:linearread, not sure how use them , unable deduce type signature since very new haskell.

here code of image reading, grayscaling , edge detecting:

{-# language scopedtypevariables #-} import prelude hiding (filter) import system.environment (getargs)  import vision.detector.edge (canny) import vision.image import vision.image.storage.devil (autodetect (..), load, save)  detectedges :: rgba -> grey detectedges img =   let grey = convert img :: grey       -- img blurring --       blurradius = 2       blurred = gaussianblur blurradius (nothing :: maybe double) grey :: grey        -- sobel applying --       sobelradius = 2       lowthreshold = 256       highthreshold = 1024   in (canny sobelradius lowthreshold highthreshold blurred) :: grey  processimg :: rgba -> rgba processimg img =   let edges = detectedges img   -- here goes of important stuff   in convert edges :: rgba  main :: io () main =   [input, output] <- getargs    io <- load autodetect input   case io of     left err             ->       putstrln "unable load image:"       print err      right (img :: rgba)  ->       merr <- save autodetect output (processimg img)       case merr of         nothing  ->           putstrln "success."         err ->           putstrln "unable save image:"           print err 

thank in advance.

how find area , perimeter of connected components?

you can use contour tracing vision.image.contour contour perimeters. first lets start getting edges have:

{-# language scopedtypevariables #-} import prelude p import system.environment (getargs)  import vision.detector.edge (canny) import vision.image import vision.primitive.shape import vision.image.storage.devil (autodetect (..), load, save) import vision.image.transform(floodfill) import control.monad.st (runst, st) import vision.image.contour  -- detects edge of image canny's edge detector. -- -- usage: ./canny input.png output.png main :: io () main =     [input, output] <- getargs      -- loads image. automatically infers format.     io <- load autodetect input      case io of         left err             ->             putstrln "unable load image:"             print err         right (grey :: grey) ->             let blurred, edges :: grey                 edges = canny 2 256 1024 blurred :: grey 

here's acquire contours. due bug in draw function, use later, i'll blur first contours distinct inner , outer points. patched eventually...

                cs           = contours (blur 2 edges :: grey)                 goodcontours = p.filter goodsize (allcontourids cs) 

now have value of contours type includes valid contourid each connected component. each contourid can area contoursize , perimeter contourperimeter. size of perimeter length of list of perimeter points.

i did overly-tailored filter, called goodsize spoons, can play area , perimeter you'd like:

                goodsize x   = let ((xmin,xmax),(ymin,ymax)) = contourbox cs x                                in xmax-xmin > 60 && xmax-xmin < 500 &&                                   ymax-ymin > 100 && ymax-ymin < 500                  final, filledcontours :: rgba                 filledcontours =                    convert $ drawcontours cs (shape edges) fill goodcontours 

optionally, each contour use floodfill color. here use 3 colors , fill whichever contours first in list. contours list ordered top-to-bottom left-to-right odd-ish. sortby xmin goodcontours left-right ordering.

                floodstart = concatmap (take 1 . contourperimeter cs) goodcontours                 colors = cycle [rgbapixel 255 0 0 255, rgbapixel 0 255 0 255, rgbapixel 0 0 255 255]                 final = runst dofill 

the fill operation using st monad, can find many questions here on stackoverflow.

                dofill :: forall s. st s rgba                 dofill =                           m <- thaw filledcontours :: st s (mutablemanifest rgbapixel s)                           mapm_ (\(p,c) -> floodfill p c m) (zip floodstart colors)                           return =<< unsafefreeze m              -- saves edges image. automatically infers output format.             merr <- save autodetect output final             case merr of                 nothing  ->                     putstrln "success."                 err ->                     putstrln "unable save image:"                     print err  contourbox cs x =   let ps = contourperimeter cs x       (xs,ys) = unzip $ p.map (\(z :. x :. y) -> (x,y)) ps   in ((minimum xs, maximum xs), (minimum ys, maximum ys)) 

the end result is:

rgb spoons


Comments

Popular posts from this blog

routing - AngularJS State management ->load multiple states in one page -

python - GRASS parser() error -

Swift game error message -