Search code examples
haskellimage-processinghip

Haskell HIP : Apply Filter to an Image


I'm trying to add a filter to an image using the Haskell Image Processing package HIP, I was able to read the image using the ByteString Package and convert the image to type Image VS YCbCr Word8 using HIP. Now, how do I convert from Image VS YCbCr Word8 to Border (Pixel cs e) or Pixel cs e? I'm still learning Haskell so please keep it simple. see code below :

addFilterJpg :: FilePath -> IO ()
addFilterJpg fc = do
    case validPath fc of 
        Left err -> putStrLn err
        Right img -> do
            case readImage img of
                Left err -> putStrLn err
                Right img -> do
                  -- convert img::(Image VS YCbCr Word8) to Border (Pixel cs e)
                  -- apply filter
                  -- save image
                  putStrLn "Convolution Filter"

Solution

  • There are a couple of issues with your question:

    • Firstly you are missing a declaration of validPath function. I'll assume it does some file path validation, so I'll just ignore it in the answer.
    • readImage is an IO action, as such you can't just pattern match on Either, you need to execute it first.
    • You also need to output the result image somewhere, so you need out path as well

    Some more image specific remarks:

    • Applying convolution to YCbCr encoded image doesn't really make sense, so you either need to convert to RGB or grayscale Y. I'll assume you want color so we'll use RGB
    • You didn't specify which filter you want, so'll just go with gaussian blur
    applyFilterJpg :: FilePath -> FilePath -> IO ()
    applyFilterJpg fcin fcout = do
      eImg <- readImageExact JPG fcin
      case eImg of
        Left err -> putStrLn err
        Right img -> do
          let imgRGB :: Image VS RGB Double
              imgRGB = convert (img :: Image VS YCbCr Word8)
              gaussianBlurKernel :: Image VS X Double
              gaussianBlurKernel = fromLists $ [ [ 1/16, 1/8, 1/16 ]
                                               , [  1/8, 1/4,  1/8 ]
                                               , [ 1/16, 1/8, 1/16 ] ]
              convRGB = convolve Edge gaussianBlurKernel imgRGB
          writeImage fcout convRGB
    

    This is what we get when we run it:

    enter image description here

    That being said, there are already functions built in that will simplify this whole process for you:

    • Use import functions that already do the conversion for you, so you don't need to mess with manual conversion of color spaces.
    • Instead of supplying kernel for filter manually, check see if there is already one available in HIP that you need.
    addFilterJpg' :: FilePath -> FilePath -> IO ()
    addFilterJpg' fcin fcout = do
      imgRGB <- readImageRGB VS fcin
      let convRGB = applyFilter (gaussianBlur 1) imgRGB
      writeImage fcout convRGB
    

    This is the outcome of the above function:

    enter image description here