import java.awt.image.*;
import java.awt.*;
import javax.imageio.*;
import java.util.Hashtable;

// classe dei kernel di vari filtri
public class Puntuali
{

   public BufferedImage equalizza(BufferedImage immOrig) // Metodo implementato per l'equalizzazione
    {

     Istogramma isto= new Istogramma(immOrig);

          byte [][] tabella = new byte [3][256];

          for(int i=0; i<256; i++) tabella[0][i]=(byte)(isto.R()[i]*255);
          for(int i=0; i<256; i++) tabella[1][i]=(byte)(isto.G()[i]*255);
          for(int i=0; i<256; i++) tabella[2][i]=(byte)(isto.B()[i]*255);

          ByteLookupTable value=new ByteLookupTable(0,tabella);

          LookupOp iR=new LookupOp(value,null);

         BufferedImage temp=iR.filter(immOrig, null);
         return temp;

    }

    public BufferedImage negativo(BufferedImage immOrig)  // Metodo implementato per il negativo
    {
        byte [][] tabella = new byte [3][256];
        for(int i=0; i<256; i++)
        {
            tabella[0][i]=(byte)Math.round(255-i);
            tabella[1][i]=(byte)Math.round(255-i);
            tabella[2][i]=(byte)Math.round(255-i);
        }

        ByteLookupTable Table=new ByteLookupTable(0,tabella);
        LookupOp NegOp=new LookupOp(Table,null);
        immOrig =NegOp.filter(immOrig, null);

        return immOrig;
    }
    
