Dibujar un histograma RGB de una foto con Java

En un proyecto que he realizado relacionado con el mundo de la fotografía, he necesitado desarrollar una interfaz gráfica en Java para un visor de fotografías que me mostrase el histograma por canal de cada foto. Y así es como lo resolví:

Clase Histograma en Java

Lo primero que he creado, es una clase histograma. Esta clase, al crearla, necesitará que le proporcionemos una imagen. Entonces recorrerá cada uno de sus píxeles y almacenará su valor RGB en un array.

public class Histograma {

    /**
     * Devuelve el histograma de la imagen.
     * @param imagen BufferedImagen de la cual se quiere obtener el histograma
     * @return Devuelve una variable int[5][256], donde el primer campo[0] corresponde
     * al canal Rojo, [1]=verde [2]=azul
     */
    public int[][] histograma(BufferedImage imagen){
        Color colorAuxiliar;

        int histogramaReturn[][]=new int[5][256]; /*Creamos la variable que contenga el histograma*/

        for( int i = 0; i < imagen.getWidth(); i++ ){ //Recorremos los pixels de la imagen
            for( int j = 0; j < imagen.getHeight(); j++ ){
                //Obtenemos color del pixel actual
                colorAuxiliar=new Color(imagen.getRGB(i, j));
                histogramaReturn[0][colorAuxiliar.getRed()]+=1;
                histogramaReturn[1][colorAuxiliar.getGreen()]+=1;
                histogramaReturn[2][colorAuxiliar.getBlue()]+=1;
            }
        }
        return histogramaReturn;
    }
}

¿Fácil verdad? Pues ahora sólo tenemos que utilizar la información guardada en esa matriz para dibujar los tres histogramas en un Panel de SWING.

Dibujo de la clase Histograma (SWING)

Ahora necesitamos crear una clase que sea la que pinte el Histograma sobre un JPanel. Para ello, haremos uso de la librería externa y de código libre JFreeChart. El código es sencillo y no necesita mucha explicación:

public class HistogramCreator {
      /**
     * Crea un gráfico de barras y lo asigna al JPanel recibido
     * @param histograma histograma de frecuencias (int[256]).
     * @param jPanelHistograma JPanel donde el histograma será dibujado
     * @param colorBarras color utilizado para dibujar el histograma
     */
    public void crearHistograma(int[] histograma,JPanel jPanelHistograma,Color colorBarras) {
        //Creamos el dataSet y añadimos el histograma
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        String serie = "Number of pixels";
        for (int i = 0; i < histograma.length; i++){
            dataset.addValue(histograma[i], serie, "" + i);
        }
        //Creamos el chart
        JFreeChart chart = ChartFactory.createBarChart("Histograma RGB", null, null,dataset, PlotOrientation.VERTICAL, true, true, false);
        //Modificamos el diseño del chart
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        BarRenderer renderer = (BarRenderer) plot.getRenderer();
        renderer.setSeriesPaint(0, colorBarras);
        chart.setAntiAlias(true);
        chart.setBackgroundPaint(new Color(255, 255, 255));
        jPanelHistograma.removeAll();
        jPanelHistograma.repaint();
        jPanelHistograma.setLayout(new java.awt.BorderLayout());
        jPanelHistograma.add(new ChartPanel(chart));
        jPanelHistograma.validate();    
    }
}

Ahora sólo queda cargar una foto y utilizarla para dibujar el histograma en un JPanel:

// Creamos el histograma
try {
    File photo = new File(dirImg);
    // se lee una imagen, indicando la ruta
    Image imagen=ImageIO.read(photo);
    // utilizamos la clase histograma
    Histograma ObjHistograma=new Histograma();
    int[][] histograma=ObjHistograma.histograma((BufferedImage)imagen);
    // utilizamos la clase creadora de histogramas
    HistogramCreator ObjDibujaHisto=new HistogramCreator();
    for (int i = 0; i < 3; i++) {
        //extraemos un canal del histograma
        int[] histogramaCanal=new int[256];
        System.arraycopy(histograma[i], 0, histogramaCanal, 0, histograma[i].length);
        //Dibujamos en el panel
        switch(i){
            case 0:
                ObjDibujaHisto.crearHistograma(histogramaCanal, histogramRed, Color.red);
                break;
            case 1:
                ObjDibujaHisto.crearHistograma(histogramaCanal, histogramGreen, Color.green);
                break;
            case 2:
                ObjDibujaHisto.crearHistograma(histogramaCanal, histogramBlue, Color.blue);
                break;
        }
    }

} catch (Exception e) {
    JOptionPane.showMessageDialog(null, JOptionPane.ERROR_MESSAGE, "Error controlado en excepción", JOptionPane.ERROR_MESSAGE);
}

El resultado, al menos en mi caso, es así: