其实,Photoshop本质是一种数学软件,它把图片作为一个矩阵来处理,只不过隐藏了内部的数学原理。所以PS能做的,R语言在一定程度上也可以做。首先介绍一个最为简单的软件包,名字叫做“jpeg”,里面仅包含两个函数:一个是读取jpg,一个是写入jpg,而使用方法更是简单无比。magick在这里负责显示图片。
加载R包,读取原图片
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 154671 72x72 |
敲一下dim(orgpic),你会发现结果是:192 256 3, 也就是说,这是一个array,代表了192*256的一幅图片,每个像素点都由一个三维向量(R,G,B)来描述。我们可以这样访问一个像素点:orgpic[30,40,]结果并不是一般人在PS类软件常见的0到255之间的整数,而是0到1之间的浮点数。
下面来做一个负片效果
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 155612 72x72 |
是不是略酷?虽然没有什么实际的用途…… 接下来可以做出很多类似操作。比如,原图像的平方是什么?
做原图像的平方
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 153168 72x72 |
看起来似乎比原来的图像更深沉了。
原图像的平方根什么效果?
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 174798 72x72 |
你猜对了,图片会更加明亮清淡一些。难道这就是所谓日系小清新的奥秘? 事实上,常见的PS操作,本质都是一些数学运算。比如调整曲线就是建立一个映射,最简单的降噪方法就是加权平均。调整对比,亮度,饱和等等这些原理也都不复杂。
下面我们可以自己定义一个分段二次函数看看效果
自定义分段二次函数作用于原图
|
|
这个分段二次函数,以0.5为中心点。当x<0.5时,函数定义为low*x^2+(1-0.5*low)*x;当x>=0.5时,函数定义为-high*x^2+(1+1.5*high)*x-0.5*high,这里low与high都是我们需要指定的参数。这个函数有如下性质:f(0)=0,f(0.5)=0.5,f(1)=1;在[0,1]区间内单调增,是连续可导函数。
这里我们可以看到,其实这个分段二次函数就是一种“曲线”。
单调增的性质表明,如果原来这个像素点是R>G>B,加工后还是,不会改变图像原有的基本观感。而两个端点的限制则主要是为了保证取值在我们允许的范围内。f(0.5)=0.5这个限制比较特殊,它的意思就是说,尽可能的不大幅改变中间调附近的颜色。这跟前面的平方函数就不同。平方函数直接就把0.5变成0.25了,图像整体会变暗,要是更高次方,可能就接近于0,黑乎乎一片了。而此处的限制,基本上保证图像在“能看”的范围内。
其中的两个参数,low和high分别控制高光与阴影,取值范围都在[-2,2]内,即使你指定了范围之外的值也会自动恢复到边界。当这两个数值设置的比较大时,亮部会更亮,暗部会更暗,直观看就是对比度增强。反之,如果取得是负数,图片会变得比较“苍白”。如果是0的话,那么就退化为恒等的一次函数。
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 190355 72x72 |
下图看起来似乎是蓝天更鲜艳了,也许是对比/饱和度加强?
下面来做另一个例子,反转负冲
这里需要分别控制R,G,B三个通道。下面这个函数的基本原理就是,对G,B通道,反相(例如1-orgpic[,,3])后正片叠底(temp[,,3]*temp[,,3])再与原片混合(b*temp[,,3]+(1-b)*orgpic[,,3]);对于R通道,不反相而直接颜色加深(2-1/temp[,,1])。 注:不难证明,2-1/temp[,,1] <= temp[,,1],利用的是均值不等式。
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 151641 72x72 |
效果是不是很神奇?
RGB当然大家都知道。但是,我们一般谈论颜色,很少会说“某某分量占多少”,更多的时候我们的表达方式可能是:比较深,比较浅,等等。那么这就与HSL或HSV色彩模式相关。这里H是Hue,色相。S是Saturation,饱和度。L是明度,V是色调。基础知识可以参考网络资源。RGB色彩模式与HSL,HSV色彩模式之间互相转换的关系此处从略。
再来一个很灵活的转换为黑白的函数
|
|
这个函数最终返回一个加权平均值,权重可以自定。比如RGBBW(orgpic,1,0,0)就相当于给照片加了个红色滤镜。我们来随便做个例子:
|
|
1 2 |
## format width height colorspace matte filesize density ## 1 JPEG 1024 768 sRGB FALSE 142308 72x72 |
在人像照片处理中,假设人物穿的是蓝色的衣服,那么,如果直接加红色滤镜,衣服就会看起来像是黑的。能否让人脸的红色表现得更白,同时衣服也不要太黑呢? 用这个就可以:RGBBW(orgpic,2,1,2),这样的话绿色通道会得到抑制,而红色与蓝色都会变强,相当于一个近似的绿色截止滤镜,可以看到草地就变黑了。
众所周知,宾得相机的色彩风格很有特点。虽然我们没有办法知道很细节的东西,不过,我们可以做一个简单粗暴的假设:宾得机身直出jpg不同风格的算法只是对RGB三个通道做分别的计算,那么实际是很容易做逆向工程的。比如说,首先用自然模式拍一张照片,然后利用宾得的机身处理功能,分别生成鲜明,人像,风景,风雅,明亮等风格的照片。接下来,我们把这几张图片读入R当中,以自然模式的数据作为x,以其他风格的数据作为y,做一个模型拟合。因为操作步骤较多,因此这里不再赘述。