天天看點

圖像處理------基于像素的圖像混合

介紹幾種常見的将兩張圖像混合在一起形成一張新的圖像的算法,

首先看一下下面算法示範中要使用的兩張圖像:

圖像處理------基于像素的圖像混合
圖像處理------基于像素的圖像混合

為了得到更好的混合效果,我選擇了兩張一樣大小的圖檔。

方法一:

通過簡單對于像素點的像素相乘得到輸出像素值,代碼示範如下:

private int modeone(int v1, int v2) {  

<span style="white-space:pre">  </span>return (v1 * v2) / 255;  

}  

方法一的效果如下:

圖像處理------基于像素的圖像混合

方法二:

通過計算兩個像素之和再減去方法一的輸出值,代碼如下:

private int modetwo(int v1, int v2) {  

    return v1 + v2 - v1 * v2 / 255;  

方法二的效果如下:

圖像處理------基于像素的圖像混合

方法三:

通過像素值128這個特殊的中值來求取輸出值,代碼如下:

private int modethree(int v1, int v2) {  

    return (v2 < 128) ? (2 * v1 * v2 / 255):(255 - 2 * (255 - v1) * (255 - v2) / 255);  

方法三的效果如下:

圖像處理------基于像素的圖像混合

方法四:

與方法三不同,中值127.5被用在計算等式中,代碼如下:

private int modefour(double v1, double v2) {  

  if ( v1 > 127.5 ){  

      return (int)(v2 + (255.0 - v2) * ((v1 - 127.5) / 127.5) * (0.5 - math.abs(v2-127.5)/255.0));  

   }else{  

      return (int)(v2 - v2 * ((127.5 -  v1) / 127.5) * (0.5 - math.abs(v2-127.5)/255.0));  

   }  

方法四的效果如下:

圖像處理------基于像素的圖像混合

方法五:

中值計算考慮,是方法一的更新版本,使得混合更加精細,代碼如下:

private int modefive(double v1, double v2) {  

      return (int)(v2 + (255.0 - v2) * ((v1 - 127.5) / 127.5));  

      return (int)(v2 * v1 / 127.5);  

方法五的效果如下:

圖像處理------基于像素的圖像混合

濾鏡源代碼如下:

package com.gloomyfish.filter.study;  

import java.awt.image.bufferedimage;  

/*** 

 * i get these blend method from html5 demo then i decide to  

 * translate these java script methods into java 

 * 偶爾我也會寫中文注釋, 常見的圖像混合方法 

 * @author fish 

 * @date 2012-11-28 

 */  

public class imageblendfilter extends abstractbufferedimageop {  

    /** define the blend mode */  

    public final static int multiply_pixel = 1;  

    public final static int screen_pixel = 2;  

    public final static int overlay_pixel = 3;  

    public final static int softlight_pixel = 4;  

    public final static int hardlight_pixel = 5;  

    private int mode;  

    private bufferedimage secondimage;  

    public imageblendfilter() {  

        mode = 1;  

    }  

    public void setblendmode(int mode) {  

        this.mode = mode;  

    public void setsecondimage(bufferedimage image) {  

        this.secondimage = image;  

    @override  

    public bufferedimage filter(bufferedimage src, bufferedimage dest) {  

        checkimages(src);  

        int width = src.getwidth();  

        int height = src.getheight();  

        if ( dest == null )  

            dest = createcompatibledestimage( src, null );  

        int[] input1 = new int[width*height];  

        int[] input2 = new int[secondimage.getwidth() * secondimage.getheight()];  

        int[] outpixels = new int[width*height];  

        getrgb( src, 0, 0, width, height, input1);  

        getrgb( secondimage, 0, 0, secondimage.getwidth(), secondimage.getheight(), input2);  

        int index = 0;  

        int ta1 = 0, tr1 = 0, tg1 = 0, tb1 = 0;  

        for(int row=0; row<height; row++) {  

            for(int col=0; col<width; col++) {  

                index = row * width + col;  

                ta1 = (input1[index] >> 24) & 0xff;  

                tr1 = (input1[index] >> 16) & 0xff;  

                tg1 = (input1[index] >> 8) & 0xff;  

                tb1 = input1[index] & 0xff;  

                int[] rgb = getblenddata(tr1, tg1, tb1, input2, row, col);  

                outpixels[index] = (ta1 << 24) | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];  

            }  

        }  

        setrgb( dest, 0, 0, width, height, outpixels );  

        return dest;  

    private int[] getblenddata(int tr1, int tg1, int tb1, int[] input,int row, int col) {  

        int width = secondimage.getwidth();  

        int height = secondimage.getheight();  

        if(col >= width || row >= height) {  

            return new int[]{tr1, tg1, tb1};  

        int index = row * width + col;  

        // int ta = (input[index] >> 24) & 0xff;  

        int tr = (input[index] >> 16) & 0xff;  

        int tg = (input[index] >> 8) & 0xff;  

        int tb = input[index] & 0xff;  

        int[] rgb = new int[3];  

        if(mode == 1) {  

            rgb[0] = modeone(tr1, tr);  

            rgb[1] = modeone(tg1, tg);  

            rgb[2] = modeone(tb1, tb);  

        else if(mode == 2) {  

            rgb[0] = modetwo(tr1, tr);  

            rgb[1] = modetwo(tg1, tg);  

            rgb[2] = modetwo(tb1, tb);            

        else if(mode == 3) {  

            rgb[0] = modethree(tr1, tr);  

            rgb[1] = modethree(tg1, tg);  

            rgb[2] = modethree(tb1, tb);              

        else if(mode == 4) {  

            rgb[0] = modefour(tr1, tr);  

            rgb[1] = modefour(tg1, tg);  

            rgb[2] = modefour(tb1, tb);           

        else if(mode == 5) {  

            rgb[0] = modefive(tr1, tr);  

            rgb[1] = modefive(tg1, tg);  

            rgb[2] = modefive(tb1, tb);           

        return rgb;  

    private int modeone(int v1, int v2) {  

        return (v1 * v2) / 255;  

    private int modetwo(int v1, int v2) {  

        return v1 + v2 - v1 * v2 / 255;  

    private int modethree(int v1, int v2) {  

        return (v2 < 128) ? (2 * v1 * v2 / 255):(255 - 2 * (255 - v1) * (255 - v2) / 255);  

    private int modefour(double v1, double v2) {  

      if ( v1 > 127.5 ){  

          return (int)(v2 + (255.0 - v2) * ((v1 - 127.5) / 127.5) * (0.5 - math.abs(v2-127.5)/255.0));  

       }else{  

          return (int)(v2 - v2 * ((127.5 -  v1) / 127.5) * (0.5 - math.abs(v2-127.5)/255.0));  

       }  

    private int modefive(double v1, double v2) {  

          return (int)(v2 + (255.0 - v2) * ((v1 - 127.5) / 127.5));  

          return (int)(v2 * v1 / 127.5);  

    private void checkimages(bufferedimage src) {  

        if(secondimage == null || secondimage.getwidth() > width || secondimage.getheight() > height) {  

            throw new illegalargumentexception("the width, height of the input image must be great than blend image");