Assignment 1: Heuristically Detail Revealing

HDR (which really stands for High Dynamic Range) refers to the concept of capturing scene details that span an exceptionally large range of brightness. Dynamic range (DR) is essentially the ratio between the lightest and darkest distinguishable tones in a scene. That sounds simple enough, but the word distinguishable actually has a somewhat imprecise meaning. For example, in darker portions of a scene, noise from both the camera and the light itself (photon shot noise) make distinguishing different tones a statistical thing; what probablity threshold do we apply to call two tones distinguished? A common answer is 50% certainty, but that seems rather generous.... There is also the issue of tonal resolution; how small must the tonal step be to consider a tone distinguished from a similar tone? In any case, measuring DR of a captured image isn't quite as straightforward as you'd expect.

Of course, imprecision in the defition doesn't prevent folks from measuring and talking about DR. DxOMark and sensorgen give lots of measurements. Usually, DR is expressed in terms of stops or (equivalently) EV. One EV change represents a doubling or halving of the brightness. In real life, it is not clear that there are limits on the EV that can be spanned within a scene, and it certainly isn't difficult to find examples with over 20EV. Imagine looking at the Sun from inside a dark cave... but don't actually do that. Why? Because human eyesight isn't designed to handle such great instantaneous DR. The exact number is debatable, but humans can see something 10-14EV DR at a glance; our pupils dilate/constrict (mydriasis/miosis for MDs, change f/number for us) to allow us to handle a larger DR over time. The problem is that most digital cameras only have about 9-11EV DR, which means they can't even record what we see at a glance. Some of the better sensors, notably many made by Sony, can capture 13-15EV DR... which is great, but still far from sufficient for that cave-to-Sun view. Perhaps more importantly, it's also insufficient for things like seeing the kid walking behind your car when the backup camera is blinded by another car's headlights. It's also not sufficient if you're trying to capture the lighting of the scene so you can duplicate it in computer-generated renderings that you are placing in the images (e.g., movie special effects).

There are quite a few different ways to extend the DR of cameras to enable HDR capture. We'll be talking about some of the more exotic ones later. However, this project is just about making your little PowerShot able to capture a lot more than the 9-10EV maximum it normally gets. You'll do it by combining multiple captures into a single image -- and you'll do it entirely within the camera using a Lua script.

One last note: ideally, we like to talk about DR in calibrated units of scene brightness. You're not going to do that here. Like most digital cameras, Canon does actually tag images with exposure parameters and an estimate of scene brightness -- so we could perform a calibration sequence to get fairly accurate scene brightness readings for each pixel. However, that's a lot of computation. Worse still, we really just want the camera to deliver the final image as a JPEG, and they can only represent about 9EV DR in any direct way. So, the HDR images you'll generate in-camera will crudely tone map into a JPEG. In other words, the delivered JPEG will be HDR in the sense of being Heuristically Detail Revealing, but will not contain calibrated scene EV values.

Your Project Using CHDK Lua Scripting

Neither the Canon PowerShot A4000 nor ELPH 115 has been tested by DxOMark. In fact, none of the PowerShots using that 16MP sensor have been. So, you will not find anything giving precise DR measurements. We don't care. All that you're going to do is to do some cleverly self-adjusting HDR. Self-adjusting? What?

It's really simple. For HDR, you just shoot a series of raw images with different exposures and then average them. I've posted the dumb little "average the last two raws" script I showed in class as an example of using the raw development facilities, rawavg.lua. The self-adjusting part has to do with the choice of how many exposures and at what values.

It turns out that the best way to determine what exposures you need would be to directly sample the raw buffer. You could do that, but it would be very slow. Instead, you're going to guess based on the live view... which is a little awkward because the live view is automatically gained up or down. The key thing is that the live view does simulate what the camera would capture with automatic exposure, so sampling the range of values there gives some indication of how things are skewed. In other words, the exposures you average should be placed to equalize the coverage of the image histogram. If you wish, you may have the user specify the (maximum) number of images to combine.

There are several ways to get a histogram in Lua. There are two ways to get live view histogram data. I originally sampled it myself using md_get_cell_val(x,y) to read each value from a reduced-resolution grid established using the motion detection interface, md_motion_detect(...). However, in retrospect, it's easier to get the full histogram by using get_live_histo(). The live histogram returned can also be downsampled by HISTO_STEP_SIZE, but it is somewhat less flexible in that it only samples the Y (luminance) channel of the pixels, whereas the motion detection interface can be set to sample any channel -- but Y should work fine for this project. There is also the very convenient get_histo_range(lo,hi), which allows you to sample the actual image data histogram... but only of the last image shot (i.e., the raw buffer contents). That is also very slow, so you have to enable it by setting shot_hist_enable(1)... and don't want to leave it on when not needed.

To equalize coverage of the histogram, you simply take and average multiple exposures such that the number of histogram pixels covered well (roughly centered) by each exposure is roughly constant. An image with a histogram that is just a spike in the middle could be covered by a single exposure. One with two humps each approximately 2 stops away from the center might be covered by averaging two exposures, one +2 EV and one -2 EV. There really isn't one right answer for how to pick the exposures; you must invent your own algorithm for computing the coverage.

Due Dates, Submission Procedure, & Such

You will be submitting source code (for your Lua script), a make file (which does nothing much for this project), and a simple HTML-formatted "implementor's notes" document. Aside from a brief overview of how your script works, which must include a brief explanation of the algorithm you use to determine the exposures to average, be sure to answer the question: about how many EV can your camera capture? Toward that, it would be reasonable to include at least a couple of images -- one taken normally, the other taken using your script. These should be referenced in your HTML using IMG tags with SRC in the local directory, not posted and referenced from somewhere on the WWW.

For full consideration, your project should be submitted no later than October 8, 2014. Submit your .tar or .tgz file here:

Your email address is .
Your password is

Which type of student are you?
Undergraduate registered for EE599
Graduate registered for EE699


http://aggregate.org/CACS/ Cameras as Computing Systems