packages feed

hip 1.5.3.0 → 1.5.4.0

raw patch · 20 files changed

+431/−21 lines, 20 filesdep +arraydep +randombinary-addedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: array, random

API changes (from Hackage documentation)

- Graphics.Image.Types: }
+ Graphics.Image: canvasSize :: Array arr cs e => Border (Pixel cs e) -> (Int, Int) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: crop :: Array arr cs e => (Int, Int) -> (Int, Int) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: downsample :: Array arr cs e => (Int -> Bool) -> (Int -> Bool) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: downsampleCols :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: downsampleRows :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: flipH :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: flipV :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: leftToRight :: Array arr cs e => Image arr cs e -> Image arr cs e -> Image arr cs e
+ Graphics.Image: resize :: (Interpolation method, Array arr cs e) => method -> Border (Pixel cs e) -> (Int, Int) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: rotate :: (Array arr cs e, Interpolation method) => method -> Border (Pixel cs e) -> Double -> Image arr cs e -> Image arr cs e
+ Graphics.Image: rotate180 :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: rotate270 :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: rotate90 :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: scale :: (Interpolation method, Array arr cs e) => method -> Border (Pixel cs e) -> (Double, Double) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: superimpose :: Array arr cs e => (Int, Int) -> Image arr cs e -> Image arr cs e -> Image arr cs e
+ Graphics.Image: topToBottom :: Array arr cs e => Image arr cs e -> Image arr cs e -> Image arr cs e
+ Graphics.Image: translate :: Array arr cs e => Border (Pixel cs e) -> (Int, Int) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: upsample :: Array arr cs e => (Int -> (Int, Int)) -> (Int -> (Int, Int)) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: upsampleCols :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image: upsampleRows :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image.ColorSpace: data family Pixel cs e :: *
+ Graphics.Image.IO.Formats: -- | Options that can be used during writing an image in this format.
+ Graphics.Image.Interface: -- | Underlying image representation.
+ Graphics.Image.Processing.Ahe: ahe :: forall arr e cs. (MArray arr Y Double, Array arr Y Double, Array arr Y Word16, MArray arr Y Word16, Array arr X Double) => Image arr Y Double -> Int -> Int -> Int -> Image arr Y Word16
+ Graphics.Image.Processing.Ahe: simpleFilter :: (Array arr cs e, Array arr X e) => Direction -> Border (Pixel cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Binary: infix 4 !>!
+ Graphics.Image.Processing.Filter: Filter :: (Image arr cs e -> Image arr cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Filter: [applyFilter] :: Filter arr cs e -> Image arr cs e -> Image arr cs e
+ Graphics.Image.Processing.Filter: gaussianSmoothingFilter :: (Fractional e, Array arr cs e, Array arr X e) => Border (Pixel cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Filter: laplacianFilter :: (Array arr cs e, Array arr X e) => Border (Pixel cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Filter: logFilter :: (Array arr cs e, Array arr X e) => Border (Pixel cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Filter: meanFilter :: (Fractional e, Array arr cs e, Array arr X e) => Border (Pixel cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Filter: unsharpMaskingFilter :: (Fractional e, Array arr cs e, Array arr X e) => Border (Pixel cs e) -> Filter arr cs e
+ Graphics.Image.Processing.Hough: dotProduct :: Num x => (x, x) -> (x, x) -> x
+ Graphics.Image.Processing.Hough: fromIntegralP :: (Integral x, Num y) => (x, x) -> (y, y)
+ Graphics.Image.Processing.Hough: hough :: forall arr. (MArray arr Y Double, Array arr Y Double, Array arr Y Word8) => Image arr Y Double -> Int -> Int -> Image arr Y Word8
+ Graphics.Image.Processing.Hough: mag :: Floating x => (x, x) -> x
+ Graphics.Image.Processing.Hough: sub :: Num x => (x, x) -> (x, x) -> (x, x)
+ Graphics.Image.Processing.Noise: randomCoords :: StdGen -> Int -> Int -> [(Int, Int)]
+ Graphics.Image.Processing.Noise: saltAndPepper :: forall arr e cs. (MArray arr Y Double, Array arr Y Double) => Image arr Y Double -> Float -> StdGen -> Image arr Y Double
- Graphics.Image.ColorSpace: (:+) :: ~a -> ~a -> Complex a
+ Graphics.Image.ColorSpace: (:+) :: !a -> !a -> Complex a
- Graphics.Image.ColorSpace: class ToCMYK cs e => ToCMYKA cs e where toPixelCMYKA = addAlpha 1 . toPixelCMYK
+ Graphics.Image.ColorSpace: class ToCMYK cs e => ToCMYKA cs e
- Graphics.Image.ColorSpace: class ToHSI cs e => ToHSIA cs e where toPixelHSIA = addAlpha 1 . toPixelHSI
+ Graphics.Image.ColorSpace: class ToHSI cs e => ToHSIA cs e
- Graphics.Image.ColorSpace: class ToRGB cs e => ToRGBA cs e where toPixelRGBA = addAlpha 1 . toPixelRGB
+ Graphics.Image.ColorSpace: class ToRGB cs e => ToRGBA cs e
- Graphics.Image.ColorSpace: class ToY cs e => ToYA cs e where toPixelYA = addAlpha 1 . toPixelY
+ Graphics.Image.ColorSpace: class ToY cs e => ToYA cs e
- Graphics.Image.ColorSpace: class ToYCbCr cs e => ToYCbCrA cs e where toPixelYCbCrA = addAlpha 1 . toPixelYCbCr
+ Graphics.Image.ColorSpace: class ToYCbCr cs e => ToYCbCrA cs e
- Graphics.Image.ColorSpace: data Complex a :: * -> *
+ Graphics.Image.ColorSpace: data Complex a
- Graphics.Image.ColorSpace: data Word16 :: *
+ Graphics.Image.ColorSpace: data Word16
- Graphics.Image.ColorSpace: data Word32 :: *
+ Graphics.Image.ColorSpace: data Word32
- Graphics.Image.ColorSpace: data Word64 :: *
+ Graphics.Image.ColorSpace: data Word64
- Graphics.Image.ColorSpace: data Word8 :: *
+ Graphics.Image.ColorSpace: data Word8
- Graphics.Image.IO.Formats: class ImageFormat format where data SaveOption format exts f = [ext f] isFormat e f = e `elem` exts f where {
+ Graphics.Image.IO.Formats: class ImageFormat format where {
- Graphics.Image.IO.Formats: data GifLooping :: *
+ Graphics.Image.IO.Formats: data GifLooping
- Graphics.Image.IO.Formats: data PaletteCreationMethod :: *
+ Graphics.Image.IO.Formats: data PaletteCreationMethod
- Graphics.Image.IO.Formats: data PaletteOptions :: *
+ Graphics.Image.IO.Formats: data PaletteOptions
- Graphics.Image.Interface: class (ColorSpace (Opaque cs) e, ColorSpace cs e) => AlphaSpace cs e where type Opaque cs where {
+ Graphics.Image.Interface: class (ColorSpace (Opaque cs) e, ColorSpace cs e) => AlphaSpace cs e where {
- Graphics.Image.Interface: class (Vector (Vector arr) (Pixel cs e), MArray (Manifest arr) cs e, BaseArray arr cs e) => Array arr cs e where type Manifest arr :: * type Vector arr :: * -> * where {
+ Graphics.Image.Interface: class (Vector (Vector arr) (Pixel cs e), MArray (Manifest arr) cs e, BaseArray arr cs e) => Array arr cs e where {
- Graphics.Image.Interface: class (Typeable arr, ColorSpace cs e, SuperClass arr cs e) => BaseArray arr cs e where type SuperClass arr cs e :: Constraint data Image arr cs e where {
+ Graphics.Image.Interface: class (Typeable arr, ColorSpace cs e, SuperClass arr cs e) => BaseArray arr cs e where {
- Graphics.Image.Interface: class (Eq cs, Enum cs, Show cs, Bounded cs, Typeable cs, Eq (Pixel cs e), Unbox (Components cs e), Elevator e) => ColorSpace cs e where type Components cs e foldrPx f !z0 !xs = foldlPx f' id xs z0 where f' k x !z = k $! f x z foldlPx f !z0 !xs = foldrPx f' id xs z0 where f' x k !z = k $! f z x foldl1Px f !xs = fromMaybe (error "foldl1Px: empty Pixel") (foldlPx mf Nothing xs) where mf m !y = Just (case m of { Nothing -> y Just x -> f x y }) toListPx !px = foldr' f [] (enumFrom (toEnum 0)) where f !cs !ls = getPxC px cs : ls where {
+ Graphics.Image.Interface: class (Eq cs, Enum cs, Show cs, Bounded cs, Typeable cs, Eq (Pixel cs e), Unbox (Components cs e), Elevator e) => ColorSpace cs e where {
- Graphics.Image.Interface: class BaseArray arr cs e => MArray arr cs e where data MImage s arr cs e where {
+ Graphics.Image.Interface: class BaseArray arr cs e => MArray arr cs e where {
- Graphics.Image.Types: class BaseArray arr cs e => MArray arr cs e where data MImage s arr cs e where {
+ Graphics.Image.Types: class BaseArray arr cs e => MArray arr cs e
- Graphics.Image.Types: data family MImage s arr cs e;
+ Graphics.Image.Types: data family MImage s arr cs e

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+1.5.4.0+=======++* Addition of `disable-chart` flag+* Bunch of semi-functional stuff from GSoC 2018+ 1.5.2.0 ======= 
README.md view
@@ -3,9 +3,9 @@  Haskell Image Processing (HIP) Library -Documentation is on [Hackage](http://hackage.haskell.org/package/hip), and [Stackage](https://www.stackage.org/nightly/package/hip).+Documentation is on [Hackage](http://hackage.haskell.org/package/hip), and [Stackage](https://www.stackage.org/package/hip). -[![Build Status](https://travis-ci.org/lehins/hip.svg?branch=master)](https://travis-ci.org/lehins/hip) +[![Build Status](https://travis-ci.org/lehins/hip.svg?branch=master)](https://travis-ci.org/lehins/hip) [![Hackage](https://img.shields.io/hackage/v/hip.svg?style=flat)](https://hackage.haskell.org/package/hip)  Installation
hip.cabal view
@@ -1,5 +1,5 @@ Name:              hip-Version:           1.5.3.0+Version:           1.5.4.0 License:           BSD3 License-File:      LICENSE Author:            Alexey Kuleshevich@@ -16,7 +16,7 @@             It is capable of reading and writing a number of popular image formats by using <https://hackage.haskell.org/package/JuicyPixels JuciyPixels> and <https://hackage.haskell.org/package/netpbm netpbm> packages. Being a pure Haskell library it does not require any external programs, although it can display images using a program of your choice. Homepage:          https://github.com/lehins/hip Bug-Reports:       https://github.com/lehins/hip/issues-Cabal-Version:     >= 1.10+Cabal-Version:     >= 1.18 Build-Type:        Simple Extra-Doc-Files:   images/*.jpg                  , images/*.png@@ -25,25 +25,36 @@                  , images/*.svg                  , README.md                    CHANGELOG.md++Flag disable-chart+  Description: Disable Chart-diagrams and Chart for a lighter dependency footprint+  Default: False+  Manual: True+ Library   Default-Language: Haskell2010   HS-Source-Dirs: src -  Build-Depends: Chart           >= 1.5-               , Chart-diagrams  >= 1.5-               , JuicyPixels     >= 3.2.7+  Build-Depends:+                 JuicyPixels     >= 3.2.7                , base            >= 4.5 && < 5                , bytestring      >= 0.9.0.4                , colour          >= 2.3.3                , deepseq         >= 1.1                , directory       >= 1.2.2.0                , filepath        >= 1.0-               , netpbm          >= 1.0.1                , primitive       >= 0.4                , process         >= 1.1.0.0                , repa            >= 3.2.1.1 && < 4                , temporary       >= 1.1.1                , vector          >= 0.10+               , array+               , random+               , netpbm          >= 1.0.1+  if !flag(disable-chart)+    Build-Depends:+                 Chart           >= 1.5+               , Chart-diagrams  >= 1.5   Other-Extensions: BangPatterns                   , ConstraintKinds                   , CPP@@ -59,7 +70,6 @@                  , Graphics.Image.ColorSpace                  , Graphics.Image.IO                  , Graphics.Image.IO.Formats-                 , Graphics.Image.IO.Histogram                  , Graphics.Image.Interface                  , Graphics.Image.Interface.Repa                  , Graphics.Image.Interface.Vector@@ -67,7 +77,12 @@                  , Graphics.Image.Processing.Binary                  , Graphics.Image.Processing.Complex                  , Graphics.Image.Processing.Filter+                 , Graphics.Image.Processing.Hough+                 , Graphics.Image.Processing.Ahe+                 , Graphics.Image.Processing.Noise                  , Graphics.Image.Types+  if !flag(disable-chart)+    Exposed-Modules: Graphics.Image.IO.Histogram   Other-Modules:   Graphics.Image.ColorSpace.Binary                  , Graphics.Image.ColorSpace.CMYK                  , Graphics.Image.ColorSpace.Complex@@ -78,7 +93,6 @@                  , Graphics.Image.ColorSpace.YCbCr                  , Graphics.Image.IO.Base                  , Graphics.Image.IO.Formats.JuicyPixels-                 , Graphics.Image.IO.Formats.Netpbm                  , Graphics.Image.Interface.Elevator                  , Graphics.Image.Interface.Repa.Generic                  , Graphics.Image.Interface.Repa.Storable@@ -92,7 +106,10 @@                  , Graphics.Image.Processing.Geometric                  , Graphics.Image.Processing.Interpolation                  , Graphics.Image.Utils+                 , Graphics.Image.IO.Formats.Netpbm   GHC-Options:     -Wall+  if flag(disable-chart)+    CPP-Options: -DDISABLE_CHART   if os(windows)     CPP-Options:      -DOS_Win32   else@@ -113,6 +130,7 @@                     , Graphics.Image.Interface.VectorSpec                     , Graphics.Image.Interface.RepaSpec                     , Graphics.Image.IO.FormatsSpec+  Build-Tool-Depends: hspec-discover:hspec-discover   Build-Depends:      base            >= 4.5 && < 5                     , bytestring                     , hip@@ -145,6 +163,8 @@                      , criterion                      , hip   default-language:    Haskell2010+  if flag(disable-chart)+    Buildable:         False   Source-Repository head
+ images/GSM_gsn_yield_IP.jpg view

binary file changed (absent → 7083 bytes)

+ images/GSM_gsn_yield_OP.png view

binary file changed (absent → 96153 bytes)

+ images/yield_ahe.png view

binary file changed (absent → 56049 bytes)

+ images/yield_gray.png view

binary file changed (absent → 38253 bytes)

+ images/yield_hough.png view

binary file changed (absent → 32670 bytes)

+ images/yield_laplacian.png view

binary file changed (absent → 36750 bytes)

+ images/yield_log.png view

binary file changed (absent → 21502 bytes)

+ images/yield_mean.png view

binary file changed (absent → 74621 bytes)

+ images/yield_snp.png view

binary file changed (absent → 45119 bytes)

+ images/yield_unsharpMasking.png view

binary file changed (absent → 29402 bytes)

src/Graphics/Image.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_GHC -fno-warn-unused-imports -fno-warn-duplicate-exports #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} -- |@@ -118,7 +119,9 @@ import Graphics.Image.Processing.Binary as IP import Graphics.Image.Processing.Complex as IP import Graphics.Image.Processing.Geometric as IP+#ifndef DISABLE_CHART import Graphics.Image.IO.Histogram as IP+#endif   -- | Create an image with a specified representation and pixels of 'Double'@@ -131,7 +134,7 @@ -- Because all 'Pixel's and 'Image's are installed into 'Num', above is equivalent to: -- -- >>> let grad_gray = makeImageR RPU (200, 200) (\(i, j) -> PixelY $ fromIntegral (i*j)) / (200*200)--- >>> writeImage "images/grad_gray.png" grad_gray+-- >>> writeImage "images/grad_gray.png" (grad_gray :: Image RPU Y Double) -- -- Creating color images is just as easy. --
src/Graphics/Image/IO/Formats.hs view
@@ -79,7 +79,8 @@                           , Readable (Image arr cs Double) PNG                           , Readable (Image arr cs Double) TGA                           , Readable (Image arr cs Double) TIF-                          , Readable (Image arr cs Double) PPM )+                          , Readable (Image arr cs Double) PPM+                          )   instance AllReadable arr cs => Readable (Image arr cs Double) InputFormat where
src/Graphics/Image/Interface.hs view
@@ -250,8 +250,8 @@   -- | Backwards permutation of an image.   backpermute :: (Int, Int) -- ^ Dimensions of a result image.               -> ((Int, Int) -> (Int, Int))-                 -- ^ Function that maps an index of a source image to an index-                 -- of a result image.+                 -- ^ Function that maps an index of a result image to an index+                 -- of a source image.               -> Image arr cs e -- ^ Source image.               -> Image arr cs e -- ^ Result image. 
+ src/Graphics/Image/Processing/Ahe.hs view
@@ -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   +
src/Graphics/Image/Processing/Filter.hs view
@@ -14,7 +14,7 @@ -- module Graphics.Image.Processing.Filter   ( -- * Filter-    Filter+    Filter (..)   , applyFilter   , Direction(..)     -- * Gaussian@@ -26,6 +26,16 @@     -- * Prewitt   , prewittFilter   , prewittOperator+    -- * Laplacian+  , laplacianFilter+    -- * Laplacian of Gaussian+  , logFilter+    -- * Gaussian Smoothing+  , gaussianSmoothingFilter+    -- * Mean +  , meanFilter+    -- * Unsharp Masking+  , unsharpMaskingFilter     ) where  @@ -46,8 +56,6 @@   = Vertical   | Horizontal -- -- | Create a Gaussian Filter. -- -- @since 1.5.3@@ -95,7 +103,7 @@                                   , [  0,  0,  0 ]                                   , [  1,  2,  1 ] ]         Horizontal -> fromLists $ [ [ -1, 0, 1 ]-                                  , [ -2, 0, 1 ]+                                  , [ -2, 0, 2 ]                                   , [ -1, 0, 1 ] ] {-# INLINE sobelFilter #-} @@ -118,8 +126,6 @@ {-# INLINE sobelOperator #-}  -- prewittFilter :: (Array arr cs e, Array arr X e) =>                  Direction -> Border (Pixel cs e) -> Filter arr cs e prewittFilter dir !border =@@ -132,10 +138,121 @@ {-# INLINE prewittFilter #-}  - prewittOperator :: (Array arr cs e, Array arr X e, Floating e) => Image arr cs e -> Image arr cs e prewittOperator !img = sqrt (prewittX ^ (2 :: Int) + prewittY ^ (2 :: Int))   where !prewittX = applyFilter (prewittFilter Horizontal Edge) img         !prewittY = applyFilter (prewittFilter Vertical Edge) img {-# INLINE prewittOperator #-}+++-- |The Laplacian of an image highlights regions of rapid intensity change+-- and is therefore often used for edge detection. It is often applied to an+-- image that has first been smoothed with something approximating a+-- Gaussian smoothing filter in order to reduce its sensitivity to noise.+-- More info about the algo at <https://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm>+--+-- <<images/yield.jpg>>   <<images/yield_laplacian.png>>+--+laplacianFilter :: (Array arr cs e, Array arr X e) =>+                   Border (Pixel cs e) -> Filter arr cs e+laplacianFilter !border =+  Filter (correlate border kernel)+  where+    !kernel = fromLists $ [ [ -1, -1, -1 ]   -- Unlike the Sobel edge detector, the Laplacian edge detector uses only one kernel. +                        , [  -1, 8, -1 ]     -- It calculates second order derivatives in a single pass. +                        , [  -1, -1, -1 ]]   -- This is the approximated kernel used for it. (Includes diagonals)+{-# INLINE laplacianFilter #-}++-- | 'Laplacian of Gaussian' (LOG) filter is a two step process of smoothing+-- an image before applying some derivative filter on it. This comes in+-- need for reducing the noise sensitivity while working with noisy+-- datasets or in case of approximating second derivative measurements.+-- +-- The LoG operator takes the second derivative of the image. Where the image+-- is basically uniform, the LoG will give zero. Wherever a change occurs, the LoG will+-- give a positive response on the darker side and a negative response on the lighter side.+-- More info about the algo at <https://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm>+--+-- <<images/yield.jpg>>   <<images/yield_log.png>>+--+logFilter :: (Array arr cs e, Array arr X e) =>+             Border (Pixel cs e) -> Filter arr cs e+logFilter !border =+  Filter (correlate border kernel)+  where+    !kernel = fromLists $ [ [ 0, 1, 1, 2, 2, 2, 1, 1, 0 ]+                          , [  1,  2,  4, 5, 5, 5, 4, 2, 1 ]+                          , [  1,  4,  5, 3, 0, 3, 5, 4, 1 ]+                          , [  2,  5,  3, -12, -24, -12, 3, 5, 2 ]+                          , [  2,  5,  0, -24, -40, -24, 0, 5, 2  ]+                          , [  2,  5,  3, -12, -24, -12, 3, 5, 2  ]+                          , [  1,  4,  5, 3, 0, 3, 5, 4, 1  ]+                          , [  1,  2,  4, 5, 5, 5, 4, 2, 1  ]+                          , [  0,  1,  1, 2, 2, 2, 1, 1, 0  ] ]+{-# INLINE logFilter #-}++-- | The Gaussian smoothing operator is a 2-D convolution operator that is used to +-- `blur' images and remove detail and noise. The idea of Gaussian smoothing is to use +-- this 2-D distribution as a `point-spread' function, and this is achieved by convolution. +-- Since the image is stored as a collection of discrete pixels we need to produce a +-- discrete approximation to the Gaussian function before we can perform the convolution. +-- More info about the algo at <https://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htm>+-- +-- <<images/GSM_gsn_yield_IP.jpg>> <<images/GSM_gsn_yield_OP.png>> +--+gaussianSmoothingFilter :: (Fractional e, Array arr cs e, Array arr X e) =>+                           Border (Pixel cs e) -> Filter arr cs e+gaussianSmoothingFilter !border =+  Filter (I.map (/ 273) . correlate border kernel)+  where+    !kernel = fromLists $ [[ 1, 4, 7, 4, 1 ]     -- Discrete approximation to the Gaussian function.+                          ,[  4, 16, 26, 16, 4 ] -- 273 is the sum of all values in the mask and hence used in rescaling.+                          ,[  7, 26, 41, 26, 7 ]+                          ,[  4, 16, 26, 16, 4 ]+                          ,[ 1, 4, 7, 4, 1 ]]++{-# INLINE gaussianSmoothingFilter #-}    +++-- | The mean filter is a simple sliding-window spatial filter that replaces the +-- center value in the window with the average (mean) of all the pixel values in +-- the window. The window, or kernel, can be any shape, but this one uses the most +-- common 3x3 square kernel.+-- More info about the algo at <http://homepages.inf.ed.ac.uk/rbf/HIPR2/mean.htm>+-- +-- <<images/yield.jpg>>   <<images/yield_mean.png>>+-- +meanFilter :: (Fractional e, Array arr cs e, Array arr X e) =>+                           Border (Pixel cs e) -> Filter arr cs e+meanFilter !border =+  Filter (I.map (/ 9) . correlate border kernel)+  where +    !kernel = fromLists $[ [ 1, 1, 1 ]       -- Replace each pixel with the mean value of its neighbors, including itself.+                          , [  1, 1, 1 ]   +                          , [  1, 1, 1 ]]++{-# INLINE meanFilter #-}++-- | The unsharp-masking filter is a sharpening operator which derives its name from+-- the fact that it enhances edges (and other high frequency components in an image) +-- via a procedure which subtracts an unsharp, or smoothed, version of an image from+-- the original image. It is commonly used in the photographic and printing industries +-- for crispening edges.+-- More info about the algo at <https://homepages.inf.ed.ac.uk/rbf/HIPR2/unsharp.htm>+--+-- <<images/yield_gray.png>>   <<images/yield_unsharpMasking.png>>+--+unsharpMaskingFilter :: (Fractional e, Array arr cs e, Array arr X e) =>+                           Border (Pixel cs e) -> Filter arr cs e+unsharpMaskingFilter !border =+  Filter (I.map (/256) . correlate border kernel)+  where +    !kernel = fromLists $ [[ -1, -4, -6, -4, -1 ]     +                          ,[  -4, -16, -24, -16, -4 ]    -- Uses negative image to create a mask of the original image.+                          ,[  -6, -24, 476, -24, -6 ]    -- The unsharped mask is then combined with the positive (original) image.+                          ,[  -4, -16, -24, -16, -4 ]    -- So, the resulting image is less blurry, i.e clearer.+                          ,[ -1, -4, -6, -4, -1 ]]++{-# INLINE unsharpMaskingFilter #-}+ 
+ src/Graphics/Image/Processing/Hough.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Hough Transform is used as a part of feature extraction in images. +-- It is a tool that makes it far easier to identify straight lines in+-- the source image, whatever their orientation.+module Graphics.Image.Processing.Hough where++import Control.Monad (forM_, when)+import qualified Data.Foldable as F (maximum)+import Data.Array+import Data.Array.ST (newArray, writeArray, readArray, runSTArray)++import Prelude as P hiding (subtract)+import Graphics.Image+import Graphics.Image.Interface as I+import Graphics.Image.Types as IP++-- | Some helper functions :+-- | Trivial function for subtracting co-ordinate pairs +sub :: Num x => (x, x) -> (x, x) -> (x, x)+sub (x1, y1) (x2, y2) = (x1 - x2, y1 - y2)++-- | Compute the sum of squares or dot product of a given pair of co-ordinates+dotProduct :: Num x => (x, x) -> (x, x) -> x+dotProduct (x1, y1) (x2, y2) = (x1 * x2) + (y1 * y2)++-- | Conversion of pair fromIntegral+fromIntegralP :: (Integral x, Num y) => (x, x) -> (y, y)+fromIntegralP (x1, y1) = (fromIntegral x1, fromIntegral y1)++-- | Compute magnitude+mag :: Floating x => (x, x) -> x+mag x = sqrt (dotProduct x x)++-- | 'hough' computes the Linear Hough Transform and maps each point in the target image, ​ (ρ, θ) ​ +-- to the average color of the pixels on  the corresponding line of the source image ​(x,y) ​- space,+-- where the line corresponds to points of the form ​(xcosθ + ysinθ = ρ(rho)). +--+-- The idea is that where there is a straight line in the original image, it corresponds to a +-- bright (or dark, depending on the color of the background field) spot; by applying a suitable +-- filter to the results of the transform, it is possible to extract the locations of the lines in the original image.+--+-- <<images/yield.jpg>>   <<images/yield_hough.png>>+--+-- Usage : +--	+-- >>> frog <- readImageRGB VU "yield.jpg"+-- >>> input1 <- getLine+-- >>> input2 <- getLine+-- >>> let thetaSz = (P.read input1 :: Int)+-- >>> let distSz = (P.read input2 :: Int)+-- >>> let houghImage :: Image VU RGB Double+-- >>>     houghImage = hough frog thetaSz distSz+-- >>> writeImage "test.png" houghImage+--+hough+  :: forall arr . ( MArray arr Y Double, IP.Array arr Y Double, IP.Array arr Y Word8)+  => Image arr Y Double+  -> Int+  -> Int+  -> Image arr Y Word8+hough image thetaSz distSz = I.map (fmap toWord8) hImage+ where+   widthMax, xCtr, heightMax, yCtr :: Int+   widthMax = ((rows image) - 1)+   xCtr = (widthMax `div` 2)+   heightMax = ((cols image) - 1)+   yCtr = (heightMax `div` 2)++   slope :: Int -> Int -> (Double, Double)+   slope x y =+     let PixelY orig = I.index image (x, y)+         PixelY x' = I.index image (min (x+1) widthMax, y)+         PixelY y' = I.index image (x, min (y+1) heightMax)+     in (orig - x', orig - y')++   slopeMap :: [ ((Int, Int), (Double, Double)) ]+   slopeMap = [ ((x, y), slope x y) | x <- [0 .. widthMax], y <- [0 .. heightMax] ]++   distMax :: Double -- Compute Maximum distance+   distMax = (sqrt . fromIntegral $ (heightMax + 1) ^ (2 :: Int) + (widthMax + 1) ^ (2 :: Int)) / 2 ++   accBin = runSTArray $   -- Core part of Algo begins here. Working in a safe way with a mutable array.+     do arr <- newArray ((0, 0), (thetaSz, distSz)) (0 :: Double) -- Build a new array, with every element initialised to the supplied value.+        forM_ slopeMap $ \((x, y), gradient) -> do+            let (x', y') = fromIntegralP $ (xCtr, yCtr) `sub` (x, y)+            when (mag gradient > 0) $+              forM_ [0 .. thetaSz] $ \theta -> do+                let theta_ =+                      fromIntegral theta * 360 / fromIntegral thetaSz / 180 *+                      pi :: Double+                    distance = cos theta_ * x' + sin theta_ * y'    -- (ρ(rho) = xcosθ + ysinθ)+                    distance_ = truncate $ distance * fromIntegral distSz / distMax -- returns the nearest integer+                    idx = (theta, distance_)+                when (distance_ >= 0 && distance_ < distSz) $+                  do old <- readArray arr idx      -- read an element at 'idx' from mutable array 'arr'+                     writeArray arr idx (old + 1)+        return arr++   maxAcc = F.maximum accBin  +   hTransform (x, y) =+        let l = 255 - truncate ((accBin ! (x, y)) / maxAcc * 255) -- pixel generating function+        in PixelY l++   hImage :: Image arr Y Word8+   hImage = makeImage (thetaSz, distSz) hTransform+
+ src/Graphics/Image/Processing/Noise.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns #-} ++module Graphics.Image.Processing.Noise where++import Control.Monad (forM_)+import Control.Monad.ST+import System.Random++import Prelude as P hiding (subtract)+import Graphics.Image.Interface as I+import Graphics.Image+import Graphics.Image.Types as IP++-- | Helper function for generating a list of random co-ordinates.+randomCoords :: StdGen -> Int -> Int -> [(Int,Int)]+randomCoords a width height = (rnx1, rny1) : randomCoords g2 width height+  where+    (rnx1, g1) = randomR (0, width) a+    (rny1, g2) = randomR (0, height) g1++-- | Salt and pepper noise or impulse noise is a form of noise seen on images.+-- It is mainly caused by sharp and sudden disturbances in the image signal. +-- +-- 'saltAndPepper' generates this particular type of noise by introducing a sparse +-- distribution of white and black pixels in the input image. The level or intensity+-- of the noise to be introduced is a parameter of this method and is scaled +-- between 0 and 1, that is the input Noise Intensity has a domain : (0, 1).+-- +-- <<images/yield.jpg>>   <<images/yield_snp.png>>+--+-- Usage :+-- +-- >>> img <- readImageY VU "images/yield.jpg"+-- >>> input1 <- getLine+-- >>> g <- newStdGen+-- >>> let noiseLevel = (P.read input1 :: Float)+-- >>> let snpImage :: Image VU Y Double+-- >>>     snpImage = saltAndPepper img noiseLevel g+-- >>> writeImage "images/yield_snp.png" snpImage+--+saltAndPepper+  :: forall arr e cs . (MArray arr Y Double, IP.Array arr Y Double)+  => Image arr Y Double+  -> Float  -- ^ Noise Intensity -> Domain : (0, 1)+  -> StdGen -- ^ Instance of RandomGen+  -> Image arr Y Double+saltAndPepper image noiseLevel = accBin+ where+   widthMax, heightMax, noiseIntensity :: Int+   widthMax = ((rows image) - 1)+   heightMax = ((cols image) - 1)+   noiseIntensity = round (noiseLevel * (fromIntegral widthMax) * (fromIntegral heightMax))   ++   accBin :: StdGen -> Image arr Y Double+   accBin g = runST $ +      do arr <- I.thaw image  +         let coords = take (noiseIntensity + 1) (randomCoords g widthMax heightMax)+         forM_ coords $ \i -> do+           let a :: Int+               a = uncurry (+) i        +           if (a `mod` 2 == 0)+              then do let px =  0+                      I.write arr i px+              else do let px = 1.0+                      I.write arr i px+         freeze arr