packages feed

crocodile-0.1.2: app/src/ToneMap.hs

-- Tone map an image
{-# LANGUAGE BangPatterns #-}

module ToneMap(toneMapImage, 
               toneMapIdentity, 
               toneMapAverageLuminance, 
               toneMapReinhard, 
               toneMapHejlBurgessDawson,
               exposeImage,
               imageAverageLogLuminance,
               imageAverageLuminance) where

import PolymorphicNum
import Colour

-- x = x
toneMapIdentity :: [Colour] -> [Colour]
toneMapIdentity = map id

-- x = x / avg xs
toneMapAverageLuminance :: [Colour] -> [Colour]
toneMapAverageLuminance xs = map (<*> invAverageBrightness) xs
    where
      invAverageBrightness = 1 / imageAverageLuminance xs

-- Reinhard tone map operator http://filmicgames.com/archives/75
toneMapReinhard :: [Colour] -> [Colour]
toneMapReinhard = map (\(Colour !r !g !b _) -> Colour (r / (r + 1)) (g / (g + 1)) (b / (b + 1)) 1)

-- Hejl-Burgess-Dawson http://filmicgames.com/archives/75
toneMapHejlBurgessDawson :: [Colour] -> [Colour]
toneMapHejlBurgessDawson = map f
    where
      f colour = (x <*> (x <*> (6.2 :: Double) <+> (0.5 :: Double))) </> (x <*> (x <*> (6.2 :: Double) <+> (1.7 :: Double)) <+> (0.06:: Double))
          where
            x = (\x' -> fold max x' 0) (colour <-> (0.004 :: Double))

-- Apply a tone map operator
toneMapImage :: ([Colour] -> [Colour]) -> [Colour] -> [Colour]
toneMapImage f = f

-- Normal averaging
imageAverageLuminance :: [Colour] -> Double
imageAverageLuminance = imageAverageLuminance' 0 0
    where
      imageAverageLuminance' accLum accCount (x:xs) = imageAverageLuminance' (accLum + luminance x) (accCount + 1) xs
      imageAverageLuminance' accLum 0 [] = accLum
      imageAverageLuminance' accLum accCount [] = accLum / accCount

-- Get the average luminance of a scene, using Reinhard style log-lum averaging to damp down the effect of outlier pixels
imageAverageLogLuminance :: [Colour] -> Double
imageAverageLogLuminance = imageAverageLogLuminance' 0 0
    where
      imageAverageLogLuminance' accLum accCount (x:xs) = imageAverageLogLuminance' (accLum + logLuminance x) (accCount + 1) xs
      imageAverageLogLuminance' accLum 0 [] = exp accLum
      imageAverageLogLuminance' accLum accCount [] = exp (accLum / accCount)

-- Adjust the exposure of an image
exposeImage :: ([Colour] -> Double) -> [Colour] -> Double -> [Colour]
exposeImage f xs exposureScale = map (</> (exposure * exposureScale)) xs
    where
      exposure = f xs