Skip to content

Instantly share code, notes, and snippets.

@nbrick
Created June 14, 2016 10:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nbrick/dc84e2d25138336e86981168410dcb82 to your computer and use it in GitHub Desktop.
Save nbrick/dc84e2d25138336e86981168410dcb82 to your computer and use it in GitHub Desktop.
Colonel Mustard example solution
-- Convert image to an intensity matrix, find its null vector (kernel),
-- scale such that components are simple integers and try 1=A, 2=B, etc..
-- Output is ILIKETOTHINKOYSTERSTRANSCENDNATIONALBARRIERS.
-- This example solution has been tested with:
-- * GHC 7.10.3
-- * JuicyPixels 3.2.7.1
-- * HMatrix 0.17.0.2
import System.IO( openFile, IOMode( ReadMode ) )
import Data.ByteString( hGetContents )
import Data.Char( chr )
import Data.Function( (&) )
import Numeric.LinearAlgebra(
Matrix, Vector, Z, R, build, fromZ, null1, toList )
import Codec.Picture.Bitmap( decodeBitmap )
import Codec.Picture.Types(
Image( .. ), DynamicImage( .. ), PixelRGB8( .. ), Pixel8, pixelAt )
main :: IO ()
main = do
fileContents <- hGetContents =<< openFile "./colonelmustard.bmp" ReadMode
case decodeBitmap fileContents of
Right im -> im & intensityMatrix & decode & putStrLn
intensityMatrix :: DynamicImage -> Matrix Z
intensityMatrix (ImageRGB8 im@(Image w h _)) = build (h, w) intensityAt
where
intensityAt :: Z -> Z -> Z -- HMatrix lib forces us to use this signature.
intensityAt i j = sum $ fromIntegral <$> [r, g, b]
where
PixelRGB8 r g b = pixelAt im x y where [y, x] = fromEnum <$> [i, j]
decode :: Matrix Z -> String
decode m =
m & (fromZ :: Matrix Z -> Matrix R) -- (Need a matrix of reals to do SVD.)
& (null1 :: Matrix R -> Vector R) -- Get the kernel of the matrix.
& (toList :: Vector R -> [Double]) -- (Vector has no Functor instance.)
& \v -> (flip (/) $ v !! 0) <$> v -- Scale such that (v !! 0) == 1.0.
& (fmap round :: [Double] -> [Int])
& drop 5 -- Throw away timing pattern [1, 2, 3, 4, 5].
& init -- Throw away large negative integer at the end.
& fmap ((+) 64) & fmap chr -- 1=A, 2=B, etc..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment