Package taller3

Source Code of taller3.ImageProcessor

/*
* ImageProcessor.java
*
* Created on October 13, 2007, 1:26 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/

package taller3;


import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.imageio.ImageIO;

import coder.HuffmanCoder;

/**
*
* @author Juli�n Klas
*/
public class ImageProcessor {
   
  public final static int RED_CHANNEL = 0;
  public final static int GREEN_CHANNEL = 1;
  public final static int BLUE_CHANNEL = 2;
  public final static int INTENSITY_CHANNEL = 3;
  public final static int RGB_CHANNEL = 4;
   
 
    private String DEFAULT_FILENAME="c:\\mercadoliebre.jpg";
    private BufferedImage img = null;

   
    int[] grayHistogram = new int[256];
    int[][] rgbHistogram = new int[3][];
   
    /**
     * Carga una imagen a partir de un archivo
     *
     * @param filename nombre del archivo que contiene la imagen
     * @throws IOException
     */
    public void loadImage(String filename) throws IOException{
        if(filename==null) filename=DEFAULT_FILENAME;
        img=ImageIO.read(new File(filename));       
    }
   
    public List<Color> getColorMatchList(List<Color> places, int buckets, float tolerance) {
      buildColorHistogram(buckets);
     
      List<Color> result = new ArrayList<Color>();
     
      List<Pair<Color,Float>> intermediate = new ArrayList<Pair<Color,Float>>();
     
      for (Color color : places) {
        intermediate.add(new Pair<Color,Float>(color,getSimilitude(color, buckets, tolerance)));     
    }
     
      Collections.sort(intermediate,new Comparator<Pair<Color,Float>>() {
      public int compare(Pair<Color, Float> o1, Pair<Color, Float> o2) {
        return o1.getSecond().compareTo(o2.getSecond());
      }
      });
     
      for (Pair<Color, Float> pair : intermediate) {
      result.add(pair.getFirst());
    }
     
      return result;
    }
   
    // retorna la masa alrededor de mas menos 10% de los buckets
    private Float getSimilitude(Color color, int buckets,float tolerance) {
     
      int intColor = color.getRGB();
     
      char redIndex   = (char)(((intColor >> 16) & 0xFF) * (float)(buckets - 1) / 255.0f);
      char greenIndex = (char)(((intColor >>  8) & 0xFF) * (float)(buckets - 1) / 255.0f);
      char blueIndex   = (char)(((intColor >>  0) & 0xFF) * (float)(buckets - 1) / 255.0f);
     
      float mass = 0;
     
      int desplazamiento = Math.min(1,(int)Math.round(buckets*(1-tolerance)));
     
      if(desplazamiento % 2 == 0) desplazamiento++;
     
      for (int i = -Math.max(0,desplazamiento); i <= Math.min(desplazamiento,255); i++) {
      mass += rgbHistogram[0][redIndex+i]+rgbHistogram[1][greenIndex+i]+rgbHistogram[2][blueIndex+i];
    }
     
    return mass;
  }

