Retro-Histo: making an image fit your histogram!

So David over at Ironic Sans recently rolled out a neat trick: starting with a histogram and working backwards, as it were, to create an image that fit it.

Wonderful idea. And he does it; but he doesn’t take it far enough, dammit. His output works—its histogram, when viewed, is indeed the NYC skyline—but the image itself is just a spiffed-up greyscale gradient.

What about being able to create an arbitrary image—or, more to the point, being able to modify an existing image—so that you come away with something that looks like something and fits your target histogram?

Sure! I’ve been working out the idea for the last few days (not that it’s a days-long problem, difficulty-wise, but I’ve been coming at it slowly here and there), and I’ve got a perl script that will take a histogram and a source image and spit out a new image that is undeniably the “original”, but modified in its brightness levels to make it fit the target histogram.

Example time! Here’s a source image: a picture I took a while back of a firehand in Portland.

original firehand image

And here is that image’s original histogram:

firehand histogram

Now, that’s a fine histogram and all, but what I really want is an image that has this histogram—the skyline of Miami. (Why Miami? I’ll get there in a minute, don’t worry.)

miami skyline histogram

So, okay: I run this through my histogramization script (basically some straightforward Perl using Image::Magick for image-reading and -writing routines), and what I get out is this:

retrohisto'd firehand

Hey, it’s the original image, but kind more dark and grainy. And with a histogram that looks like the Miami skyline.

Hell yes. Of course, you’ll have to check it in photoshop or whatever to actually see the proof, but if you’re reading this you’re probably the sort who would do that. Go crazy!

But wait! David was originally playing with the idea of an image that was its own histogram. He got a nice approximation with a smooth, abstract curve and left it at that. But I’ve got the tools now to do better. So:Here’s a picture of the Miami skyline snagged (woo, creative commons!) from flickr, made greyscale, resized and cropped down to fit our 256*100 histogram image size.

miami original

Here’s that image’s histogram, for reference:

original histogram

Here’s that Miami skyline-histogram from above again: I made it by painting the city black and the sky white in Photoshop.

miami histogram

And, shucked through the Perl script, here’s what came out the other side:

miami skyline with a self-similar histogram

Again, you’ll have to check the histogram in your viewer of choice to be sure, but that right there is a picture of the Miami skyline with a self-similar histogram. Hot damn.

So! It can be done. There are a lot of wrinkles, of course—for one, this method produces stranger results for very eccentric histograms; for another, it’s only greyscale, color being a bit more complicated of an issue (though not necessarily fundamentally so, depending on how you handle it). The way one histogram viewer or another displays a given image will also affect the quality of the histogram-viewing experience, so what looks good to in the histograms this script itself generates won’t necessarily look great in photoshop or the GIMP or whatever—the shape should be right, but it might be a bit jaggy or have the wrong aspect ratio. Some of that is probably solvable, but I’m not going to try at this point.More images, histograms, and the perl itself can be found in the working directory.

Suggestions, comments, questions &c are welcome, as are custom histograms if you’d like me to see what they do to images. If you want to send me a histogram, it needs to fit these parameters:
– 256*100 pixels
– black and white, black on the bottom
– at least one black pixel for each level (this is fragile alpha software)

Nerd fun is the best goddam fun there is.

Late Update! Here’s what happens if I give this a shot with the original NYC skyline shot that David used for his experiment.

Original (cropped down to histo-size to improve the self-similarity results):

Histogram of original:

Target NYC histogram

And the output, with target histogram:

Cool! It’s kind of ugly, though; I mentioned above that one caveat of this technique is that more eccentric histograms will produce odder results, and this is a decent example. The original image has a great big spike of dark tones (the skyline silhouette is a wash of black (or something close to black, really) and the target histogram has a somewhat well-distributed range of tones, which means that by mathematical necessity that skyline will have several varied tones filling out the even dark space of the original.

It’s also jpeg artifact theater, hoo boy.

So, lesson learned: a good range of tones in the original will improve output in the final image, generally speaking. Compare with the self-similar Miami output above—that photo had a pretty rich palette to begin with, so it came out looking more over-processed than ugly.

Author: Josh Millard

I manage and help moderate the community website MetaFilter, where I go by "cortex"; in my spare time I get up to all sorts of creative nerdery on the internet and in Portland, Oregon.

42 thoughts on “Retro-Histo: making an image fit your histogram!”

  1. A couple more things:

    – David has made a new post over at Ironic Sans discussing this. I’m not sure “Josh is a genius.” isn’t overstating it, but I’m not gonna complain. Thank, David!

    A quick summary on Flickr; I think that there are more people who watch my flickr stream than there are people who read this blog. Heh.

  2. Histogram fitting links:

    – Check out page 76 or so of Tony Jebara’s 1995 thesis, 3D Pose Estimation and Normalization for Face Recognition, for some hot histogram-fitting equations.

    – This paper, Perfectly Flat Histogram Equalization, sounds pretty fascinating, but the Internet doesn’t seem to have a copy. Li’l help?

    – And, bingo? A fast, non-iterative and exact histogram matching algorithm, Morovic, Shaw, Sun. The abstract:

    A fast, non-iterative algorithm is presented for transforming an image so as to give it exactly a given target histogram. This is achieved for any original and target histogram combinations and examples of results are given in addition to a comparison with applying the earth mover’s distance (EMD) method to this task.

    Again, I don’t have access to the actual paper, but it sounds like that might be exactly what’s going on here.

    – Getting a bit more general: a paper on histogram enhancement for xray visibility, a coursework page discussing histogram matching, and some completely badass wonkery on secure image steganography vs. histogram comparison.

  3. Hey thanks for the props there Josh, but I think yours beats mine hands down. I saw the title of today’s article on Ironic Sans and was like “he’s talking about me!” but when I saw yours, I was like “daaaaamn”. Great work.

  4. Boston? Seriously? I’m so firing my fact checker. Thanks for the heads up, gbritton.

    Nick: thanks. It’s worth noting that I did what you did as a first step—I was producing gradients as a sanity check before I worked out the alter-in-place routine to keep the photo looking right.

  5. Both perl scripts in the working directory are returning

    { Error 404 }
    Page Not Found

    when viewed or downloaded.

  6. Yeah, I’ve got something kind of fucked in my .htaccess config, I think. The __code* items in the directory are copies of the respective scripts, for easy perusin’.

  7. Huh. Interesting notion from greatbiggary over on JWZ’s livejournal post: use same-intensity, different-hue pixels to paint a visible picture that would completely lack histogram variance: b&w intensity histogram would just be a single spike, with all the visual information spread out across the separate RGB (or CMYK or whatever you prefer) channels.


  8. And as toy steganography goes, that could be fun and slightly subtle: encode the true information in your image in the hue-varying pixels of a given intensity x, and fill in the rest of the picture with a plausible range of other intensities. Isolating that one level would give you the reveal, but otherwise the information wouldn’t be obvious.

    Making that work from an arbitrary starting point could be interesting.

  9. Hi,

    as written above, it is not possible to download the perlscript :-(
    Could you send them by e-mail?



  10. Hmm your code is returning an error (and I’m no good at Perl so I have no idea what it means). is telling me:

    ‘Use of uninitialized value $lev in numeric gt (>) at ./ line 33.’

    And a similar error in rehist. Any ideas how I can fix it?

  11. Dude, AWESOME CONCEPT! Is there any way you could make an in-depth tutorial of how we could do this ourselves (so that the average nerd can comprehend this)? Thanks, it would be a lot of help!

Leave a Reply

Your email address will not be published. Required fields are marked *