Search code examples
javadistortionfisheye

Can't use fisheye lens effect on my image in Java


I want to use fisheye lens algorithm in Java, but I can't implement a main method.

At the bottom of this site, I found java code, that implements fisheye algorithm, but there wasn't any main() method. I've tried to implement a main() method by my own, but so far I just can display image, but I can't use the barrel() method on that image which should make fisheye effect on my image.

Could you please correct my main method, or implement a new one, that loads some image(bufferedImage) and then use barrel() method on that image?

My code so far is:

import java.awt.FlowLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class DisplayImage {
float xscale;
float yscale;
float xshift;
float yshift;
int [] s;                             


public BufferedImage barrel (BufferedImage input, float k){

    float centerX=input.getWidth()/2; //center of distortion
    float centerY=input.getHeight()/2;

    int width = input.getWidth(); //image bounds
    int height = input.getHeight();

    BufferedImage dst = new BufferedImage(width, height,BufferedImage.TYPE_INT_ARGB); //output pic

      xshift = calc_shift(0,centerX-1,centerX,k);
      float newcenterX = width-centerX;
      float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,k);

      yshift = calc_shift(0,centerY-1,centerY,k);
      float newcenterY = height-centerY;
      float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,k);

      xscale = (width-xshift-xshift_2)/width;
      yscale = (height-yshift-yshift_2)/height;

      for(int j=0;j<dst.getHeight();j++){
          for(int i=0;i<dst.getWidth();i++){
            float x = getRadialX((float)i,(float)j,centerX,centerY,k);
            float y = getRadialY((float)i,(float)j,centerX,centerY,k);
            sampleImage(input,x,y);
            int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
//            System.out.print(i+" "+j+" \\");

            dst.setRGB(i, j, color);

          }
        }
    return dst;
}

void sampleImage(BufferedImage arr, float idx0, float idx1)
{
    s = new int [4];
  if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1)){
    s[0]=0;
    s[1]=0;
    s[2]=0;
    s[3]=0;
    return;
  }

  float idx0_fl=(float) Math.floor(idx0);
  float idx0_cl=(float) Math.ceil(idx0);
  float idx1_fl=(float) Math.floor(idx1);
  float idx1_cl=(float) Math.ceil(idx1);

  int [] s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
  int [] s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
  int [] s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
  int [] s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl);

  float x = idx0 - idx0_fl;
  float y = idx1 - idx1_fl;

  s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y));
  s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y));
  s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y));
  s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y));
}

int [] getARGB(BufferedImage buf,int x, int y){
    int rgb = buf.getRGB(x, y); // Returns by default ARGB.
    int [] scalar = new int[4];
    scalar[0] = (rgb >>> 24) & 0xFF;
    scalar[1] = (rgb >>> 16) & 0xFF;
    scalar[2] = (rgb >>> 8) & 0xFF;
    scalar[3] = (rgb >>> 0) & 0xFF;
    return scalar;
}

float getRadialX(float x,float y,float cx,float cy,float k){
  x = (x*xscale+xshift);
  y = (y*yscale+yshift);
  float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
  return res;
}

float getRadialY(float x,float y,float cx,float cy,float k){
  x = (x*xscale+xshift);
  y = (y*yscale+yshift);
  float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
  return res;
}

float thresh = 1;

float calc_shift(float x1,float x2,float cx,float k){
  float x3 = (float)(x1+(x2-x1)*0.5);
  float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx)));
  float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx)));

  if(res1>-thresh && res1 < thresh)
    return x1;
  if(res3<0){
    return calc_shift(x3,x2,cx,k);
  }
  else{
    return calc_shift(x1,x3,cx,k);
  }
}



public static void main(String avg[]) throws IOException
{
    BufferedImage img=ImageIO.read(new File("image.jpg"));       
    ImageIcon icon=new ImageIcon(img);   
    JFrame frame=new JFrame();
    frame.setLayout(new FlowLayout());
    frame.setSize(625,648);
    JLabel lbl=new JLabel();
    lbl.setIcon(icon);
    frame.add(lbl);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


}

}

Code is working, but it only display image. I want to use barrel() method on my image, which will do the fisheye effect. Because I am newbie to java, I can't do that, please help.


