java 影象特效之影象混合(溶圖)
阿新 • • 發佈:2019-02-03
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;
}
以上