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.

And here is that image’s original 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.)

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:

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!

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

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

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

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.
So wait, that’s called a “firehand”?
So, this firehand, it vibrates?
This is easily the coolest thing you’ve done in years.
Blues name generator excepted.
Here, by the way, is the Metafilter thread about David’s original post, with intense dorkery inside, including this excellent volley wherein PuGZ presents a proof-of-concept for per-channel color histogram-fitting hijinks. The initial results weren’t particularly smooth, but the process was clearly there.
And I missed this at first, but Nick Fisher built (before I ever got my experiment working) this histogram toy that creates a greyscale gradient based on an input histogram—see more explanation in his blog post about it.
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.
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.
‘Firehand’ would be a good nickname for a blues musician.
Histogrammatic ‘Firehand’ Nixon.
I have to say, ‘histogramas esteganográficos autorreferentes’ has a nice ring to it.
Oh my crappin’ pants, JWZ noticed this. Hiya, Jamie.
more like Adolf Millard
more like twentynein amirite
This is pretty cool, but that photo isn’t the Miami skyline, it’s the
Boston skyline.
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.
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.
Both perl scripts in the working directory are returning
{ Error 404 }
Page Not Found
when viewed or downloaded.
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’.
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.
Hmm.
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.
Very creatve, i’d say. The histogram looks good, and the image is not bad as well
I demand that this technique be named “steganobargraphy”.
Pingback: Histograma subliminar at 100nexos
Hi,
as written above, it is not possible to download the perlscript :-(
Could you send them by e-mail?
Thanks
schmartin
To be clear, you can grab the perlscript here.
Hey Josh,
Thought you might like this image, which contains the complete text of “Moby Dick”.
http://www.flickr.com/photos/krazydad/257804202/
Pingback: Chronillogical » Blog Archive » Cool Stuff
That’s really great, Jim.
Pingback: Entdecke das versteckte Bild | Sonstiges
Pingback: The AV Club Blog » Blog Archive » What Is This A Picture Of?
Pingback: Hidden image « Fish Piper
Pingback: links for 2007-10-26 at toshism
Pingback: stitch » blown highlights
Pingback: Share… » Histogram as Image
Pingback: Josh Millard Speaks! :: Hex, leet, and constrained alphabets - for me3dia
Pingback: hyponeiria » Blog Archive » Bookmarks for June 23rd - July 8th
Pingback: HistoFace on Ironic Sans « Stewdio Blog
I seem to have shown up in some lecture notes. Nice.
Hmm your code is returning an error (and I’m no good at Perl so I have no idea what it means).
hist.pl is telling me:
‘Use of uninitialized value $lev in numeric gt (>) at ./hist.pl line 33.’
And a similar error in rehist. Any ideas how I can fix it?
Pingback: Esteganografia en el Histograma de una Imagen
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!
Pingback: Nueva técnica esteganográfica en imagenes: Histogramas : Bitgamia