Sat, 29 Jun 2013

8-bit Paleontology

— SjG @ 9:28 am

My maternal grandfather was a paleontologist of some note, yet it was no small surprise that L— broached the subject upon the occasion of my recent visit.

L—, a colleague from former heady days in the dot-com era and now a Web 2.0 millionaire in her own right, has used some of her new-found wealth to indulge in her original academic interest, the study of 8-bit Paleontology. In what was a rare honor, L— permitted me to view her private collection.

This collection, housed in the Library of her estate, is a well-lit room, dominated by the mounted skeleton of a contemporary Homocongregus namco. Surrounding this modern skeleton, she has a splendid display of fossils of some of the great precursor species, including Homocongregus dotovorus and Homocongregus arcada.

Today, however, she was pleased to show her latest acquisition. Opening a velvet-lined box, she revealed to me what is arguably the world’s best example of the immediate ancestor to Homocongregus namco: a gorgeous fossil of Homocongregus Phasmaprosecutus preserved in stone for all eternity in the very act of consuming a row of equally well preserved Pacdotus powerupi. It is truly a stunning piece, worthy of any great museum, and incontrovertible physical record of the evolutionary path of the species.

She kindly allowed me to photograph this specimen, thus I am able to present this image to share with the world, and contribute to the greater good of science:
Homocongregus Phasmaprosecutus

Thu, 13 Jun 2013

Failures in Image Processing

— SjG @ 10:00 am

I have a tendency to have ideas that seem simple until I attempt the implementation. Then, all of the complexities jump out at me, and I give up and move on to the next idea. Once in a while, however, I’ll go so far as to prototype something or play around before abandoning ship. This here’s an example of the latter.

The Big Idea hit when I looking up a recruiter who had emailed me out of the blue. He shared the name of someone I went to school with, and I wanted to see if it was, in fact, the same person. In this case, a quick Google Images search on the name and job title indicated that it was not the same person, so I didn’t have to fake remembered camaraderie.

While searching, though, I thought it interesting the variety of faces that showed up for that name. Hm. Wouldn’t it be cool, thought I, if I could enter a name into my simple little web service, and it would spit back the “average face” of the first ten or twenty matching images from Google? After writing a few pages of code, scrapping them, switching languages and libraries, writing a few pages of code, scrapping them, switching languages and libraries again, writing a few more pages of code, I then ditched the whole enterprise.

In the process, I did use some morphing software to test the underlying concept. Here is the average face for my picture mixed in with the first seven Samuel Goldstein images that were clear enough, angled correctly, and of sufficient size to work with:

For what it’s worth, here are a few of the software challenges to automating something like this:

  • Extracting the portrait from the background. This isn’t critical, but will simplify subsequent tasks.
  • Scaling the heads to be the same size.
  • Aligning the images more or less. I was going to use the eyes as the critical alignment points; if they couldn’t be within a certain degree of accuracy, this would suggest incompatible images (e.g., one a 3/4 portrait, the other straight on).
  • Detail extraction. This is finding key points that match on each image. Experimentally, when combining images by hand, it may be sufficient to match:
    • 4 points for each eye, marking the boundaries
    • 3 points marking the extremities of the nostrils and bottom center of septum
    • 5 points marking ear boundaries: top point where they connect to the head, top of extension, center, bottom of lobe, point where lobe connects to head
    • 5 points marking top outer edges, outer angle, and center of mandible
    • 5 points mapping hairline
    • 5 points mapping top of hair
    • 7 points along the superciliary ridge
  • Interpolate these points on each pair of images, then on each interpolated pair, and so on until a single final interpolation is achieved
  • Render the image to a useful format
  • View image, and laugh (or cry)

A few other lessons learned:

The typical picture returned by Google images search for a name will be a thumbnail portrait. It’ll be small — maybe 150 by 300 pixels or so. While that’s enough data to recognize a face, it’s not a lot of data when you start manipulating it. Ideally, for nicer results, source images should be a minimum of two or three times that size.

Google gives back different results depending on whether you surround the name with quotes or not; it also makes a big difference if you pass size or color parameters. The “face” search is a good parameter to use, although when searching for “Samuel Goldstein” face search inexplicably had lots of Hitlers and Osama Bin Ladens. The “safe search” feature is also strongly recommended for this project — again, when searching for “Samuel Goldstein” without safe search yielded a variety of unexpected vaginas.