    public BufferedImage incupire(BufferedImage ImmOrig)  // Metodo implementato per incupire
    {
        byte [][] tabella = new byte [3][256];
        double [] valoriLUT = new double [256];
        for(int i=0; i<256; i++)
            valoriLUT[i]=(i*i/255);
        for(int i=0; i<256; i++)
            tabella[0][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[1][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[2][i]=(byte)valoriLUT[i];

        ByteLookupTable value=new ByteLookupTable(0,tabella);

        LookupOp iR=new LookupOp(value,null);

        BufferedImage temp=iR.filter(ImmOrig, null);
        return temp;
    }

    public BufferedImage schiarire(BufferedImage immOrig) //Metodo implementato per schiarire
    {
        byte [][] tabella = new byte [3][256];

        double [] valoriLUT = new double [256];
        for(int i=0; i<256; i++)
            valoriLUT[i]=2*i-(i*i/255);
        for(int i=0; i<256; i++)
            tabella[0][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[1][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[2][i]=(byte)valoriLUT[i];
        
        ByteLookupTable value=new ByteLookupTable(0,tabella);
        LookupOp iR=new LookupOp(value,null);
        BufferedImage temp=iR.filter(immOrig, null);
        return temp;
    }

    public BufferedImage parametro(BufferedImage immOrig,double val) //Metodo implementato per operare con parametro
    {
       
        byte [][] tabella = new byte [3][256];

        double [] valoriLUT = new double [256];
        double d;

        if(val < 0.0 ) val = 0.0;
        for(int i=0; i<256; i++) { d = Math.round(i*val);
                                    if(d > 255.0 ) d= 255.0;
                                   valoriLUT[i]= d; }

        for(int i=0; i<256; i++)
            tabella[0][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[1][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[2][i]=(byte)valoriLUT[i];
        
        ByteLookupTable value=new ByteLookupTable(0,tabella);
        LookupOp iR=new LookupOp(value,null);
        BufferedImage temp=iR.filter(immOrig, null);
        return temp;
    }


    public BufferedImage logaritmica(BufferedImage immOrig,double R, double L) //Trasformazione logaritmica
    {
       
        byte [][] tabella = new byte [3][256];

        double [] valoriLUT = new double [256];
        double c= (L-1)/(Math.log(R));

        for(int i=0; i<256; i++)
                  valoriLUT[i]= Math.round(c*(Math.log(1+i)));

        for(int i=0; i<256; i++)
            tabella[0][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[1][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[2][i]=(byte)valoriLUT[i];
        
        ByteLookupTable value=new ByteLookupTable(0,tabella);
        LookupOp iR=new LookupOp(value,null);
        BufferedImage temp=iR.filter(immOrig, null);
        return temp;
    }

   public BufferedImage gaussiana(BufferedImage immOrig,double R, double L, double gamma) //Trasformazione gaussiana
    {
       
        byte [][] tabella = new byte [3][256];

        double [] valoriLUT = new double [256];
        double c= (L-1)/(Math.pow(R,gamma));

        for(int i=0; i<256; i++)
                  valoriLUT[i]= Math.round(c*(Math.pow(i,gamma)));

        for(int i=0; i<256; i++)
            tabella[0][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[1][i]=(byte)valoriLUT[i];
        for(int i=0; i<256; i++)
            tabella[2][i]=(byte)valoriLUT[i];
        
        ByteLookupTable value=new ByteLookupTable(0,tabella);
        LookupOp iR=new LookupOp(value,null);
        BufferedImage temp=iR.filter(immOrig, null);
        return temp;
    }

  public BufferedImage filtraCanali(BufferedImage originale, double redfactor, double greenfactor, double bluefactor)
    {
      BufferedImage copia = new BufferedImage(originale.getWidth(),originale.getHeight(),BufferedImage.TYPE_INT_RGB);          
      copiaImmagine(originale, copia);
      
      WritableRaster copiaRaster = copia.getRaster();
      WritableRaster origRaster = originale.getRaster();

        int x=originale.getWidth();
        int y=originale.getHeight();
        int rosso[] = origRaster.getSamples(0,0,x,y,0,(int [])(null));
        int verde[] = origRaster.getSamples(0,0,x,y,1,(int [])(null));
        int blue[]   = origRaster.getSamples(0,0,x,y,2,(int [])(null));
        
         int newRosso [] = new int [rosso.length];
         int newVerde [] = new int [verde.length];
         int newBlue [] = new int [blue.length];

        for(int i=0;i<newRosso.length;i++)
        {
            newRosso[i] =(byte)( rosso[i] * redfactor );
            newVerde[i] =(byte)( verde[i] * greenfactor );
            newBlue[i] =(byte)( blue[i] * bluefactor );
        }

        copiaRaster.setSamples(0,0,x,y,0,newRosso);
        copiaRaster.setSamples(0,0,x,y,1,newVerde);
        copiaRaster.setSamples(0,0,x,y,2,newBlue);

      return copia;
    }

  public BufferedImage scalaGrigi(BufferedImage originale)
    {
      BufferedImage copia = new BufferedImage(originale.getWidth(),originale.getHeight(),BufferedImage.TYPE_INT_RGB);          
      copiaImmagine(originale, copia);
      
      WritableRaster copiaRaster = copia.getRaster();
      WritableRaster origRaster = originale.getRaster();

        int x=originale.getWidth();
        int y=originale.getHeight();
        int rosso[] = origRaster.getSamples(0,0,x,y,0,(int [])(null));
        int verde[] = origRaster.getSamples(0,0,x,y,1,(int [])(null));
        int blue[]   = origRaster.getSamples(0,0,x,y,2,(int [])(null));
        
        //Dagli RGB dell'immagine originale metto nell'array Y il canale LUMINANZA secondo le regola
        // Y = ROSSO *0.299 + VERDE * 0.587 + BLU *0.114
        int Y [] = new int [rosso.length];

        for(int i=0;i<Y.length;i++)
        {
            Y[i] =(byte)( rosso[i] * 0.299 + verde[i] * 0.587 + blue[i] * 0.114);
        }

        copiaRaster.setSamples(0,0,x,y,0,Y);
        copiaRaster.setSamples(0,0,x,y,1,Y);
        copiaRaster.setSamples(0,0,x,y,2,Y);

      return copia;
    }

 


   private void copiaImmagine(BufferedImage origine, BufferedImage dest) /*Copia un'immagine in una di destinazione*/
    {
        Graphics2D g2=dest.createGraphics();
        g2.drawImage(origine,0,0,null);
        g2.dispose();
    }

}

