feat(resize): resize/scale using nearest-neighbor

This commit is contained in:
Mahdi Dibaiee 2017-02-03 21:57:48 +03:30
parent 0f40936c98
commit 529d503204
3 changed files with 37 additions and 5 deletions

View File

@ -2,6 +2,7 @@ module Main where
import Data.Picture import Data.Picture
import System.Environment import System.Environment
import Data.Either import Data.Either
import Numeric.LinearAlgebra (rows, cols)
data Options = Options { file :: FilePath data Options = Options { file :: FilePath
, output :: FilePath , output :: FilePath
@ -13,6 +14,7 @@ module Main where
, argGamma :: Int , argGamma :: Int
, argBrightness :: Double , argBrightness :: Double
, argCompress :: Int , argCompress :: Int
, argScale :: Double
} }
opts = Options { file = "" opts = Options { file = ""
@ -25,6 +27,7 @@ module Main where
, argGamma = 1 , argGamma = 1
, argBrightness = 0 , argBrightness = 0
, argCompress = 0 , argCompress = 0
, argScale = 1
} }
main :: IO () main :: IO ()
@ -42,6 +45,7 @@ module Main where
putStrLn " --rotate <n> - rotate image by n degrees" putStrLn " --rotate <n> - rotate image by n degrees"
putStrLn " --grayscale - turn the image grayscale" putStrLn " --grayscale - turn the image grayscale"
putStrLn " --invert - invert (negative) the image" putStrLn " --invert - invert (negative) the image"
putStrLn " --scale <n> - scale the image using nearest-neighbor interpolation"
putStrLn " --compress <n> - approximate the (width - n)-th rank of image using SVD, note: this is not size compression, a number between 0 (no compression) and image width (full compression)" putStrLn " --compress <n> - approximate the (width - n)-th rank of image using SVD, note: this is not size compression, a number between 0 (no compression) and image width (full compression)"
putStrLn " --output <filename> - output name, defaults to output.png" putStrLn " --output <filename> - output name, defaults to output.png"
else do else do
@ -60,6 +64,7 @@ module Main where
. brightness (argBrightness options) . brightness (argBrightness options)
. conditionalFn grayscale (argGrayscale options) . conditionalFn grayscale (argGrayscale options)
. conditionalFn invert (argInvert options) . conditionalFn invert (argInvert options)
. scale (argScale options)
. compress (argCompress options) $ p . compress (argCompress options) $ p
writePicturePng (output options) edited writePicturePng (output options) edited
@ -79,6 +84,7 @@ module Main where
parseArgs ("--brightness":n:rest) opts = parseArgs rest (opts { argBrightness = read n }) parseArgs ("--brightness":n:rest) opts = parseArgs rest (opts { argBrightness = read n })
parseArgs ("--gamma":n:rest) opts = parseArgs rest (opts { argGamma = read n }) parseArgs ("--gamma":n:rest) opts = parseArgs rest (opts { argGamma = read n })
parseArgs ("--compress":n:rest) opts = parseArgs rest (opts { argCompress = read n }) parseArgs ("--compress":n:rest) opts = parseArgs rest (opts { argCompress = read n })
parseArgs ("--scale":n:rest) opts = parseArgs rest (opts { argScale = read n })
parseArgs ("--output":n:rest) opts = parseArgs rest (opts { output = n }) parseArgs ("--output":n:rest) opts = parseArgs rest (opts { output = n })
parseArgs (name:rest) opts = parseArgs rest (opts { file = name }) parseArgs (name:rest) opts = parseArgs rest (opts { file = name })

View File

@ -1,5 +1,5 @@
name: picedit name: picedit
version: 0.2.0.0 version: 0.2.1.0
synopsis: simple image manipulation functions synopsis: simple image manipulation functions
description: Simple set of functions for image manipulation: contrast, brightnesss, rotation, etc. description: Simple set of functions for image manipulation: contrast, brightnesss, rotation, etc.
homepage: https://github.com/mdibaiee/picedit#readme homepage: https://github.com/mdibaiee/picedit#readme
@ -16,10 +16,10 @@ cabal-version: >=1.10
library library
hs-source-dirs: src hs-source-dirs: src
exposed-modules: Data.Picture exposed-modules: Data.Picture
build-depends: base >= 4.7 && < 5, build-depends: base >= 4.7 && < 5
JuicyPixels >= 3.2.8 && < 3.3, , JuicyPixels >= 3.2.8 && < 3.3
hmatrix >= 0.17.0.2 && < 0.19, , hmatrix >= 0.17.0.2 && < 0.19
vector >= 0.11.0.0 && < 0.13 , vector >= 0.11.0.0 && < 0.13
default-language: Haskell2010 default-language: Haskell2010
executable picedit executable picedit
@ -29,6 +29,7 @@ executable picedit
build-depends: base build-depends: base
, picedit , picedit
, cli >= 0.1.2 && < 0.2 , cli >= 0.1.2 && < 0.2
, hmatrix >= 0.17.0.2 && < 0.19
default-language: Haskell2010 default-language: Haskell2010
source-repository head source-repository head

View File

@ -22,6 +22,8 @@ module Data.Picture ( Picture
, invert , invert
, compress , compress
, embed , embed
, resize
, Data.Picture.scale
-- * Converting between Image and Picture -- * Converting between Image and Picture
, fromImage , fromImage
, toImage , toImage
@ -170,5 +172,28 @@ module Data.Picture ( Picture
f b lm = (b * (cmap (1-) scaledAlpha)) + (lm * scaledAlpha) f b lm = (b * (cmap (1-) scaledAlpha)) + (lm * scaledAlpha)
maxAlpha = (rows ba><cols ba) $ zipWith max (toList . flatten $ ba) (toList . flatten . fit $ la) maxAlpha = (rows ba><cols ba) $ zipWith max (toList . flatten $ ba) (toList . flatten . fit $ la)
-- | Resize an image using nearest-neighbor interpolation
resize :: (Int, Int) -> Picture -> Picture
resize (sWidth, sHeight) (r, g, b, a) = (f r, f g, f b, f a)
where
initial = vector [0..fromIntegral sWidth * fromIntegral sHeight - 1]
(width, height) = (rows r, cols r)
(xRatio, yRatio) = (fromIntegral width / fromIntegral sWidth, fromIntegral height / fromIntegral sHeight)
f m = tr $ reshape sWidth $ V.map replace initial
where
v = flatten (tr m)
replace index =
let (x, y) = (fromIntegral $ floor index `mod` sWidth, fromIntegral . floor $ index / fromIntegral sWidth)
(px, py) = (floor $ x * xRatio, floor $ y * yRatio)
in v ! (py * width + px)
-- | Scale an image using the resize function
scale :: Double -> Picture -> Picture
scale 1 p = p
scale s (r, g, b, a) = resize (floor $ s * width, floor $ s * height) (r, g, b, a)
where
(width, height) = (fromIntegral $ rows r, fromIntegral $ cols r)
bound (l, u) x = max l $ min u x bound (l, u) x = max l $ min u x
pixelBound = bound (0, 255) pixelBound = bound (0, 255)