Bing image search gives different results (not too surprisingly), but they also have some anomalies. My search brought back many of the same pictures, along with an inexplicable collection of calabashes and LP labels.

If any ambitious programmers go ahead and implement this, please send me the link when you’re done!

Tue, 8 Jan 2013

iPhone 5 Wallpapers

— SjG @ 8:48 pm

I needed to change my iPhone lock screen image. With no further aesthetic commentary, here are three Retina-ready, iPhone 5-sized images you can use. They’ll also work on non-Retina or lower-resolution iPhone screens, you’ll just have to select a portion of the image (or scale it down). If you don’t know how to install Wallpaper images on your iPhone, the first page I Googled gave a pretty good step-by-step.

(Click on the thumbnail to see the full-size versions; right-click to download them)


Mon, 17 Sep 2012

Cambot’s First Campaign

— SjG @ 10:30 pm

Cambot is a project based on the Teensy development board. Cambot creates an infra-red “trip beam” that triggers a pre-focused Nikon D90.

To create an IR beam and detector that work in direct sunlight, Cambot pulses the IR source every 10ms, and compares detected signal between the on and off states. If it’s greater than a threshold, it’s considered a valid signal. The sensor also has a vary small aperture which is additionally shielded with a filter to reduce the ambient IR. When powered on, Cambot goes into calibration mode, which lights up an LED when it detects a good signal. This is critical for lining up the IR sources and detector — once a good signal is sustained for 3 seconds, Cambot goes into “armed” mode. When armed, breaking the beam will turn off the IR source, half-press the camera’s shutter for 10ms so the camera can compute exposure, and then fires off a burst of pictures before re-arming itself.

While there’s nothing in Cambot that couldn’t have been implemented with, say, 555 timers, counters, and gates, having the ability to drive digital logic with C code makes things much more flexible. When trying to determine the proper threshold values for arming and triggering, the ability to output hex data over the USB connector to a host computer was invaluable.

Here’s Cambot’s first run, when the trip-beam was positioned over a tempting milkweed blossom in the back yard.

If there’s any interest, I’ll post a circuit diagram and source code.

Sun, 25 Sep 2011

Photoshop scripting with Javascript

— SjG @ 6:41 pm

I’ve played with the Javascript interface to Photoshop for a couple of years. Conceptually, it’s great — a simple, powerful, interpreted language like Javascript, with an API to interface to one of the best image-processing packages available. In practice, it’s not as good as it is in concept, but it’s still pretty good. The API doesn’t include all of Photoshop’s functionality directly, and there are a lot of things you need to execute as fairly obscure event actions. These event actions aren’t documented, but can be determined by activating a plug-in which logs everything that you do using the Photoshop GUI — you can then read through these logs, and copy the actions you need.

Still, there are some real advantages to using this Javascript interface, as opposed to something designed for the purpose like, say, Processing. You can use the Photoshop UI for controlling inputs to your script (set foreground colors, select portions of the image, select specific layers, etc.), and output your manipulations directly into Photoshop layers.

I’ll be posting here shortly a library I’ve created for easily building dialog panels for setting script options. I find that most manipulations I want to do have a set of variables, and I’d rather not tweak the code each time I want to change them.

This library was originally written under Photoshop 10 (aka CS3). Under version 11 (aka CS4), it was less stable. Sometimes it would crash out at odd places complaining that I was referencing properties of undefined objects. Because there have been memory leaks and other issues with the Javascript interpreter, these seemingly random failures were annoying but not too surprising. When it came to version 12 (aka CS5), I was rarely able to run my scripts at all. What made it frustrating was the apparent randomness of the crashes. I could print a variable to the console, and the very next line would crash out with an “undefined object” error when referencing that variable.
To make a long story short, I was able to track down the issue. It turns out that in iterations, declaring variables matters. That is to say:
for (i in someCollection)

will cause random crashes, but
for (var i in someCollection)

runs beautifully. Now, I “knew” that the var keyword is optional and used for specifying scope, but I never had any idea that there could be an issue within the scope of a simple loop. Obviously, Javascript didn’t know that I intended i to be a variable on each iteration — perhaps it thinks I meant for i to be a 1957 Chevy Belair on some iterations.

In any case, having cracked the code as it were, I have proceeded to enhance and add to my library. After a little more testing, I’ll be posting it here or on GitHub.