In this episode of Imgbusters we're going to look at how to do this effect:
If we look closely we notice that pixels are "smeared" horizontally. We can also see that the direction is probably left to right rather than right to left. This effect seems to pick a color and then repeat the same color for a few pixels to the right. Let's try this:
from PIL import Image import math import sys im = Image.open(sys.argv).convert("RGB") w, h = im.size
y = 0 x = 0 while y < h: x = 0 p = im.getpixel((0,y)) while x < w: p_ = im.getpixel((x,y)) i = 0 while x < w and i < 8: output.putpixel((x,y), p_) i += 1 x += 1 y += 1
Well... that didn't really work. What the effect we want is actually doing is group pixels of the same colour together and then colour them exactly the same way. In essence, to get this effect we need to run from left to right remembering the colour of a reference pixel then check if the next pixel has about the same colour, if yes, we replace that pixel with the colour from the earlier pixel, if not we keep the pixel and then repeat. Let's try it:
def pos(rgb): return int((math.sqrt(rgb*rgb + rgb*rgb + rgb*rgb)/442.0)*255.0) x = 0 y = 0 d = 64 while y < h: x = 0 p = im.getpixel((0,y)) while x < w: p_ = im.getpixel((x,y)) if abs(pos(p) - pos(p_)) > d: p = p_ output.putpixel((x,y), p) x += 1 y += 1
What's the mysterious pos function? Simple. An RGB value can be considered a point in a 3D space (x,y,z) and the distance from such a point (x,y,z) to (0,0,0) is sqrt $ x*x + y*y + z*z. The maximum distance is about 442. /442.0*255.0 scales the distance to 0..255. To prevent extending too far to the right we need to slowly fade out. We can do this by introducing a counter to count how many pixels we've replaced or we constantly decrease d. d defines how much a pixel can differ in colour from the reference pixel. You can experiment by using different values for d.
x = 0 y = 0 d = 64 d_ = d while y < h: x = 0 p = im.getpixel((0,y)) while x < w: p_ = im.getpixel((x,y)) if abs(pos(p) - pos(p_)) > d_: p = p_ d_ = d else: d_ /= 1.1 output.putpixel((x,y), p) x += 1 y += 1