Besides being a furry bundle of energy, and unable to take direction, Dante makes life a little harder to take photos by having bright blue-green eyes when a flash is used. Scientific America has the reason why.

So, what's a geek to do? Well, I wasted an otherwise unused Sunday late morning writing a blue-eye reducer for The Gimp, based on Geoff Kuenning's red-eye reduction perl script.

Red-eye is a lot easier to fix, since red-eye is mostly red, and red is a primary colour. By the time the perl script sees it, you can just compare the channel brightness, and then it's only a matter of changing the red channel's brightness if necessary.

The blue-eye effect from Dante is more cyan - a combination of blue and green. This means having only the red channel to tell you what the correct brightness for the area is. Which obviously isn't all that useful - for example, the center of the blue-eye effect is basically white, meaning the red channel's maxed brightness too.

Geoff's code's core is the following routine to check if the pixel should be fixed, and then fixes it by changing the red channel's brightness to the average of the blue and the green channel:

$rbrite = $r * 0.5133333;
$gbrite = $g;
$bbrite = $b * 0.1933333;

if ($rbrite >= $gbrite - $threshold
    && $rbrite >= $bbrite - $threshold)
{
    $rbrite = ($gbrite + $bbrite) / 2;
    $r = int($rbrite / 0.51333333);
    $data->set(0, $x, $y, $r);
}

Through some experimentation, I tackle the blue-eye problem like this:

$rbrite = 77 * $r / 256;
$gbrite = 150 * $g / 256;
$bbrite = 29 * $b / 256;
my ($obbrite) = $bbrite;
my ($ogbrite) = $gbrite;
if ($bbrite + $gbrite >= ($rbrite - $threshold) * 2.5) {
    $bbrite = $ambient + ($rbrite * 0.70) +
        (($ogbrite + 50) * 0.07) + (($obbrite + 50) * 0.07);
    $gbrite = $ambient + ($rbrite * 0.70) +
        (($ogbrite + 50) * 0.07) + (($obbrite + 50) * 0.07);
    $rbrite = ($rbrite * 0.30) + (($gbrite + $bbrite) / 2);
    $r = int($rbrite);
    $g = int($gbrite);
    $b = int($bbrite);
    $data->set(0, $x, $y, $r);
    $data->set(1, $x, $y, $g);
    $data->set(2, $x, $y, $b);
}

How'd I come up with that? Guesswork, mostly.

How effective is it?

Here's a close-up of the before and after effects:

Dante's blue-eye effect closeup
Dante's blue-eye effect closeup - solved

Here's the same thing of the same face, side-by-side:

Dante's blue-eye effect Dante's blue-eye effect - solved

Apparently, this will only be useful for the next few months, and then Dante's matured eyes will make a different colour.