Julian Wolkenstein’s Symmetrical Portraits project just made the rounds. I could’ve sworn I saw it on Brain Pickings, but I can’t find it now. Whatever, no matter.

It’s a weird-looking project: take a bunch of head-shots, cut them down the middle, and mirror each half, so one asymmetrical face becomes two symmetrical faces. It’s startling how much some of the pairs differ from each other. There’s a hypothesis that symmetry makes the people more attractive, but some of them are pretty uncanny:

So what’s a Processing goof-off going to do? Tear them apart, and put them back together. I don’t know whether the asymmetrical version is right, or whether it’s backwards, but I don’t think it really matters, unless you know the person in the photo. Click ‘em for big versions.












Here’s the code I used to de-symmetry them. Note the mouse controls: I had to tweak some of them, especially that second one of the blond short-haired guy.

 1 // 36_Wolkenstein_12.jpg
 2 String[] files = new String[] {
 3   "01_v2", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"
 4 };
 5 PImage[] origImgs;
 6 
 7 int imgIndex = 0;
 8 
 9 void setup() {
10   PImage img = load(files[0]);
11   size(ceil(img.width * 1.5), img.height);
12 
13   origImgs = new PImage[files.length];
14 
15   for (int i = 0; i < files.length; i++) {
16     origImgs[i] = load(files[i]);
17   }
18 }
19 
20 void draw() {
21   PImage orig = origImgs[imgIndex];
22   image(orig, 0, 0);
23 
24   int placeLine = round(orig.width * 1.25);
25   int cropLine = round(orig.width * 0.75);
26 
27   int placeOffset = round(map(mouseX, 0, width, -20, 20));
28   int cropOffset = round(map(mouseY, 0, height, -20, 20));
29 
30   image(
31     orig.get(0, 0, round(orig.width * 0.5), orig.height),
32     orig.width, 0);
33 
34   image(
35     orig.get(
36       cropLine + cropOffset,
37       0, round(orig.width * 0.25), orig.height
38     ),
39     placeLine + placeOffset, 0);
40 }
41 
42 void keyPressed() {
43   if (key == ENTER) {
44     save("fixed_" + files[imgIndex] + ".jpg");
45   }
46   imgIndex = (imgIndex + 1) % files.length;
47 }
48 
49 PImage load(String chunk) {
50   return loadImage("36_Wolkenstein_" + chunk + ".jpg");
51 }