1. 程式人生 > >用java實現圖片漸變疊加(3種方法)

用java實現圖片漸變疊加(3種方法)

原理上是2種方法,但是可以用3種方法實現(沒想到花了我那麼多時間):1.是根據alpha值計算,象素的各單色分量衰減後相加;2.是修改一張圖片的透明度,然後用畫到另一張圖片上面;3.是象素點的插值,不涉及透明度的使用。做的時候先試的第3種方法的,花的時間最多,結果發現效果最爛,象素差別過大看起來就像麻子一樣。程式碼裡的漸變範圍是圖片的1/4到3/4.自己可以修改的^_^。

最簡單的是第2種方法。第3種效果最差,但是最容易想到。我最喜歡的是第1種。

程式碼和上一篇blog《用java分離象素》有很多重複的地方,但是為了眾看客執行方便,重複的部分還是寫了出來。

實現過程描述如下:

一。根據alpha值計算

  把圖片的象素分離出來。原圖的alpha值都設為0xff。確定一張圖片A漸變的衰減係數div(0~1),另一張圖片B的衰減就是1-div。

div=row/range; row是遞增的行,range是漸變範圍。

合成漸變的象素的公式我發現是:

color=(A.blue+A.green+A.red)*div+(B.blue+B.green+B.red)*(1-div)

A表示圖片A的某點象素,B表示圖片B的某點象素。當然實現上各種顏色不能直接相加,要位移相應的位,然後進行或運算。

二。修改透明度

   修改圖片B的漸變範圍象素的alpha值,alpha為0就是透明,0xff為不透明。漸變就是alpha的值的遞變。然後以圖片B的大小,新建一個影象緩衝bi

Graphics2D g2= (Graphics2D)bi.getGraphics();
        g2.drawImage(imageA.getImage(),0,0,null)//將圖片A畫入緩衝區bi

        最後把修改好的半透明圖片畫入bi
        g2.drawImage(image,0,0,null);

最後完整的圖片漸變疊加就儲存在了這個緩衝區內。最後輸出圖片即可。

javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));

我想應該還有別的辦法可以實現:對兩張圖片的象素,基於alpha值進行計算,是可以合成漸變效果的象素的。目前還沒有試驗出這個計算方法。

三。象素插值。等差數列的原理。

 有兩張圖片A,B,圖片A的象素密度隨橫座標的的增加減小,圖片B的密度與圖片A變化相反。

 我用的方法是,描述每一列相隔row行,需要插入一個象素。row這個變數的取值,在紙面上畫出來的曲線,是在漸變區先增後減的一次函式。轉折點是漸變區的中點。

下面的程式碼按順序對應的上面的每種方法。

方法一:

import java.awt.image.PixelGrabber;
import java.awt.Image;
import java.awt.image.ImageObserver;
import  javax.swing.ImageIcon;
import java.io.FileWriter;
import javax.swing.JFrame;
import java.awt.image.MemoryImageSource;
import  java.awt.Graphics2D;
import java.io.File;
public class SpliceCount{
 int pixels[];
 int Aw,Ah,Bw,Bh;
 int Wmax,Hmax;  //the size of splice image
 int arrayImageA[],arrayImageB[];   //arrays used to save the pixels
 String imagepathA="images/try.gif"; //you can change the image path here
 String imagepathB="images/fruit1.jpg";
 String outputimage="SpliceCount.jpg";
 FileWriter fw;  //used to write log
 int index=0;
 ImageIcon imageA,imageB;
 public SpliceCount(){
  
  imageA=new ImageIcon(imagepathA);
  imageB=new ImageIcon(imagepathB);
  
  Aw=imageA.getIconWidth();
  Ah=imageA.getIconHeight();
  Bw=imageB.getIconWidth();
  Bh=imageB.getIconHeight();
  arrayImageA=handlepixels(imageA.getImage(),0,0,Aw,Ah);
  arrayImageB=handlepixels(imageB.getImage(),0,0,Bw,Bh);
  if(arrayImageA!=null&&arrayImageB!=null){
   
   doSplice(arrayImageA,arrayImageB);   
   Image image=createImage(pixels);
   saveImage(image,outputimage);
  }
  if(fw!=null){
   try{
    fw.close();
   }catch(Exception e){
    e.printStackTrace();
   }   
  }
 }
 
