1. 程式人生 > >java 影象特效之影象混合(溶圖)

java 影象特效之影象混合(溶圖)

photoshop中的圖層混合功能大家一定很熟悉。此功能可以根據指定模式,將2個圖層進行混合,實現不同色彩風格的影象效果,也就是我們通常所說的溶圖。 實現影象混合的原理其實很簡單,就是將兩張影象的重疊,分別取相同位置的兩個畫素點上的RGB值,通過特定的公式計算出新的RGB值,這樣,不公的公式,將產生不同的色彩效果。

假設a[i]代表第一個畫素點的RGB值中的一個值,相對應於b[i](代表另一個畫素點的RGB值中的一個值),變暗效果的公式是a[i] < b[i] ? a[i] : b[i],這個公式很簡單,就是比較2個值得大小。

除此之外,還有其他效果的演算法可以供我們使用:

排除

a[i] + b[i] - 2 * a[i] * b[i] / 255

差值

Math.abs(a[i] - b[i])

實色混合

(b[i] < 128 ?
    (b[i] == 0 ? 2 * b[i] : Math.max(0, (255 - ((255 - a[i]) << 8 ) / (2 * b[i])))) 
:
    ((2 * (b[i] - 128)) == 255 ? (2 * (b[i] - 128)) : Math.min(255, ((a[i] << 8 ) / (255 - (2 * (b[i] - 128)) )))))
    < 128 ? 
        0 : 255;

點光

Math.max(0, Math.max(2 * b[i] - 255, Math.min(b[i], 2 * a[i])))

線性光

Math.min(255, Math.max(0, (b[i] + 2 * a[i]) - 1))

亮光

b[i] < 128 ?
    (b[i] == 0 ? 2 * b[i] : Math.max(0, (255 - ((255 - a[i]) << 8 ) / (2 * b[i])))) 
:
    ((2 * (b[i] - 128)) == 255 ? (2 * (b[i] - 128)) : Math.min(255, ((a[i] << 8 ) / (255 - (2 * (b[i] - 128)) ))))

強光

(a[i] < 128) ? (2 * a[i] * b[i] / 255) : (255 - 2 * (255 - a[i]) * (255 - b[i]) / 255)

柔光

b[i] < 128 ? 
    (2 * (( a[i] >> 1) + 64)) * (b[i] / 255) 
: 
(255 - ( 2 * (255 - ( (a[i] >> 1) + 64 ) ) * ( 255 - b[i] ) / 255 ))

疊加

(b[i] < 128) ? (2 * a[i] * b[i] / 255) : (255 - 2 * (255 - a[i]) * (255 - b[i]) / 255)

線性減淡

Math.min(255, (a[i] + b[i]))

顏色減淡

(b[i] == 255) ? b[i] : Math.min(255, ((a[i] << 8 ) / (255 - b[i])))

濾色

255 - (((255 - a[i]) * (255 - b[i])) >> 8)

變亮

(b[i] > a[i]) ? b[i] : a[i]

線性加深

(a[i] + b[i] < 255) ? 0 : (a[i] + b[i] - 255)

顏色加深

b[i] == 0 ? b[i] : Math.max(0, Math.max(0, (255 - ((255 - a[i]) << 8 ) / b[i])))

正片疊底

a[i] * b[i] / 255
參考:影象混合(溶圖)演算法的javascript實現   

對於圖片


給出上述一些效果的實現:

/*
	 * a[i] * b[i] / 255
	 * 正片疊底
	 */
	public Image filter() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	

                int fr = this.img.red[x + y * this.img.w]*jb.red[x + y * this.img.w]/255;  
                int fg = this.img.green[x + y * this.img.w]*jb.green[x + y * this.img.w]/255;  
                int fb = this.img.blue[x + y * this.img.w]*jb.blue[x + y * this.img.w]/255;  
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

