haskellbmpjuicy-pixels

How to extract RGB values from (most) pictures?


I want to extract every RGB value from possible pictures in Haskell.

What would be the easiest way to get the raw values (0-255)?

I already got some results with the Juicy Pixels library, but somehow I always get the exception:

*** Exception: ./Data/Vector/Generic.hs:249 ((!)): index out of bounds (660000,660000)

This is the corresponding code.

{-# LANGUAGE TypeSynonymInstances #-}

module Main where

import Codec.Picture         (readImage, pixelAt, PixelRGB8(..))
import Codec.Picture.Types
import System.FilePath.Posix (splitExtension)

toRGBRaw :: FilePath -> IO ()
toRGBRaw fp = do
    image <- readImage fp
    case image of
      Left _ -> putStrLn $ "Sorry, not a supported codec for " ++ fp
      Right dynimg -> do
        let imgrgba8 = fromDynamicImage dynimg
        let (name, _) = splitExtension fp
        writeFile (name ++ ".txt") (concat $ accumPixels imgrgba8)

accumPixels :: Image PixelRGBA8 -> [String]
accumPixels img@(Image w h _) = [ format (pixelAt img x y) x y | x <- [0..w], y <- [0..h]]
  where format (PixelRGBA8 r g b _) j k = "#" ++ show r ++ "$"
                                              ++ show g ++ "$"
                                              ++ show b ++ "$"
                                              ++ show j ++ "$"
                                              ++ show k ++ "*\n"


-- Copied from
-- See http://hackage.haskell.org/package/JuicyPixels-util-0.2/docs/Codec-Picture-RGBA8.html

class ToPixelRGBA8 a where
    toRGBA8 :: a -> PixelRGBA8

instance ToPixelRGBA8 Pixel8 where
    toRGBA8 b = PixelRGBA8 b b b 255

instance ToPixelRGBA8 PixelYA8 where
    toRGBA8 (PixelYA8 l a) = PixelRGBA8 l l l a

instance ToPixelRGBA8 PixelRGB8 where
    toRGBA8 (PixelRGB8 r g b) = PixelRGBA8 r g b 255

instance ToPixelRGBA8 PixelRGBA8 where
    toRGBA8 = id

fromDynamicImage :: DynamicImage -> Image PixelRGBA8
fromDynamicImage (ImageY8 img) = pixelMap toRGBA8 img
fromDynamicImage (ImageYA8 img) = pixelMap toRGBA8 img
fromDynamicImage (ImageRGB8 img) = pixelMap toRGBA8 img
fromDynamicImage (ImageRGBA8 img) = img

-- end of Codec.Picture.RGBA8

This is an example image: Link

The code is currently a little bit unordered because I had to copy some definitions from Codec.Picture.RGBA8 which is not available through LTS. Don't mind the string representation, I'm parsing those via an Arduino with a WiFi shield.


Solution

  • Your list comprehension in accumPixels is 0-indexed, but also includes the boundaries. This is likely the issue. In Haskell, [0..3] is the list [0,1,2,3], so you probably mean [0..(w-1)] and [0..(h-1)].