 public void doSplice(int[] imageA,int[] imageB){
  pixels=imageB;
  Hmax=Bh;
  Wmax=Bw;
  int rangeFrom=Bw/4;
  int rangeTo=Bw*3/4;
     int range=Bw>>1;
      
  for(int i=rangeFrom;i<Bw;i++){
      float div=(float)(rangeTo-i)/(float)range;
      if(i>rangeTo){   //漸變範圍以外,不衰減
       div=0;       
      }                
      float div1=1-div;  //漸變左邊範圍以外,不衰減,用imgeA填充
     
     
      for(int j=0;j<Bh;j++){
       int pixel=pixels[j*Bw+i];
       int alpha = (pixel >> 24) & 0xff; //分離imageB象素好相加
             int red   = (pixel >> 16) & 0xff;       
             int green = (pixel >>  8) & 0xff;
             int blue  = (pixel     ) & 0xff;
             
             int alpha1,red1,green1,blue1;
             pixel=imageA[j*Aw+i];  //準備分離imageA象素
             if(i>Aw||j>Ah){    //imageA 的大小不夠,用白色填充
              alpha1 = 0xff;
               red1 = 0xff;
               green1= 0xff;
               blue1= 0xff;
             }else{
               alpha1 = (pixel >> 24) & 0xff;
                  red1   = (pixel >> 16) & 0xff;       
                  green1 = (pixel >>  8) & 0xff;
                  blue1  = (pixel     ) & 0xff;
             }            
             
       alpha=0xff;
       red =Math.round(red*div+red1*div1); //象素按每種顏色的衰減相加
       green =Math.round(green*div+green1*div1);
       blue =Math.round(blue*div+blue1*div1);
       
          pixels[j*Bw+i]=(alpha<<24)|(red<<16)|(green<<8)|(blue); //合成顏色  
         
   }
  } 
 }
 public void writePixel2File(int color){
     index++;
     
     if(fw==null){
      try{
     fw =new FileWriter("pixel.txt");
     }catch(Exception e){
      e.printStackTrace();
     }
     }             
        try{
         if(index%100==0)
         fw.write("n");
         
         fw.write("t"+color);
        }catch(Exception e){
         e.printStackTrace();
        }
    }
 
 public Image createImage(int[] colors){
     JFrame jf=new JFrame();
        Image modImg = jf.createImage(
              new MemoryImageSource(           
             Wmax,Hmax,colors,0,Wmax));
        return modImg;
    }
   
 
 public void saveImage(Image image,String filename){     
     java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage(Wmax, Hmax, java.awt.image.BufferedImage.TYPE_INT_BGR);
        Graphics2D g2= (Graphics2D)bi.getGraphics();
      
        g2.drawImage(image,0,0,null);
       
        try{
         javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));
        }catch(Exception e){
         e.printStackTrace();
        }       
    }
   
 public int[] handlepixels(Image img, int x, int y, int w, int h) {
        int[] pixel = new int[w * h];               
        PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixel, 0, w);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            System.err.println("interrupted waiting for pixels!");
           
        }
        if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
            System.err.println("image fetch aborted or errored");
        }      
        return pixel;
    }
 public static void main(String[] args){
  SpliceCount splice=new SpliceCount();
 }
}


方法二

import java.awt.image.PixelGrabber;
import java.awt.Image;
import java.awt.image.ImageObserver;
import  javax.swing.ImageIcon;
import java.io.FileWriter;
import javax.swing.JFrame;
import java.awt.image.MemoryImageSource;
import  java.awt.Graphics2D;
import java.io.File;
public class SpliceAlpha{
 int pixels[];
 int Aw,Ah,Bw,Bh;
 int Wmax,Hmax;  //the size of splice image
 int arrayImageA[],arrayImageB[];   //arrays used to save the pixels
 String imagepathA="images/try.gif"; //you can change the image path here
 String imagepathB="images/fruit1.jpg";
 String outputimage="splicealpha.jpg";
 FileWriter fw;  //used to write log
 int index=0;
 ImageIcon imageA,imageB;
 public SpliceAlpha(){
  
  imageA=new ImageIcon(imagepathA);
  imageB=new ImageIcon(imagepathB);
  
  Aw=imageA.getIconWidth();
  Ah=imageA.getIconHeight();
  Bw=imageB.getIconWidth();
  Bh=imageB.getIconHeight();
  arrayImageA=handlepixels(imageA.getImage(),0,0,Aw,Ah);
  arrayImageB=handlepixels(imageB.getImage(),0,0,Bw,Bh);
  if(arrayImageA!=null&&arrayImageB!=null){
   
   doSplice(arrayImageA,arrayImageB);   
   Image image=createImage(pixels);
   saveImage(image,outputimage);
  }
  if(fw!=null){
   try{
    fw.close();
   }catch(Exception e){
    e.printStackTrace();
   }   
  }
 }
 
