-- The University of New Mexico's Haskell Image Processing Library
-- Copyright (C) 2013 Joseph Collard
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see .
{-# LANGUAGE ViewPatterns, FlexibleContexts #-}
{-# OPTIONS -O2 #-}
module Data.Image.Convolution(convolveRows,
convolveCols,
convolve) where
--array>=0.4.0.1
import Data.Array.IArray
import Data.Image.Internal
type Kernel a = Array Int a
type Kernel2D a = Array (Int, Int) a
kernel :: [a] -> Kernel a
kernel ls = listArray (0, (length ls) - 1) (reverse ls)
kernel2d :: [[a]] -> Kernel2D a
kernel2d ls = listArray ((0,0), (length ls-1, length (head ls) - 1)) (reverse . concat $ ls)
{-| Given a list consisting solely of pixel values representing a 1D
convolution kernel and an image, convolveRows returns the 1D discrete
periodic convolution of the rows of the image with the kernel.
>>>frog <- readImage "images/frog.pgm"
>>>convolveRows [1,-1] frog
-}
convolveRows :: (Image img,
Num (Pixel img)) => [Pixel img] -> img -> img
convolveRows = convolveRows' . kernel
convolveRows' :: (Image img,
Num (Pixel img)) => Kernel (Pixel img) -> img -> img
convolveRows' k = convolve' k' where
k' = listArray ((0,0), (0,cols-1)) ls where
ls = elems k
cols = length ls
{-| Given a list consisting solely of pixel values representing a 1D
convolution kernel and an image, convolveCols returns the 1D discrete
periodic convolution of the columns of the image with the kernel.
>>>convolveCols [1,-1] frog
>>>let dx = convolveRows [1, -1] frog
>>>let dy = convolveCols [1, -1] frog
>>>imageMap sqrt (dx*dx + dy*dy) :: GrayImage
-}
convolveCols :: (Image img,
Num (Pixel img)) => [Pixel img] -> img -> img
convolveCols = convolveCols' . kernel
convolveCols' :: (Image img,
Num (Pixel img)) => Kernel (Pixel img) -> img -> img
convolveCols' k = convolve' k' where
k' = listArray ((0,0), (rows-1,0)) ls where
ls = elems k
rows = length ls
{-| Given a 2D list consisting solely of pixels representing a 2D
convolution kernel and an image, convolve returns the 2D discrete
periodic convolution of the image with the kernel.
>>>convolve [[1,1,1],[1,-8,1],[1,1,1]] frog
-}
convolve :: (Image img,
Num (Pixel img)) => [[Pixel img]] -> img -> img
convolve = convolve' . kernel2d
convolve' :: (Image img,
Num (Pixel img)) => Kernel2D (Pixel img) -> img -> img
convolve' k img@(dimensions -> (rows, cols)) = makeImage rows cols conv where
conv r c = px where
imgVal = map (uncurry (periodRef img) . (\ (r', c') -> (r+r', c+c'))) imgIx
imgIx = map (\ (r, c) -> (r - cR, c - cC)) . indices $ k
kVal = elems k
px = sum . map (\ (p,k') -> p*k') . zip imgVal $ kVal
((minR, minC), (maxR, maxC)) = bounds k
cR = (maxR - minR) `div` 2
cC = (maxC - minC) `div` 2
recenter = map (\ (r, c) -> ((r-cR), (c-cC))) . indices $ k
periodRef :: (Image img) => img -> Int -> Int -> (Pixel img)
periodRef img@(dimensions -> (rows, cols)) r c = ref img (r `mod` rows) (c `mod` cols)