Sepia and Image Negative Algorithms (with Python and Java code)

Two very common camera-effects which are found in all camera-abled devices are Sepia and Negative. Here the algorithms used to create the effects at RGB pixel level:

1) Sepia: This is a beautiful brownish oldie effect which is achieved by the following manipulation on the pixels:

OutputRedPixel = (R * .393) + (G *.769) + (B * .189)
OutputGreenPixel = (R * .349) + (G *.686) + (B * .168)
OutputBluePixel = (R * .272) + (G *.534) + (B * .131)

where R, B and G are input Red, Blue and Green pixels respectively. If a color exceeds 255 we simply use 255.

2) Negative: Remember the old-age light sensitive cameras which gave out negatives. Here is how we achieve the effect in digital images. We set the RGB value of each pixel to its complementary RGB value:

OutputRed = 255-R
OutputGreen = 255-G
OutputBlue = 255-B

Negate an image twice and you get the original image.

Here is the Python example code


#! /usr/bin/env python
# SNToner.py
# Author: Abdul Fatir
# E-Mail: abdulfatirs@gmail.com

from PIL import Image
# Opening the Raw Image File
raw_image = Image.open("raw.png")
WIDTH,HEIGHT = raw_image.size
# Creating Image objects for Sepia and Negative Images
sepia_image = Image.new("RGB",(WIDTH,HEIGHT))
neg_image = Image.new("RGB",(WIDTH,HEIGHT))
# Loading Pixel Data for all images 
raw_pixels = raw_image.load()
sepia_pixels = sepia_image.load()
neg_pixels = neg_image.load()

for Y in range(HEIGHT):
	for X in range(WIDTH):
		# Getting RGB of each pixel
		R,G,B = raw_pixels[X,Y]
		oR = (R*.393) + (G*.769) + (B*.189)
		oG = (R*.349) + (G*.686) + (B*.168)
		oB = (R*.272) + (G*.534) + (B*.131)
		# Writing pixel data after doing necessary manipulations
		sepia_pixels[X,Y] = (int(oR),int(oG),int(oB))
		neg_pixels[X,Y] = (255-R,255-G,255-B)
# Saving the images
sepia_image.save('sepia.png')
neg_image.save('negative.png')

Here is a similar Java code:

import java.io.File;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.awt.Color;
import static java.lang.System.out;
public class SepiaNegativeToner
{
	public static String ImageName="raw.png";
	
	public static void main(String args[])throws IOException
	{
		BufferedImage image,sepia,negative;
		
		image = ImageIO.read(new File(ImageName));
		int WIDTH = image.getWidth();
		int HEIGHT = image.getHeight();
		
		sepia = new BufferedImage(WIDTH,HEIGHT,image.getType());
		negative = new BufferedImage(WIDTH,HEIGHT,image.getType());
		
		// Looping through each pixel
		for(int y=0;y<HEIGHT;y++)
		{
			for(int x=0;x<WIDTH;x++)
			{
				int RGB = image.getRGB(x,y);
				int R = (RGB >> 16) & 0xff; // Red Value
				int G = (RGB >> 8) & 0xff;	// Green Value
				int B = (RGB) & 0xff;		// Blue Value
				
				// Output RGB values for Sepia
				int outputRed = (int)((R * .393) + (G *.769) + (B * .189));
				int outputGreen = (int)((R * .349) + (G *.686) + (B * .168));
				int outputBlue = (int)((R * .272) + (G *.534) + (B * .131));
				
				outputRed = Math.min(outputRed,255);
				outputGreen = Math.min(outputGreen,255);
				outputBlue = Math.min(outputBlue,255);
				sepia.setRGB(x,y, new Color(outputRed,outputGreen,outputBlue).getRGB());
				
				// Making the negative pixel
				Color complementary = new Color(255-R,255-G,255-B);
				negative.setRGB(x,y, complementary.getRGB());
			}
		}
		
		// Saving the Images
		ImageIO.write(sepia,"PNG",new File("sepia.png"));
		ImageIO.write(negative,"PNG",new File("negative.png"));
	}
}