 public void doSplice(int[] imageA,int[] imageB){
  pixels=imageB;
  Hmax=Bh;
  Wmax=Bw;
  int rangeFrom=Bw/4;
  int rangeTo=Bw*3/4;
     int range=Bw>>1;
      
  for(int i=rangeFrom;i<Bw;i++){
      float div=(float)(rangeTo-i)/(float)range;
      int alpha=(int)(0xff*div);
      alpha=alpha<<24;
     
      for(int j=0;j<Bh;j++){
       if(i>=rangeTo){
         pixels[j*Bw+i]=0;
           continue;
          }
      pixels[j*Bw+i]=pixels[j*Bw+i]&0xffffff;    
      pixels[j*Bw+i]=pixels[j*Bw+i]|(alpha);
     
   }
  } 
 }
 public void writePixel2File(int color){
     index++;
     
     if(fw==null){
      try{
     fw =new FileWriter("pixel.txt");
     }catch(Exception e){
      e.printStackTrace();
     }
     }             
        try{
         if(index%100==0)
         fw.write("\n");
         
         fw.write("\t"+color);
        }catch(Exception e){
         e.printStackTrace();
        }
    }
 
 public Image createImage(int[] colors){
     JFrame jf=new JFrame();
        Image modImg = jf.createImage(
              new MemoryImageSource(           
             Wmax,Hmax,colors,0,Wmax));
        return modImg;
    }
   
 
 public void saveImage(Image image,String filename){     
     java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage(Wmax, Hmax, java.awt.image.BufferedImage.TYPE_INT_BGR);
        Graphics2D g2= (Graphics2D)bi.getGraphics();
        g2.drawImage(imageA.getImage(),0,0,null);
        g2.drawImage(image,0,0,null);
       
        try{
         javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));
        }catch(Exception e){
         e.printStackTrace();
        }       
    }
   
 public int[] handlepixels(Image img, int x, int y, int w, int h) {
        int[] pixel = new int[w * h];               
        PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixel, 0, w);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            System.err.println("interrupted waiting for pixels!");
           
        }
        if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
            System.err.println("image fetch aborted or errored");
        }      
        return pixel;
    }
 public static void main(String[] args){
  SpliceAlpha splice=new SpliceAlpha();
 }
}


方法三

用象素交錯填充的辦法實現的圖片疊加。

效果不怎麼好

import java.awt.image.PixelGrabber;
import java.awt.Image;
import java.awt.image.ImageObserver;
import  javax.swing.ImageIcon;
import java.io.FileWriter;
import javax.swing.JFrame;
import java.awt.image.MemoryImageSource;
import  java.awt.Graphics2D;
import java.io.File;


public class Splice{
 int arrayImageA[],arrayImageB[];   //arrays used to save the pixels
 String imagepathA="images/try.gif"; //you can change the image path here
 String imagepathB="images/fruit1.jpg";
 int rangeFrom,rangeTo; //the transition range from one position to another
 int splicePixel[];
 int Aw,Ah,Bw,Bh;
 int Wmax,Hmax;  //the size of splice image
 String outputimage="splice.jpg";
 int index=0;
 FileWriter fw;
 
 
 public Splice(){
  
  ImageIcon imageA=new ImageIcon(imagepathA);
  ImageIcon imageB=new ImageIcon(imagepathB);
  
  Aw=imageA.getIconWidth();
  Ah=imageA.getIconHeight();
  Bw=imageB.getIconWidth();
  Bh=imageB.getIconHeight(); 
   
  arrayImageA=handlepixels(imageA.getImage(),0,0,Aw,Ah);
  arrayImageB=handlepixels(imageB.getImage(),0,0,Bw,Bh);
  if(arrayImageA!=null&&arrayImageB!=null){
   doSplice2(arrayImageA,arrayImageB);   
   Image image=createImage(splicePixel);
   saveImage(image,outputimage);
  }
  if(fw!=null){
   try{
    fw.close();
   }catch(Exception e){
    e.printStackTrace();
   }   
  }    
  
 }
 public Image createImage(int[] colors){
     JFrame jf=new JFrame();
        Image modImg = jf.createImage(
              new MemoryImageSource(           
             Wmax,Hmax,colors,0,Wmax));
        return modImg;
    }
   
