Monday, October 8, 2012

How to Linear Stretch any Image(Jpg/Png/Gif) Histogram in Java to improve it's contrast

So you want to stretch an image histogram linearly in Java to remove shadow and improve contrast?
Let us assume that a pixel contains 3 channels : RGB. That means each pixel of size 4 bytes has last 3 bytes as RGB while the first is 0.
Just like Photoshop->Image->Adjustments->Levels you can stretch each component(RGB) separately using a min and max value. If you've a dark image with low light then you can see the improvement.
The actual idea is plot the histogram of each channel and find the lowest and maximum pixel values and stretch them to 0 to 255. Then the image will become bright.
Here is the code that does that. Remember you can use any format jpg/png/gif etc input and output image.
What I'm doing is first getting each pixel(int of size 4 bytes in java) and then extracting 1 byte value each of RGB component, stretch it and put it back in a new file format. The RGB are stored in each byte numbering 2,3,4. The first byte is not important to us. Last three are. So that's why shifting(<<,>>) and masking 0xff are done in the code.
Here is the java resource for image format/bufferedimage conversion. Here is the linear stretching algorithm. Here the input file is IMG_3955.JPG and output is Newout.jpg but both could be any formats.
Just set the min and max variables to the window to stretch and change the input filename. This program also dumps the histogram of each channel(r/g/b) before histogram stretch - ie actual values and after r/g/b are stretched.
DOWNLOAD THE SOURCE CODE HERE.  Read the readme.txt file.
/**
  *
  * Read readme.txt
  */
  import java.awt.image.*;
  import java.io.*;
  import java.util.*;
  import java.awt.image.BufferedImage;
  import java.io.File;
  import javax.imageio.ImageIO;
class StretchHistogram {
public static void main(String args[]) { System.out.println("hello");
BufferedImage img = null; try { img = ImageIO.read(new File("IMG_3955.JPG")); writeColorImageValueToFile(img); } catch (Exception e) { } }
public static void writeColorImageValueToFile(BufferedImage in) { int width = in.getWidth(); int height = in.getHeight(); int min = 0; //stretch min level int max = 31; //stretch max level
System.out.println("width=" + width + " height=" + height); try {
int[] r = new int[width * height]; int[] g = new int[width * height]; int[] b = new int[width * height]; int[] e = new int[width * height]; int[] data = new int[width * height]; in.getRGB(0, 0, width, height, data, 0, width);
int[] hist_refore_r = new int[256]; int[] hist_refore_g = new int[256]; int[] hist_refore_b = new int[256];
int[] hist_after_r = new int[256]; int[] hist_after_g = new int[256]; int[] hist_after_b = new int[256];
for (int i = 0; i < (height * width); i++) { r[i] = (int) ((data[i] >> 16) & 0xff); g[i] = (int) ((data[i] >> 8) & 0xff); b[i] = (int) (data[i] & 0xff);
hist_refore_r[r[i]]++; hist_refore_g[g[i]]++; hist_refore_b[b[i]]++; //System.out.println(r[i]+" "+g[i]+" "+b[i]);
//stretch them to 0 to 255 r[i] = (int) (1.0*( r[i] - min) / (max - min) * 255); g[i] = (int) (1.0*( g[i] - min) / (max - min) * 255); b[i] = (int) (1.0*( b[i] - min) / (max - min) * 255); if(r[i]> 255) r[i]=255; if(g[i]> 255) g[i]=255; if(b[i]> 255) b[i]=255; if(r[i]<0) r[i]=0; if(g[i]<0) g[i]=0; if(b[i]<0) b[i]=0;
//System.out.println(r[i]+" "+g[i]+" "+b[i]); hist_after_r[r[i]]++; hist_after_g[g[i]]++; hist_after_b[b[i]]++;
//convert it back e[i] = (r[i] << 16) | (g[i] << 8) | b[i];
} //convert e back to say jpg in.setRGB(0, 0, width, height, e, 0, width); ImageIO.write(in, "jpeg" /* "png" "jpeg" ... format desired */, new File("newout.jpg") /* target */);
printhistogram(hist_refore_r, "hist_before_r.txt"); //before stretchig ie original printhistogram(hist_refore_g, "hist_before_g.txt"); printhistogram(hist_refore_b, "hist_before_b.txt"); printhistogram(hist_after_r, "hist_after_r.txt"); //after stretching ie modified ones printhistogram(hist_after_g, "hist_after_g.txt"); printhistogram(hist_after_b, "hist_after_b.txt");
} catch (Exception e) { System.err.println("Error: " + e); Thread.dumpStack();
} }
static void printhistogram(int[] hist, String file) { try { FileWriter op = new FileWriter("F:/tmp/JavaApplication1/"+file);
for (int i = 0; i < hist.length; ++i) { op.write("[" + i + "]=" + hist[i]+"\n"); } op.close(); } catch (Exception e) { System.err.println("Error2: " + e); Thread.dumpStack(); } } }

No comments:

Post a Comment