基于Java的图片混合模式的实现

图像处理算法自己实现也不是那么难,偶然在某网站上看到photoshop中相关滤镜的简单算法,就是些对像素的加加减减(http:

//bbs.cn365design.com/viewthread.php?tid=8483),下面是参考文章,后来我将参照原文用java实现这些算法,并实现下面的图片渲染效果

几种最基本的图层混合模式:7 U8 ]) I. N5

K& P

7 I8 v# M+

^1 F# |* b. P+ e

层A和层B混合,层A在下,层B在上,a, b对应其某通道的灰度值,混合层对应通道的灰度值用公式f(a,b)表示。现在求f(a,

b)=?。(用f(a,b)表示图层混合结果,在后面还会用这个形式表示)4 a0 H5 c2 d; B8 i!

T

混合模式中有的是可交换,有的是不可交换的,(“可交换”意味着交换层A和层B,结果一样;否则可能不同),这里讨论的都是可交换的。

0 W’ m7 V3

S2 U6 {

图片设为位深度为8×3(RG=24,即灰度区间为(a和b取值范围)[0,255]。(即二进制的00000000~11111111)

在ps的所有处理结果受到灰度区间限制,因此,如果算法所得的第一结果超出灰度区间,将被灰度区间的边缘截断,即结果小于0时结果=0,结果大于255时

结果=255。以下算法表达中为了形式简单明了,对超出灰度区间的结果不作声明。

1.线性减淡:a+b              (可见合成结果变亮)6 k8 H/ J. X. `+ x

2.线性加深:a+b-255          (合成效果为变暗)

3.正片叠底:ab/255           (变暗了)

4.滤色(屏幕):255-(255-a)(255-b)/255   (即a和b反相图作正片叠底的结果再取反相)

可化简为:a+b-ab/255   (变亮了)

5.变亮:max(a,b)/

Z, U5 P4 V* I0 j6 I* L  T” z

6.变暗:min(a,b)              (效果显而易见)

7.排除:a+b-ab/128               (原图中大于128被变暗,小于128则被变亮)8 P* [* H+ q% M’ |9

z7 F” r( [

8.差值:|a-b|

从上面的算法中可以了解到的性质,

1).与黑色RGB(0,0,0)正片叠底,结果为黑色,与白色RGB(255,255,255)正片叠底,结果不变。

2).与黑色滤色,结果不变。与白色滤色,结果为白色。

3).最后我再解释一下滤色模式,滤色即加色算法,例如红+绿=黄,绿+蓝=青,(蓝+红=是不是叫紫?)

在有的英文版中叫做screen(屏幕),这是为何,一句话概括之,它相当于使用两台投影仪同时打在同一个屏幕上的结果,(这也是加色的实际物理意义)。

显而易见,结果必然会变得更亮。$

d$ E8 m. J- }, P

先强调一下,当你调节了透明度和填充以后,我们看到的叫做混合结果,或者输出结果,(我们可以看到ps

cs中将其称为“合并图层”)这个结果的RGB数据和图层中的数不是同一个。当然你可以把结果输出在一个新的图层里。# G$ O9 Y1 ~” @6 g6

r+ O” b* G2 f

透明度,主要是应用在图层方面的概念,表示的是两个图层之间的比例关系,它的计算是在图层之间进行整体控制和计算,其作用域位于最外围,涵盖了图层之间的

所有本身固有信息包括图层样式等等。

9 t6 o: N9

W1 [3 D4 X) J# x’ ~+ y

而图层样式是施加在图层方面的额外添加和控制,因此它不会受填充影响,只能由控制图层层次的透明度来控制。) Z8 V( Y4 X! x, E7

[5 y2 N- i# L! @

它们的顺序是,首先有图层中的数据a,b计算出混合结果,然后使用填充度给出中间输出结果,然后应用图层样式,最后使用透明度给出最终输出结果。即按照下

面的次序:图层混合->填充->图层样式->透明度

) X7 R7 t5

h) H) g% P

因此,透明度和填充,两者相当于调度,填充属于微观象素调度,透明度属于宏观图层调度,透明度的调度级别比填充高一个层次。3 w” N9 w- L: r# /

W

9 a4 X/ a”

b4 R3 h/ E3 x  F

如果是多个图层呢,每个图层都有自己的透明度,例如三个图层,

结果是k1*c+(1-k1)*【(k2* b+(1-k2)*a 】2 f# |; |’ r0 d! h

因此输出结果是层层向上计算的。

看过之后,觉得实现起来似乎不难,于是就尝试这下面的代码,结果发现还真能有点效果,最后凑了这一堆。当然需要说明的是这样的滤镜效果还是很一般的,与photoshop那样的效果还是有很大的区别的

代码片段:

	class GreenFilter extends java.awt.image.RGBImageFilter {
		public GreenFilter() {
			canFilterIndexColorModel = true;
		}

		public int filterRGB(int x, int y, int rgb) {
			return ((rgb & 0xff00ff00) | ((rgb & 0xffff00) >> 16) | ((rgb & 0x00) << 16));
		}
	}

	class RedBlueSwapFilter extends java.awt.image.RGBImageFilter {
		public RedBlueSwapFilter() {
			canFilterIndexColorModel = true;
		}

		public int filterRGB(int x, int y, int rgb) {
			return ((rgb & 0xff00ff00) | ((rgb & 0xff0000) >> 16) | ((rgb & 0xff) << 16));
		}
	}

	class YellowInvertFilter extends java.awt.image.RGBImageFilter {
		public YellowInvertFilter() {
			canFilterIndexColorModel = true;
		}

		public int filterRGB(int x, int y, int rgb) {
			return ((rgb & 0xffff00) | ((rgb & 0x00) >> 16) | ((rgb & 0xffff) << 16));
		}
	}

运行如下:


九 + 2 =