Solution

  • So I finally implemented desired fisheye! Just because of this and this site. I am giving here really messy but working code for anyone with similar problem:

    package fisheye;
    
    import java.awt.image.BufferedImage;
    import java.awt.image.WritableRaster;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    
    public class DitherMain {
    
       static String imageString = "image.bmp";
    
       BufferedImage startImage, endImage;
       int[] startPixels, endPixels, imR, imG, imB;
       int width, height;
    
       public static void main(String[] args){
          new DitherMain(loadImage(imageString));
       }
    
       //this object transforms the old image and writes the new image
       DitherMain(BufferedImage img){
          //filing the image into startpixels
          startImage = img;
          width = img.getWidth();
          height = img.getHeight();
          startPixels = new int[width*height];
          img.getRGB(0, 0, width, height, startPixels, 0, width);
    
          endPixels = fisheye(startPixels, width, height);
    
          transformPixels();
    
          WritableRaster wRaster = endImage.getData().createCompatibleWritableRaster();
    
          wRaster.setSamples(0, 0, width, height, 0, imR);
          wRaster.setSamples(0, 0, width, height, 1, imG);
          wRaster.setSamples(0, 0, width, height, 2, imB);
    
          endImage.setData(wRaster);
          System.out.println(endImage);
    
          //writing the file for endImage into the harddrive
          writeFile();
       }
    
       void transformPixels(){
          //endPixels = startPixels;
          endImage = startImage;
    
          imR = new int[endPixels.length];
          imG = new int[endPixels.length];
          imB = new int[endPixels.length];
    
          for(int i = 0; i < endPixels.length; i++){
             imR[i] = (endPixels[i] >> 16) & 0x000000FF;
             imG[i] = (endPixels[i] >> 8) & 0x000000FF;
             imB[i] = endPixels[i] & 0x000000FF;
          }
       }
    
       void writeFile(){
          try {
             ImageIO.write(endImage,"BMP",new File("RESULT.bmp"));
          } catch (IOException e) {
             e.printStackTrace();
          }
       }
    
       //this method just loads a specific buffered image
       public static BufferedImage loadImage(String fileName){   
          BufferedImage img;
    
          try{
             img=ImageIO.read(new File("image.bmp"));
             //img = ImageIO.read(DitherMain.class.getResource(fileName));
          } catch (Exception e) {
             e.printStackTrace();
             throw new RuntimeException(e);
          }
          return img;
       }
    
    public static int[] fisheye(int[] srcpixels, double w, double h) {
    
        /*
         *    Fish eye effect
         *    tejopa, 2012-04-29
         *    http://popscan.blogspot.com
         *    http://www.eemeli.de
         */
    
        // create the result data
        int[] dstpixels = new int[(int)(w*h)];            
        // for each row
        for (int y=0;y<h;y++) {                                
            // normalize y coordinate to -1 ... 1
            double ny = ((2*y)/h)-1;                        
            // pre calculate ny*ny
            double ny2 = ny*ny;                                
            // for each column
            for (int x=0;x<w;x++) {                            
                // normalize x coordinate to -1 ... 1
                double nx = ((2*x)/w)-1;                    
                // pre calculate nx*nx
                double nx2 = nx*nx;
                // calculate distance from center (0,0)
                // this will include circle or ellipse shape portion
                // of the image, depending on image dimensions
                // you can experiment with images with different dimensions
                double r = Math.sqrt(nx2+ny2);                
                // discard pixels outside from circle!
                if (0.0<=r&&r<=1.0) {                            
                    double nr = Math.sqrt(1.0-r*r);            
                    // new distance is between 0 ... 1
                    nr = (r + (1.0-nr)) / 2.0;
                    // discard radius greater than 1.0
                    if (nr<=1.0) {
                        // calculate the angle for polar coordinates
                        double theta = Math.atan2(ny,nx);         
                        // calculate new x position with new distance in same angle
                        double nxn = nr*Math.cos(theta);        
                        // calculate new y position with new distance in same angle
                        double nyn = nr*Math.sin(theta);        
                        // map from -1 ... 1 to image coordinates
                        int x2 = (int)(((nxn+1)*w)/2.0);        
                        // map from -1 ... 1 to image coordinates
                        int y2 = (int)(((nyn+1)*h)/2.0);        
                        // find (x2,y2) position from source pixels
                        int srcpos = (int)(y2*w+x2);            
                        // make sure that position stays within arrays
                        if (srcpos>=0 & srcpos < w*h) {
                            // get new pixel (x2,y2) and put it to target array at (x,y)
                            dstpixels[(int)(y*w+x)] = srcpixels[srcpos];    
                        }
                    }
                }
            }
        }
        //return result pixels
        return dstpixels;
    }    
    
    }