/*
	 * (a[i] + b[i] < 255) ? 0 : (a[i] + b[i] - 255)
	 * 線性加深
	 */
	public Image linearDeep() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	
                int fr = (this.img.red[x + y * this.img.w]+jb.red[x + y * this.img.w])<255?0:(this.img.red[x + y * this.img.w]+jb.red[x + y * this.img.w]-255);  
                int fg = (this.img.green[x + y * this.img.w]+jb.green[x + y * this.img.w])<255?0:(this.img.green[x + y * this.img.w]+jb.green[x + y * this.img.w]-255);  
                int fb = (this.img.blue[x + y * this.img.w]+jb.blue[x + y * this.img.w])<255?0:(this.img.blue[x + y * this.img.w]+jb.blue[x + y * this.img.w]-255);  
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

/*
	 * (b[i] > a[i]) ? b[i] : a[i]
	 * 變亮
	 */
	public Image max() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	
                int fr = this.img.red[x + y * this.img.w] > jb.red[x + y * this.img.w]?this.img.red[x + y * this.img.w]:jb.red[x + y * this.img.w];
                int fg = this.img.green[x + y * this.img.w] > jb.green[x + y * this.img.w]?this.img.green[x + y * this.img.w]:jb.green[x + y * this.img.w];
                int fb = this.img.blue[x + y * this.img.w] > jb.blue[x + y * this.img.w]?this.img.blue[x + y * this.img.w]:jb.blue[x + y * this.img.w];
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

/*
	 * 255 - (((255 - a[i]) * (255 - b[i])) >> 8)
	 * 濾色
	 */
	public Image ColorFilter() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	
                int fr = 255-((255-this.img.red[x + y * this.img.w])*(255-jb.red[x + y * this.img.w])>>8);
                int fg = 255-((255-this.img.green[x + y * this.img.w])*(255-jb.green[x + y * this.img.w])>>8);
                int fb = 255-((255-this.img.blue[x + y * this.img.w])*(255-jb.blue[x + y * this.img.w])>>8);
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

/*
	 * Math.min(255, (a[i] + b[i]))
	 * 線性減淡
	 */
	public Image LinearSub() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	
                int fr = 255>(this.img.red[x + y * this.img.w]+jb.red[x + y * this.img.w])?(this.img.red[x + y * this.img.w]+jb.red[x + y * this.img.w]):255;
                int fg = 255>(this.img.green[x + y * this.img.w]+jb.green[x + y * this.img.w])?(this.img.green[x + y * this.img.w]+jb.green[x + y * this.img.w]):255;
                int fb = 255>(this.img.blue[x + y * this.img.w]+jb.blue[x + y * this.img.w])?(this.img.blue[x + y * this.img.w]+jb.blue[x + y * this.img.w]):255;
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

/*
	 * a[i] + b[i] - 2 * a[i] * b[i] / 255
	 * 排除
	 */
	public Image Exclude() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	
                int fr = this.img.red[x + y * this.img.w]+jb.red[x + y * this.img.w]-2*this.img.red[x + y * this.img.w]*jb.red[x + y * this.img.w]/255;
                int fg = this.img.green[x + y * this.img.w]+jb.green[x + y * this.img.w]-2*this.img.green[x + y * this.img.w]*jb.green[x + y * this.img.w]/255;
                int fb = this.img.blue[x + y * this.img.w]+jb.blue[x + y * this.img.w]-2*this.img.blue[x + y * this.img.w]*jb.blue[x + y * this.img.w]/255;
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

/*
	 * Math.abs(a[i] - b[i])
	 * 差值
	 */
	public Image sub() {
		
		if(this.img.gray)
			return this.img;  // Grayscale images can not be processed
		
		for (int y = 0; y < this.img.h; y++) {
            for (int x = 0; x < this.img.w; x++) {
            	
                int fr = Math.abs(this.img.red[x + y * this.img.w]-jb.red[x + y * this.img.w]);
                int fg = Math.abs(this.img.green[x + y * this.img.w]-jb.green[x + y * this.img.w]);
                int fb = Math.abs(this.img.blue[x + y * this.img.w]-jb.blue[x + y * this.img.w]);
                  
                this.img.data[x + y * this.img.w] = (255 << 24) | (math.st(fr) << 16) | (math.st(fg) << 8) | math.st(fb);              
            }
        }
		
		return this.img;
	}

以上