看明白整个流程之后,我们就可以看具体在做什么样的图像处理了。

x = i%img.width;
y = floor(i/img.width);

首先,取得像素再屏幕上的坐标x,y。因为i代表第几个像素,所以i除以图片宽度的余数就是这个像素在x轴的位置,而floor(i/img.width)得到的就是第几行,也就是y坐标。

然后,读取当前像素的颜色。

color cc = img.pixels[i];

让当前的画笔也采用一样的颜色。

stroke(cc);
fill(cc);

读取当前像素的亮度和饱和度。

float bri = brightness(img.pixels[i]);
float sat = saturation(img.pixels[i]);

下面就是具体的图像转换了。根据这个像素的亮度和饱和度,调用不同的函数画不同的直线或者圆点。这里用到了三个函数,draw_lines, draw_lines_dark和draw_circle。就是产生不同的效果。

if (bri > 245) 
  draw_lines(bri, x, y, amod - x/3, smod);
else if (bri < 10) 
  draw_lines_dark(bri, x, y, amod - x/3, smod);
else {
  strokeWeight(sat / 15);
  float a = (360.0 / 255.0) * sat + amod;
  float x2 = x + bri/4 * random(0.7,1) * smod * cos(radians(a));
  float y2 = y + bri/4 * random(0.7,1) * smod * sin(radians(a));
  line(x, y, x2, y2);
}

if ((sat > 200) && (bri > 150)) { // 
   draw_circle(sat, x, y, amod, smod);
}

我们来看看最常见的情况下是怎么画的,也就是else里面的部分。

strokeWeight(sat / 15);
float a = (360.0 / 255.0) * sat + amod;
float x2 = x + bri/4 * random(0.7,1) * smod * cos(radians(a));
float y2 = y + bri/4 * random(0.7,1) * smod * sin(radians(a));
line(x, y, x2, y2);

首先设置线条的粗细,饱和度越大,就越粗。线条的起点是当前的像素,终点是(x2,y2)。因为用了cos(a)和sin(a),所以线条和水平线的夹角就是a。a是由饱和度决定的,饱和度越大,夹角就越大,也就是说线条就越垂直。线条的长度由亮度决定,亮度越大,就越长。当然中间还加了了随机数。这样遇到大的色块画出来的线条不会一模一样,模拟人手绘的效果。其他情况下画的线条我们就不在这里一一分析了。

说实话我们对颜色这些理解不够深,为什么要这么处理,最后会达到什么样的效果,也不太了解。感觉就是要把像素转变成一段一段手绘的笔触。至于为什么不同的亮度和饱和度要不同的画法,我们尝试新建了一个有各种不同饱和度和亮度线条的图片,来看看不同情况下的效果是怎么样的。但还是不太明白为什么要这样。希望有高手给我们讲解一下。


现在,整个程序基本上清楚了。它做的就是逐一处理每个像素,根据像素的饱和度和亮度,用像素的颜色画不同的纹理。我们可以学到什么呢?如果我们要处理一个图像,可以用一样的流程。特别是我们也要用动画展现逐步处理的效果的时候,这是一个很好的方法。调整im递增的数字800,可以控制处理的进度。如果你有自己的像素处理算法,可以重用这个程序,替换中间像素处理的部分就可以了。

不知道这样的Processing程序分析是不是对大家有帮助呢?请给我们留言,谢谢!

© 2011, 视物 | 致知. All rights reserved.

Related Posts: