/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package edu.mbl.jif.imaging.nav.util; import edu.mbl.jif.imaging.nav.ZoomWindow; import java.awt.*; import java.awt.image.*; import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.*; /** * A Histogram represents the histogram of a BufferedImage object. The histogram of an image shows * the amount of pixels of each possible value, which is 0-255 for an BufferedImage. * * Besides calculating and drawing the histogram of an image, an Histogram object may also be used * to make a histogram equalized version of the image. Histogram equalization increases the contrast * of the image. * */ public class Histogram { private BufferedImage image; public HPanel histpanel; int displayRange16bit = 65535; /** * Constructs a Histogram for an image. */ public Histogram(BufferedImage image) { setImage(image); // histpanel = new HPanel(); } /** * Constructs a Histogram for an array of pixel data. The array must contain intensity values * between 0 and 255. data[y][x] is the intensity at (x, y) in the image. */ public Histogram(int[][] data) { BufferedImage image = CreateImagefromIntArray(data); setImage(image); } /** * Returns the image this Histogram represents. */ public BufferedImage getImage() { return image; } /** * Sets the image this Histogram represents. */ public void setImage(BufferedImage image) { this.image = image; } public int[][] getPixels(BufferedImage image) { int iw = image.getWidth(null); int ih = image.getHeight(null); int[][] pixels = new int[iw][ih]; /*DataBufferByte db = (DataBufferByte)image.getRaster().getDataBuffer(); byte[] pixelarray = db.getData(); for (int x = 0; x < pixels.length; x++){ for (int y = 0; y < pixels[0].length; y++){ pixels[x][y] = (int) pixelarray[y + x * pixels.length] &0xFF; } } */ if (image.getType() == 10) { DataBufferByte db = (DataBufferByte) image.getRaster().getDataBuffer(); byte[] pixelarray = db.getData(); //System.out.println(pix[0].length * pix.length); //System.out.println(pixelarray.length); for (int x = 0; x < iw; x++) { for (int y = 0; y < ih; y++) { pixels[x][y] = pixelarray[x + y * iw] & 0xFF; } } } else if (image.getType() == 11) { DataBufferUShort db = (DataBufferUShort) image.getRaster().getDataBuffer(); short[] pixelarray = db.getData(); for (int x = 0; x < iw; x++) { for (int y = 0; y < ih; y++) { pixels[x][y] = pixelarray[x + y * iw] & 0xFFFF; } } } else { System.err.println("Image Type incorrect."); } return pixels; } /** * Calculates and returns the histogram for the image. The histogram is represented by an int * array of 256 elements. Each element gives the number of pixels in the image of the value equal * to the index of the element. * */ public int[] getHistogram() { int iw = image.getWidth(null); int ih = image.getHeight(null); int[] histogram; if (image.getType() == 10) { histogram = new int[256]; } else { histogram = new int[displayRange16bit+1]; } int[][] pixels = getPixels(image); //find the histogram try { for (int x = 0; x < pixels.length; x++) { for (int y = 0; y < pixels[0].length; y++) { histogram[pixels[x][y]]++; } } } catch (Exception e) { e.printStackTrace(); } return histogram; } /** * Calculates and returns the normalized histogram for the image. The normalized histogram is * represented by an array of 256 doubles. Each element gives the amount of pixels in the image * of the value equal to the index of the element. The amount given is relative to the total * number of pixels in the image, so that the sum of the normalized histogram is 1. * * @return The normalized histogram. */ public double[] getNormHistogram() { int[] histogram = getHistogram(); double[] normHistogram; //The sum of the histogram equals the number of pixels in the image int sum = image.getHeight() * image.getWidth(); if (image.getType() == 10) { normHistogram = new double[256]; //Find the normalized histogram by dividing each component of the histogram //by sum for (int n = 0; n < 256; n++) { normHistogram[n] = (double) histogram[n] / sum; } } else { normHistogram = new double[displayRange16bit+1]; //Find the normalized histogram by dividing each component of the histogram //by sum for (int n = 0; n < displayRange16bit; n++) { normHistogram[n] = (double) histogram[n] / sum; } } return normHistogram; } /** * Draws the histogram of the image. * * @param g The Graphics object to draw the histogram on. * @param x The x coordinate of the histogram. * @param y The y coordinate of the histogram. * @param height The heigth of the histogram. * @param space The space between the bars in the histogram. */ public void draw(Graphics g, int x, int y, int height, int space) { } /** * Does histogram equalization on the image and returns the result as an new image. Histogram * equalization increases the contrast of the image. */ public BufferedImage makeHistEqualizedImg() { double[] normHistogram = getNormHistogram(); int[][] data = getPixels(image); int[] sum; double s = 0; if (image.getType() == 11) { sum = new int[displayRange16bit+1]; for (int v = 0; v < displayRange16bit; v++) { s += normHistogram[v]; sum[v] = (int) (s * 255 + 0.5); } } else { sum = new int[256]; for (int v = 0; v < 256; v++) { s += normHistogram[v]; sum[v] = (int) (s * 255 + 0.5); } } int[][] data2 = data; for (int x = 0; x < data.length; x++) { for (int y = 0; y < data[0].length; y++) { data2[x][y] = sum[data[x][y]]; } } BufferedImage image = CreateImagefromIntArray(data2); return image; } /** * Does histogram equalization on the image. Histogram equalization increases the contrast of the * image. */ public void equalizeHistogram() { setImage(makeHistEqualizedImg()); } /** * subclass to paint the histogram in a panel */ public class HPanel extends JPanel { public HPanel() { setPreferredSize(new Dimension(356, 200)); setBackground(new Color(241, 244, 180)); setBorder(BorderFactory.createLineBorder(Color.black)); } public void paintComponent(Graphics g) { super.paintComponent(g); double[] normHistogram = getNormHistogram(); int x, y, height, space; height = this.getHeight() * 3 / 4; x = 20; y = 20; space = 0; int len; if (image.getType() == 10) { len = 255; } else { len = displayRange16bit; } //find max value in histogram double max = 0; for (int j = 0; j < len; j++) { if (normHistogram[j] > max) { max = normHistogram[j]; } } g.setFont(new Font("SansSerif", Font.PLAIN, 11)); //draw vertical axis g.drawString("" + ((double) ((int) (max * 100)) / 10) + "%", x, y + 7); x += 30; g.drawLine(x - 2, y + height + 2, x - 2, y); g.drawLine(x - 2, y, x - 4, y); //draw horizontal axis g.drawLine(x - 2, y + height, x + (space + 1) * 257 - 1, y + height); g.drawLine(x + (space + 1) * 256, y + height + 2, x + (space + 1) * 256, y + height); g.drawString(Integer.toString(len), x + (space + 1) * 256 - 8, y + height + 11); g.drawLine(x + (space + 1) * 128, y + height + 2, x + (space + 1) * 128, y + height); g.drawString(Integer.toString(len / 2), x + (space + 1) * 128 - 8, y + height + 11); //draw bars Color shade = new Color(10, 10, 180); g.setColor(shade); int i, j = 0; if (len == 255) { for (i = 0; i < len; i++) { g.drawLine(x + (i + 1) * (space + 1), y + height, x + (i + 1) * (space + 1), y + (int) ((height - (normHistogram[i] / max) * height))); } } else { for (i = 0; i < len; i++) //j = (int) (i/Math.pow(2,8)); { g.drawLine(x + (int) (i * 0.1275 + 1) * (space + 1), y + height, x + (int) (i * 0.1275 + 1) * (space + 1), y + (int) ((height - (normHistogram[i] / max) * height))); } } } } /** * Creates an imnage from a 2D array of integers */ public static BufferedImage CreateImagefromIntArray(int[][] pixels) { int i, j; i = 0; j = 0; short[] pixelshortArray = new short[pixels.length * pixels[0].length]; //int[] pixelintArray = new int[pixels.length * pixels[0].length]; int min = getMin(pixels); int max = getMax(pixels); int gray; // System.out.println("rescaling output image: "); for (int x = 0; x < pixels.length; x++) { for (int y = 0; y < pixels[0].length; y++) { gray = pixels[x][y]; if (gray < 0) { pixelshortArray[x + y * pixels.length] = 0; } else { pixelshortArray[x + y * pixels.length] = (short) gray; } } } // returns an 8-bit buffered image for display purposes BufferedImage img = getGrayBufferedImage(pixelshortArray, pixels.length, pixels[0].length, 0, 255); return img; } /** * method to find the minimum value in a 1D array of doubles */ public static double getMin(double data[]) { double min = data[0]; for (int i = 0; i < data.length; i++) { if (data[i] < min) { min = data[i]; } } return min; } /** * method to find the maximum value in a 1D array of doubles */ public static double getMax(double data[]) { double max = data[0]; for (int i = 0; i < data.length; i++) { if (data[i] > max) { max = data[i]; } } return max; } /** * method to find the minimum value in a 1D array of int */ public static int getMin(int data[]) { int min = data[0]; for (int i = 0; i < data.length; i++) { if (data[i] < min) { min = data[i]; } } return min; } /** * method to find the maximum value in a 1D array of integers */ public static int getMax(int data[]) { int max = data[0]; for (int i = 0; i < data.length; i++) { if (data[i] > max) { max = data[i]; } } return max; } /** * method to find the minimum value in a 2D array of integers */ public static int getMin(int data[][]) { int min = data[0][0]; for (int i = 0; i < data.length; i++) { for (int j = 0; j < data[0].length; j++) { if (data[i][j] < min) { min = data[i][j]; } } } return min; } /** * method to find the maximum value in a 2D array of integers */ public static int getMax(int data[][]) { int max = data[0][0]; for (int i = 0; i < data.length; i++) { for (int j = 0; j < data[0].length; j++) { if (data[i][j] > max) { max = data[i][j]; } } } return max; } /** * method to find the minimum value in a 2D array of doubles */ public static double getMin(double data[][]) { double min = data[0][0]; for (int i = 0; i < data.length; i++) { for (int j = 0; j < data[0].length; j++) { if (data[i][j] < min) { min = data[i][j]; } }//System.out.println(min); } return min; } /** * method to find the maximum value in a 2D array of doubles */ public static double getMax(double data[][]) { double max = data[0][0]; for (int i = 0; i < data.length; i++) { for (int j = 0; j < data[0].length; j++) { if (data[i][j] > max) { max = data[i][j]; } } //System.out.println(max); } return max; } public static BufferedImage getGrayBufferedImage(short[] buf, int width, int height, int imgMin, int imgMax) { if (buf.length != width * height) { throw new IllegalArgumentException(width + " * " + height + " != " + buf.length); } BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); toGrayBytes(data, buf, imgMin, imgMax); return image; } public static void toGrayBytes(byte[] grayBytes, short[] shortBuffer, int imgMin, int imgMax) { final int displayMin = 0; // Black is zero final int displayMax = 255; //(2 << 7) - 1; // For 8 bits per sample (255) final float displayRatio = (float) (displayMax - displayMin) / (imgMax - imgMin); for (int i = 0; i < shortBuffer.length; ++i) { int in = shortBuffer[i]; int out; if (in < imgMin) { out = displayMin; } else if (in > imgMax) { out = displayMax; } else { out = (int) ((in - imgMin) * displayRatio); } grayBytes[i] = (byte) out; } } public static void main(String[] args) { String imagePath = "C:/MicroManagerData/shalins test data/000010.tif"; try { BufferedImage image = ImageIO.read(new File(imagePath)); int type = image.getType(); System.out.println("type = " + type); Histogram hist = new Histogram(image); hist.equalizeHistogram(); BufferedImage out = hist.getImage(); ZoomWindow zoomwin = new ZoomWindow("ZoomWindow Example", 3); zoomwin.setImage(out); zoomwin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); zoomwin.setVisible(true); } catch (IOException ex) { Logger.getLogger(Histogram.class.getName()).log(Level.SEVERE, null, ex); } } }