-
Notifications
You must be signed in to change notification settings - Fork 18
Gabor filter #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Gabor filter #28
Changes from all commits
9c1d31b
08c298f
9b016b3
c2cdcb5
e6b0015
ea50a9b
1509901
4733cf2
2d1de1a
1915739
e1f5626
8757017
aeefdc3
eded16d
4ee7104
5436509
bf8c508
d92fdc4
df4db10
a1f23dd
8fd18c6
258b6ad
fe345d2
22a7003
b4707ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| {-# LANGUAGE RankNTypes #-} | ||
| {-# LANGUAGE FlexibleContexts #-} | ||
| {-# LANGUAGE ScopedTypeVariables #-} | ||
| {-# LANGUAGE BangPatterns #-} | ||
|
|
||
| -- | Adaptive histogram equalization is used to improve contrast in images. | ||
| -- It adjusts image intensity in small regions (neighborhood) in the image. | ||
| module Graphics.Image.Processing.Ahe where | ||
|
|
||
| import Control.Monad (forM_, when) | ||
| import Control.Monad.ST | ||
| import Data.STRef | ||
| import Debug.Trace (trace) | ||
|
|
||
| import Prelude as P hiding (subtract) | ||
| import Graphics.Image.Processing.Filter | ||
| import Graphics.Image.Interface as I | ||
| import Graphics.Image | ||
| import Graphics.Image.Types as IP | ||
| import Graphics.Image.ColorSpace (X) | ||
|
|
||
| -- | Supplementary function for applying border resolution and a general mask. | ||
| simpleFilter :: (Array arr cs e, Array arr X e) => Direction -> Border (Pixel cs e) -> Filter arr cs e | ||
| simpleFilter dir !border = | ||
| Filter (correlate border kernel) | ||
| where | ||
| !kernel = | ||
| case dir of | ||
| Vertical -> fromLists $ [ [ 0, -1, 0 ], [ -1, 4, -1 ], [ 0, -1, 0 ] ] | ||
| Horizontal -> fromLists $ [ [ 0, -1, 0 ], [ -1, 4, -1 ], [ 0, -1, 0 ] ] | ||
|
|
||
| -- | 'ahe' operates on small 'contextual' regions of the image. It enhances the contrast of each | ||
| -- region and this technique works well when the distribution of pixel values is similar throughout | ||
| -- the image. | ||
| -- | ||
| -- The idea is to perform contrast enhancement in 'neighborhood region' of each pixel and the size | ||
| -- of the region is a parameter of the method. It constitutes a characteristic length scale: contrast | ||
| -- at smaller scales is enhanced, while contrast at larger scales is reduced (For general purposes, a size | ||
| -- factor of 5 tends to give pretty good results). | ||
| -- | ||
| -- <<images/yield.jpg>> <<images/yield_ahe.png>> | ||
| -- | ||
| -- Usage : | ||
| -- | ||
| -- >>> img <- readImageY VU "images/yield.jpg" | ||
| -- >>> input1 <- getLine | ||
| -- >>> input2 <- getLine | ||
| -- >>> let thetaSz = (P.read input1 :: Int) | ||
| -- >>> let distSz = (P.read input2 :: Int) | ||
| -- >>> let neighborhoodFactor = (P.read input2 :: Int) | ||
| -- >>> let aheImage :: Image VU RGB Double | ||
| -- >>> aheImage = ahe img thetaSz distSz neighborhoodFactor | ||
| -- >>> writeImage "images/yield_ahe.png" (toImageRGB aheImage) | ||
| -- | ||
| ahe | ||
| :: forall arr e cs . ( MArray arr Y Double, IP.Array arr Y Double, IP.Array arr Y Word16, MArray arr Y Word16, Array arr X Double) | ||
| => Image arr Y Double | ||
| -> Int -- ^ width of output image | ||
| -> Int -- ^ height of output image | ||
| -> Int -- ^ neighborhood size factor | ||
| -> Image arr Y Word16 | ||
| ahe image thetaSz distSz neighborhoodFactor = I.map (fmap toWord16) accBin | ||
| where | ||
| ip = applyFilter (simpleFilter Horizontal Edge) image -- Pre-processing (Border resolution) | ||
| widthMax, var1, heightMax, var2 :: Int | ||
| var1 = ((rows ip) - 1) | ||
| widthMax = ((rows ip) - 1) | ||
| var2 = ((cols ip) - 1) | ||
| heightMax = ((cols ip) - 1) | ||
|
|
||
| accBin :: Image arr Y Word16 | ||
| accBin = runST $ -- Core part of the Algo begins here. | ||
| do arr <- I.new (thetaSz, distSz) -- Create a mutable image with the given dimensions. | ||
| forM_ [0 .. var1] $ \x -> do | ||
| forM_ [0 .. var2] $ \y -> do | ||
| rankRef <- newSTRef (0 :: Int) | ||
| let neighborhood a maxValue = filter (\a -> a >= 0 && a < maxValue) [a-5 .. a+5] | ||
| forM_ (neighborhood x var1) $ \i -> do | ||
| forM_ (neighborhood y var2) $ \j -> do | ||
| when (I.index ip (x, y) > I.index ip (i, j)) $ modifySTRef' rankRef (+1) | ||
| rank <- readSTRef rankRef | ||
| let px = ((rank * 255)) | ||
| I.write arr (x, y) (PixelY (fromIntegral px)) | ||
| freeze arr | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| {-# LANGUAGE RankNTypes #-} | ||
| {-# LANGUAGE FlexibleContexts #-} | ||
| {-# LANGUAGE ScopedTypeVariables #-} | ||
| {-# LANGUAGE BangPatterns #-} | ||
|
|
||
| module Graphics.Image.Processing.Gabor where | ||
|
|
||
| import Control.Monad (forM_, when) | ||
| import Control.Monad.ST | ||
| import Data.STRef | ||
|
|
||
| import Prelude as P hiding (subtract) | ||
| import Graphics.Image.Processing.Filter | ||
| import Graphics.Image.Interface as I | ||
| import Graphics.Image | ||
| import Graphics.Image.Types as IP | ||
| import Graphics.Image.ColorSpace (X) | ||
| import Data.Complex (Complex((:+))) | ||
|
|
||
| gaborfn | ||
| :: (RealFloat p, Fractional p) => p -> p -> p -> p -> p -> p -> p -> Complex p | ||
| gaborfn λ θ ψ σ γ x y = exp ( (-0.5) * ((x'^2 + γ^2*y'^2) / (σ^2)) :+ 0) * exp ( 0 :+ (2*pi*(x'/λ+ψ)) ) | ||
| where x' = x * cos θ + y * sin θ | ||
| y' = -x * sin θ + y * cos θ | ||
| λ = 10.0 | ||
| θ = pi | ||
| ψ = 0 | ||
| σ = 4.0 | ||
| γ = 0.5 | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How did you come up with all these values? They are already supplied as arguments. |
||
|
|
||
| gaborFilter :: (Array arr cs e, Array arr X e, Floating e, Fractional e) => | ||
| Border (Pixel cs e) -- ^ Border resolution technique. | ||
| -> Filter arr cs e | ||
| gaborFilter !border = | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am really confused by this implementation. I might be wrong, but isn't the gabor filter, after getting created with Just by looking at the code it seems as if you are assuming that gabor kernel is separable, which I think is a mistake, so please correct me if I am wrong. |
||
| Filter (correlate border gV' . correlate border gV) | ||
| where | ||
| !gV = compute $ (gabor / scalar weight) | ||
| !gV' = compute $ transpose gV | ||
| !gabor = makeImage (1, n) (promote gaborfn) | ||
| !weight = I.fold (+) 0 gabor | ||
| !n = 5 | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(2*pi*(x'/λ+ψ)), that's incorrect, should be(2*pi*x'/λ+ψ)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's great, you copy pasted it from Wikipedia, even managed to copy it with an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very sorry sir, will correct that. I was unaware of the exact formula and found the haskell version on wiki. Will correct it.