Sepia Image

/marcel.jpg

I was simply looking for some Java code to turn the a picture into its Sepia version and realized most of the java examples were a bit lacking.

Turning a picture to Sepia is just toning down values for the different B(lue), G(reen), R(ed) channels of the picture. We are using a 3x3 kernel on the input Mat object and apply the kernel transformation using OpenCv’s transform.

Using any of the origami template available you can start typing in your language of choice.

Java Code

The java version is actually surprisingly readable and short. Note that this also works in a Jupter notebook, as we described in

package me;

import java.io.File;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.scijava.nativelib.NativeLoader;


/**
 * Using a kernel to get sepia picture
 */
public class Sepia {

    public static void main(String[] args) throws Exception {
        NativeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat source = Imgcodecs.imread("data/marcel.jpg");

        // mat is in BGR
        Mat kernel = new Mat(3, 3, CvType.CV_32F);
        kernel.put(0, 0,
                // green
                0.272, 0.534, 0.131,
                // blue
                0.349, 0.686, 0.168,
                // red
                0.393, 0.769, 0.189);
        Mat destination = new Mat();
        Core.transform(source, destination, kernel);

        String output = "target/sepia2_" + new File(filename).getName();
        Imgcodecs.imwrite(output, destination);
    }
}

Kotlin Code

Using IntelliJ’s convert to Kotlin code, we get something that is slightly shorter and remove some of the boiler plate code. Actually not much … but still.


import java.io.IOException

import org.opencv.core.Core
import org.opencv.core.CvType
import org.opencv.core.Mat
import org.opencv.imgcodecs.Imgcodecs
import org.scijava.nativelib.NativeLoader

class Sepia {

    @Throws(IOException::class)
    fun run(input: String, output: String) {
        // sepia kernel
        val kernel = Mat(3, 3, CvType.CV_32F)
        kernel.put(0, 0, 
            0.272, 0.534, 0.131, 
            0.349, 0.686, 0.168, 
            0.393, 0.769, 0.189)

        val destination = Mat()
        Core.transform(Imgcodecs.imread(input), destination, kernel)
        Imgcodecs.imwrite(output, destination)
    }

    companion object {

        @Throws(Exception::class)
        @JvmStatic
        fun main(args: Array<String>) {
            NativeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME)
            Sepia().run("data/marcel.jpg", "target/marcel_sepia.jpg")
            println("A new sepia cat is in target/marcel_sepia.jpg")
        }
    }
}

pure origami / clojure code

Of course, my favourite is still in Origami clojure when we can make full use of the Clojure threading macros:

(ns sepia
  (:require
    [opencv4.utils :as u]
    [opencv4.core :refer :all]))
    
(-> "data/marcel.jpg"
  (imread)
  (transform! 
    (u/matrix-to-mat [ 
      [0.272 0.534 0.131]
      [0.349 0.686 0.168]
      [0.393 0.769 0.189]]))
  (u/imshow))

In All three cases, Marcel goes from colored

/marcel.jpg

to sepia …

/marcel_sepia.jpg

The three samples can be found in the java tutorial section of Origami. clj, kotlin and java