用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();
}
}