  /**
     * Determina si el robot est� por colisionar con una pared
     *
     * @param bandColor color de la banda inferior del laberinto
     * @param tolerance cuenta m�nima de los colores del color de la banda en el histograma
     *   para considerar una colisi�n
     * @param histogramBuckets n�mero de divisiones en el histograma
     * @return
     */
    public boolean isCollision(int[][] bandColors, float tolerance, int histogramBuckets) {
      buildColorHistogram(histogramBuckets);
          
      for (int i = 0; i < bandColors[0].length; i++) {
        int bandColorRedIndex = (int)(bandColors[0][i]*((float)histogramBuckets/255));
        int bandColorGreenIndex = (int)(bandColors[1][i]*((float)histogramBuckets/255));
        int bandColorBlueIndex = (int)(bandColors[2][i]*((float)histogramBuckets/255));
       
        ifrgbHistogram[0][bandColorRedIndex] < tolerance     &&
          rgbHistogram[1][bandColorGreenIndex] < tolerance   &&
          rgbHistogram[2][bandColorBlueIndex] < tolerance )return true;
    }        
      return false;
    }
       
    /**
     * Crea un histograma de 3 canales (RGB)
     * @param buckets n�mero de divisiones en el histograma
     */
    private void buildColorHistogram(int buckets) {
    rgbHistogram[0]=new int[buckets];
    rgbHistogram[1]=new int[buckets];
    rgbHistogram[2]=new int[buckets];
   
    int width = img.getWidth();
    int height = img.getHeight();
   
    for(int i=0; i< width ; i++)
            for(int j=0; j< height; j++)
            {
              int color = img.getRGB(i, j);
              char redIndex =   (char)(((color >> 16) & 0xFF) * (float)(buckets - 1) / 255.0f);
              char greenIndex =   (char)(((color >>  8) & 0xFF) * (float)(buckets - 1) / 255.0f);
              char blueIndex =   (char)(((color >>  0) & 0xFF) * (float)(buckets - 1) / 255.0f);
             
                rgbHistogram[0][redIndex]++;
            rgbHistogram[1][greenIndex]++;
            rgbHistogram[2][blueIndex]++;
            }
   
  }

    /**
     * Crea un histograma de intensidades de gris
     */
  private void buildIntensityHistogram()
    {
        for(int i=0; i< img.getWidth(); i++)
            for(int j=0; j< img.getHeight(); j++)
            {
                int intensity=getIntensity(i,j);
                grayHistogram[intensity]++;
            }       
    }
   
    public void saveHistogram(String filename) throws IOException
    {
        File f=new File(filename);
        BufferedWriter bw=new BufferedWriter(new FileWriter(f));
       
        for(int k=0; k<grayHistogram.length; k++){
            bw.write(Integer.toString(grayHistogram[k]));
            bw.write(";");
        }
       
        bw.close();
    }
   
    public void equalize(int channel) {
     
      switch(channel) {
        case RED_CHANNEL:   if(rgbHistogram == null) buildColorHistogram(255);
                  equalizeSingleChannel(rgbHistogram[0],RED_CHANNEL);
                  break;
       
        case GREEN_CHANNEL: if(rgbHistogram == null) buildColorHistogram(255);
                  equalizeSingleChannel(rgbHistogram[1],GREEN_CHANNEL);
                  break;
       
        case BLUE_CHANNEL:   if(rgbHistogram == null) buildColorHistogram(255);
                  equalizeSingleChannel(rgbHistogram[2],BLUE_CHANNEL);
                  break;
       
        case INTENSITY_CHANNEL: if(grayHistogram == null) buildIntensityHistogram();
                    equalizeSingleChannel(grayHistogram,INTENSITY_CHANNEL);
                    break;
       
        case RGB_CHANNEL:   buildColorHistogram(256);
                  equalize(RED_CHANNEL);
                  equalize(GREEN_CHANNEL);
                  equalize(BLUE_CHANNEL);
                  break;
      }     
    }
   
    private void equalizeSingleChannel(int[] currentChannel, int channel) {
       
        /* 1) n�mero total de colores */
        int totalColors=img.getWidth()*img.getHeight();
       
        /* 2) limiteInferior = 5% de la masa a la izquierda  */
        int limiteInferior=0;
        int limiteSuperior=255;
        int colorMass = 0;
       
        while(limiteInferior<256 && colorMass < totalColors*0.005)
        {
            colorMass+=currentChannel[limiteInferior];
            limiteInferior++;
        }
       
        colorMass=0;
       
        while(limiteSuperior>=0 && colorMass < totalColors*0.05)
        {
            colorMass+=currentChannel[limiteSuperior];           
            limiteSuperior--;
        }
       
        if(limiteSuperior<=limiteInferior || (limiteSuperior == 255 && limiteInferior==0))
        {
            logInfo("No se pudo encontrar la masa critica.");
        }
        else
        {
                logInfo("Limite inferior: "+limiteInferior+" ; LimiteSuperior: "+limiteSuperior);
               
                int maxValue=255;
                               
                float k = (float)maxValue / (limiteSuperior-limiteInferior) ;
                float offset = - ((float)maxValue / (limiteSuperior-limiteInferior))*limiteInferior;
               
                for(int i=0; i<img.getWidth(); i++)
                    for(int j=0; j<img.getHeight(); j++)
                    {
                        int color = (channel != INTENSITY_CHANNEL) ? img.getRGB(i, j) : getIntensity(i,j);
                        int newColor = color;
                       
                        char actualIndex = 0;
                       
                        int shifting = 0;
                        int colorMask = 0;
                       
                        switch(channel) {
                          case RED_CHANNEL: shifting = 16; colorMask = 0x00FF0000; break;
                          case GREEN_CHANNEL: shifting = 8; colorMask = 0x0000FF00break;
                          case BLUE_CHANNEL: shifting = 0; colorMask = 0x000000FF; break;
                        }
                       
                        actualIndex = (char)(((color >> shifting) & 0xFF));
                       
                        int newIndex=actualIndex;

                        newIndex=(int)(k*actualIndex+offset);     
                       
                        if(actualIndex<limiteInferior)
                        {
                            newIndex = 0;
                        }
                        else if(actualIndex>limiteSuperior){                         
                            newIndex = 255;
                         }
                       
                        if(channel != INTENSITY_CHANNEL) {
                          newColor = (newColor & ~colorMask) | ((int)newIndex<<shifting & colorMask);
                        } else {                         
                            newColor =((newIndex << 8) + (newIndex << 16) + (newIndex << 24))+newIndex; 
                        }
                       
                        img.setRGB(i,j,newColor);
                    }               
        }
    }
   
    /**
     * Retorna la intensidad de gris de una cordenada de la imagen
     * @param x posici�n sobre el eje horizontal
     * @param y posici�n sobre el eje vertical
     * @return intensida de gris en el punto especificado
     */
    private int getIntensity(int x, int y) {
        Color color=new Color(img.getRGB(x,y));
       
        int out = (int)(((float)color.getRed()*0.3) + ((float)color.getGreen() * 0.59) + ((float)color.getBlue() * 0.11));
        return out;
    }

    /**
     * Guarda esta imagen como archivo JPG
     * @param filename nombre del archivo
     * @throws IOException
     */
    void saveImage(String filename) throws IOException {               
        /*ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
        iwparam.setCompressionMode(ImageWriteParam.MODE_DEFAULT);*/
        ImageIO.write(img,"jpeg",new File(filename));
    }
   
    public void colorMovingAverage() {
        float matrix[][]={{0.025f,0.05f,0.025f},{0.05f,0.7f,0.05f},{0.025f,0.05f,0.025f}};       

        int anchoImagen = img.getWidth()-1;
        int altoImagen = img.getHeight()-1;
       
        for (int color = 0; color < 3; color++) {         
          for(int i=1; i<anchoImagen; i++)       
            for(int j=1; j<altoImagen; j++)
            {
              char temp=0;
              temp += (int)(getSingleChannelColor(img.getRGB(i-1, j-1), color)*matrix[0][0]);
              temp += (int)(getSingleChannelColor(img.getRGB(i-1, j  ), color)*matrix[0][1]);
              temp += (int)(getSingleChannelColor(img.getRGB(i-1, j+1), color)*matrix[0][2]);
             
              temp += (int)(getSingleChannelColor(img.getRGB(i , j-1), color)*matrix[1][0]);
              temp += (int)(getSingleChannelColor(img.getRGB(i , j  ), color)*matrix[1][1]);
              temp += (int)(getSingleChannelColor(img.getRGB(i  ,j+1), color)*matrix[1][2]);
             
              temp += (int)(getSingleChannelColor(img.getRGB(i+1, j-1), color)*matrix[2][0]);
              temp += (int)(getSingleChannelColor(img.getRGB(i+1, j  ), color)*matrix[2][1]);
              temp += (int)(getSingleChannelColor(img.getRGB(i+1, j+1), color)*matrix[2][2]);

              int shifting = 0;
              int colorMask = 0;
             
              switch(color) {
                    case RED_CHANNEL: shifting = 16; colorMask = 0x00FF0000; break;
                    case GREEN_CHANNEL: shifting = 8; colorMask = 0x0000FF00break;
                    case BLUE_CHANNEL: shifting = 0; colorMask = 0x000000FF; break;
              }
               
              int newColor = img.getRGB(i, j);
             
                  newColor = (newColor & ~colorMask) | ((int)temp<<shifting & colorMask);
             
              img.setRGB(i,j,newColor);
            }     
    }
    }
   
    /**
     * Genera un efecto de desenfoque sobre la imagen
     */
    public void movingAverage()
    {
        float matrix[][]={{0.025f,0.05f,0.025f},{0.05f,0.7f,0.05f},{0.025f,0.05f,0.025f}};       
       
        int temp;     
       
        for(int i=1; i<img.getWidth()-1; i++)       
            for(int j=1; j<img.getHeight()-1; j++)
            {
                temp=0;

                temp += (int)(getIntensity(i-1,j-1)*matrix[0][0]);
                temp += (int)(getIntensity(i-1,j*matrix[0][1]);
                temp += (int)(getIntensity(i-1,j+1)*matrix[0][2]);
               
                temp += (int)(getIntensity(i  ,j-1)*matrix[1][0]);
                temp += (int)(getIntensity(i  ,j  )*matrix[1][1]);
                temp += (int)(getIntensity(i  ,j+1)*matrix[1][2]);
               
                temp += (int)(getIntensity(i+1,j-1)*matrix[2][0]);
                temp += (int)(getIntensity(i+1,j  )*matrix[2][1]);
                temp += (int)(getIntensity(i+1,j+1)*matrix[2][2]);
               
                temp=((temp << 8) + (temp << 16) + (temp << 24))+temp;
               
                img.setRGB(i,j,temp);               
            }
    }
   
    /**
     * Reemplaza la imagen por una representaci�n de sus bordes
     * @param sensibility nivel de sensibilidad para encontrar un borde
     */
    public void findBorder(float sensibility)
    {
        float matrixX[][]={{-1f,0f,+1f},{-2f,0f,2f},{-1f,0f,1f}};       
        float matrixY[][]={{1f,2f,1f},{0f,0f,0f},{-1f,-2f,-1f}};               
       
        if(sensibility<0) sensibility*=-1;
       
        int tempX,tempY;
        int finalColor;       
        Raster raster=img.getData();
        BufferedImage copy=new BufferedImage(img.getWidth(),img.getHeight(),img.getType());
        copy.setData(raster);
       
        for(int i=1; i<img.getWidth()-1; i++)       
            for(int j=1; j<img.getHeight()-1; j++)
            {
                tempX=0;
                tempY=0;

                /** X **/
                tempX += (int)(getIntensity(i-1,j-1)*matrixX[0][0]);
                tempX += (int)(getIntensity(i-1,j*matrixX[0][1]);
                tempX += (int)(getIntensity(i-1,j+1)*matrixX[0][2]);
               
                tempX += (int)(getIntensity(i  ,j-1)*matrixX[1][0]);
                tempX += (int)(getIntensity(i  ,j  )*matrixX[1][1]);
                tempX += (int)(getIntensity(i  ,j+1)*matrixX[1][2]);
               
                tempX += (int)(getIntensity(i+1,j-1)*matrixX[2][0]);
                tempX += (int)(getIntensity(i+1,j  )*matrixX[2][1]);
                tempX += (int)(getIntensity(i+1,j+1)*matrixX[2][2]);
               
                /** Y **/
                tempY += (int)(getIntensity(i-1,j-1)*matrixY[0][0]);
                tempY += (int)(getIntensity(i-1,j*matrixY[0][1]);
                tempY += (int)(getIntensity(i-1,j+1)*matrixY[0][2]);
               
                tempY += (int)(getIntensity(i  ,j-1)*matrixY[1][0]);
                tempY += (int)(getIntensity(i  ,j  )*matrixY[1][1]);
                tempY += (int)(getIntensity(i  ,j+1)*matrixY[1][2]);
               
                tempY += (int)(getIntensity(i+1,j-1)*matrixY[2][0]);
                tempY += (int)(getIntensity(i+1,j  )*matrixY[2][1]);
                tempY += (int)(getIntensity(i+1,j+1)*matrixY[2][2]);
                               
                float sum=(float)Math.sqrt(tempX*tempX+tempY*tempY);
               
                if(sum>sensibility){
                    finalColor=(int)(0);
                    finalColor=((finalColor << 8) + (finalColor << 16) + (finalColor << 24))+finalColor;
                    copy.setRGB(i,j,finalColor);
                }
                else{
                    finalColor=(int)(255);
                    finalColor=((finalColor << 8) + (finalColor << 16) + (finalColor << 24))+finalColor;
                    copy.setRGB(i,j,finalColor);
                }               
            }
        raster=copy.getData();
        img.setData(raster);
    }
   
    /**
     * Calcula la superposicion entre dos objetos en base a cu�n rodeado
     * est� el objeto1 por el objeto2
     *
     * @param object1 colores que representan al objeto1 en canales RGB
     * @param object2 colores que representan al objeto2 en canales RGB
     * @param tolerance par�metro para regular la sensibilidad del algoritmo
     * @return nivel superposici�n de objeto1 y objeto2
     */
    public float calcularSuperposicion(char[][] object1, char[][] object2, float tolerance, float centroidTolerance) {
     
      int[] boundingBox = getBoundingBox(object1,centroidTolerance);
     
      int x0 = boundingBox[0], y0 = boundingBox[1],x1 = boundingBox[2],y1 = boundingBox[3];
           
      int colorMassInBox = getColorMassInRegion(object2,boundingBox,tolerance);
     
      int totalMass = (int)Math.round((float)(y1-y0) * (float)(x1-x0));
     
      return (float)colorMassInBox / (float) totalMass;
    }
   
    /**
     * Obtiene la masa absoluta de colores de un objeto en una region
     *
     * @param object matriz con las componentes de color del objeto en cada canal
     * @param boundingBox region de la imagen donde se encuentra el objeto (x0,y0,x1,y1)
     * @param tolerance nivel de precisi�n a la hora de matchear colores (0 hasta 1)
     * @return el n�mero absoluto de colores que matchearon
     */
    private int getColorMassInRegion(char[][] object, int[] boundingBox,float tolerance) {
     
      int x0 = boundingBox[0], y0 = boundingBox[1],x1 = boundingBox[2],y1 = boundingBox[3];
     
      int matches = 0;
     
      for (int i = x0; i < x1; i++) {
        for (int j = y0; j < y1; j++) {
          int actualColor = img.getRGB(i, j);
          if(isColorMatch(object,actualColor,tolerance)) {
            matches ++;
          }
      }
    }
     
      if(matches == 0) return 0
      else return matches;
  }

    /**
     * Obtiene estad�sticamente las coordenadas de un rect�ngulo que encierra al objeto.
     *
     * No hay garant�as de que el cuadrado encierre efectivamente al objeto.
     *
     * @param object colores RGB que definen al objeto
     * @param centroidTolerance nivel de exactitud requerido por el algoritmo (0 m�s exacto, 1 menos exacto)
     * @return coordenadas del rect�ngulo que encierra al objeto
     */
  private int[] getBoundingBox(char[][] object, float centroidTolerance) {
     
      int anchoImagen = img.getWidth(), altoImagen = img.getHeight();
     
      int centroidX = 0, centroidY = 0;
     
      int matches = 0;
      long varX = 0, varY = 0;
     
      for (int i = 0; i < anchoImagen; i++) {
        for (int j = 0; j < altoImagen; j++) {
          int actualColor = img.getRGB(i, j);
          if(isColorMatch(object,actualColor,centroidTolerance)) {
            centroidX += i;
            centroidY += j;           
            matches ++;
          }
      }
    }
     
      if (matches == 0) return new int[] {0,0,0,0};
     
      centroidX = Math.round((float)centroidX / (float)matches);
      centroidY = Math.round((float)centroidY / (float)matches);
         
      for (int i = 0; i < anchoImagen; i++) {
        for (int j = 0; j < altoImagen; j++) {
          int actualColor = img.getRGB(i, j);
          if(isColorMatch(object,actualColor,centroidTolerance)) {
            varX += Math.pow(i-centroidX,2);
            varY += Math.pow(j-centroidY,2);          
          }
      }
    }
     
      int desvioX = (int)Math.round(Math.sqrt((double)varX/(double)(matches-1)));
      int desvioY = (int)Math.round(Math.sqrt((double)varY/(double)(matches-1)));
     
// debug, pinta un cuadro negro
//      for (int i = Math.max(0,centroidX - (int)Math.round(2.5*desvioX)); i < Math.min(centroidX + (int)Math.round(2.5*desvioX),anchoImagen); i++) {
//        for (int j = Math.max(0,centroidY - (int)Math.round(2.5*desvioY)); j < Math.min(centroidY + (int)Math.round(2.5*desvioY),anchoImagen); j++) {         
//            img.setRGB(i, j, 0);          
//        }
//    }
      // x0,y0,x1,y1
      return new int[] {
                Math.max(0,centroidX - (int)Math.round(2.5*desvioX)),
                Math.max(0,centroidY - (int)Math.round(2.5*desvioY)),
                Math.min(centroidX + (int)Math.round(2.5*desvioX),anchoImagen),
                Math.min(centroidY + (int)Math.round(2.5*desvioY),anchoImagen)
                     };
  }
   
  /**
   * Determina si hay coincidencia entre un color y una lista de colores RGB
   * con la tolerancia especificada
   *
   * @param object lista de colores RGB del objeto
   * @param actualColor color que se quiere saber si pertenece al objeto
   * @param tolerance nivel de tolerancia entre 0 y 1
   * @return true si actualColor est� en object, false en caso contrario
   */
    private boolean isColorMatch(char[][] object, int actualColor, float tolerance) {
     
      int actualRed = getSingleChannelColor(actualColor, RED_CHANNEL);
      int actualGreen = getSingleChannelColor(actualColor, GREEN_CHANNEL);
      int actualBlue = getSingleChannelColor(actualColor, BLUE_CHANNEL);
     
      for (int i = 0; i < object[0].length; i++) {
        int minRed = Math.round(object[RED_CHANNEL][i]-256*tolerance);
        int maxRed = Math.round(object[RED_CHANNEL][i]+256*tolerance);
                                        
        int minGreen = Math.round(object[GREEN_CHANNEL][i]-256*tolerance);
        int maxGreen = Math.round(object[GREEN_CHANNEL][i]+256*tolerance);
       
        int minBlue = Math.round(object[BLUE_CHANNEL][i]-256*tolerance);
        int maxBlue = Math.round(object[BLUE_CHANNEL][i]+256*tolerance);
     
        if( actualRed > minRed && actualRed < maxRed &&
          actualGreen > minGreen && actualGreen < maxGreen &&
          actualBlue > minBlue && actualBlue < maxBlue ) {
          return true;
        }
       
    }
     
     
    return false;
  }
   
  /**
     * Obtiene la entrop�a de la imagen a partir del histograma de grises
     * @return la entropia de la imagen en escala de grises
     */
    public float getEntropy(){
      this.buildIntensityHistogram();
     
      float entropy=0;
      float sum = img.getWidth()*img.getHeight();
     
     
      for (int i = 0; i < grayHistogram.length; i++) {
      float probability = (((float)grayHistogram[i])/sum);
      if(probability>0) {
        entropy+= (-probability*Math.log(probability)/Math.log(2));
       
      }
    }

      return entropy;
    }

   
  public BufferedImage getImg() {
    return img;
  }

  public void setImg(BufferedImage img) {
    this.img = img;
  }

  public float getHuffAvg() {
    this.buildIntensityHistogram();
      HuffmanCoder coder=new HuffmanCoder();
      coder.buildTreeFromFrequency(grayHistogram);
      return coder.getAverageBits();
  }

  private void logInfo(String info) {
    System.out.println(info);
  }
 
  private char getSingleChannelColor(int color, int channel) {
    switch(channel) {
      case RED_CHANNEL: return (char)(((color >> 16) & 0xFF));
      case GREEN_CHANNEL: return (char)(((color >> 8) & 0xFF));
      case BLUE_CHANNEL: return (char)(((color >> 0) & 0xFF));
    }
    return 0;
  }
 
}
TOP

Related Classes of taller3.ImageProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.