    public void saveImage(Image image,String filename){     
     java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage(Wmax, Hmax, java.awt.image.BufferedImage.TYPE_INT_BGR);
        Graphics2D g2= (Graphics2D)bi.getGraphics();
        g2.drawImage(image,0,0,null);
       
        try{
         javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));
        }catch(Exception e){
         e.printStackTrace();
        }       
    }
 /*
  *the method can splice two image(array) into one image(array)
  *the the range smaller than the the image size
  *@all parameter must not to be null!!!
  *
  **/

    public void doSplice2(int[] imageA,int[] imageB){
     //first of all,you should check whether the condition fill this method
     if(Aw>Bw){
      Wmax=Aw;          
     }else{
      Wmax=Bw;
     }
     
     rangeFrom=Wmax/4;  // you can set range here
     rangeTo=Wmax*3/4;   
     if(rangeFrom>Wmax)
        return;
     if(rangeFrom>=rangeTo)
        return;  
     if(Ah>Bh){
       Hmax=Ah;
     }else{
       Hmax=Bh; 
     }
     splicePixel=new int[Wmax*Hmax];
     int range=rangeTo-rangeFrom;
     float sp=((float)Hmax/(float)range);    //step 
    
      
      
     for(int i=0;i<Wmax;i++){   //col
      
      float rownumber=sp*(rangeTo-i);
         float row=((float)Hmax)/rownumber;
            int start=(int)Math.round(Math.random()*row);
            float point=start;
      //System.out.print("\n"+row);
      for(int j=0;j<Hmax;j++){   //row       
       start=Math.round(point);
      // start=start+(int)Math.round((Math.random()-0.5)*row);
          if(start<0)
         start=0;       
                 
       if(i<rangeFrom){
        if(j>=Bh||i>=Bw){
         splicePixel[j*Wmax+i]=0xffffffff;
         continue;
        }
           splicePixel[j*Wmax+i]=imageB[j*Bw+i]; 
         continue;
       }else if(i>=rangeTo){
        if(j>=Ah||i>=Aw){
          splicePixel[j*Wmax+i]=0xffffffff;
          continue;
         }
           splicePixel[j*Wmax+i]=imageA[j*Aw+i]; 
           continue; 
       }
      // this.writePixel2File((int)Math.round((Math.random()-0.5)*row));
       if(j==start){
        
         if(j>=Ah||i>=Aw){
          splicePixel[j*Wmax+i]=0xffffffff;
          continue;
         }       
            splicePixel[j*Wmax+i]=imageB[j*Bw+i];
            point=point+row;  
       }else{       
        if(j>=Bh||i>=Bw){
          splicePixel[j*Wmax+i]=0xffffffff;
          continue;
        }
        splicePixel[j*Wmax+i]=imageA[j*Aw+i];
       }    
      }
     }
   }
  
    public void writePixel2File(int color){
     index++;
     
     if(fw==null){
      try{
     fw =new FileWriter("pixel.txt");
     }catch(Exception e){
      e.printStackTrace();
     }
     }             
        try{
         if(index%100==0)
         fw.write("\n");
         
         fw.write("\t"+color);
        }catch(Exception e){
         e.printStackTrace();
        }
    }
 public int[] handlepixels(Image img, int x, int y, int w, int h) {
        int[] pixels = new int[w * h];               
        PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            System.err.println("interrupted waiting for pixels!");
           
        }
        if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
            System.err.println("image fetch aborted or errored");
        }      
        return pixels;
    }
 public static void main(String[] args){
  Splice splice=new Splice();
 }
}