Multiple Synthetic Lights

April 18th, 2006

Multiple photographs taken with different light sources can be blended together to create images that appear to have all the light sources simultaneously active. The light sources can be attributed arbitrary colors as well, allowing the creation of an infinite number of synthetic scenes.

Quoting from Synthetic Lighting for Photography by Paul Haeberli:

Light from different light sources add together to illuminate objects in a scene. We can use this super-position principle to modify the lighting of a scene after it has been photographed…

I’ve created an interactive application with three light sources with different colors.


Hover over the image to change the intensities of the three light sources.

This Java applet was done using Processing. The source is below. You can also download the PDE file.

/*
   Multiple Synthetic Lights

   by Ates Goral
   Sometime, 2003

   Based on
   "Synthetic Lighting for Photography"
   by Paul Haeberli
   http://www.sgi.com/misc/grafica/synth/index.html

   Instructions:
   - Roll over the photograph to change the intensities of
     the three different light sources.
*/

// Globals
PImage imgAmb, imgA, imgB, imgC;
float[] ambs, diffA, diffB, diffC;
color clrAmb, clrA, clrB, clrC;
boolean bInitial; // Initial paint?

// Calculate the difference between an image and the ambient
// image
void genDiff(PImage img, float[] arr)
{
    for (int y = 0; y < 250; y++)
    {
        for (int x = 0; x < 250; x++)
        {
            int offs = y * 250 + x;

            float sub = red(img.pixels[offs]) / 255.0 -
            ambs[offs];

            if (sub < 0)
            {
                sub = 0;
            }

            arr[offs] = sub;
        }
    }
}

void setup()
{
    size(250, 250);
    cursor(CROSS);

    imgAmb = loadImage("lighting-11.jpg"); // Ambient
    imgA = loadImage("lighting-09.jpg");
    imgB = loadImage("lighting-10.jpg");
    imgC = loadImage("lighting-14.jpg");

    ambs = new float[250 * 250];
    diffA = new float[250 * 250];
    diffB = new float[250 * 250];

    diffC = new float[250 * 250];

    for (int y = 0; y < 250; y++)
    {
        for (int x = 0; x < 250; x++)
        {
            int offs = y * 250 + x;
            // Normalize to 1.0
            ambs[offs] = red(imgAmb.pixels[offs]) / 255.0;
        }
    }

    genDiff(imgA, diffA);
    genDiff(imgB, diffB);
    genDiff(imgC, diffC);

    // Colors
    clrAmb = #202A35;
    clrA = #7F1025;
    clrB = #8A8768;
    clrC = #291D80;

    bInitial = true; // Enforce initial paint
}

void loop()
{
    // Don't bother if the mouse hasn't moved
    if (pmouseX == mouseX && pmouseY == mouseY && !bInitial)
    {
        return;
    }

    float mX, mY;

    if (!bInitial) // If not doing the initial paint,
                    // use mouse input
    {
        mX = mouseX / 250.0;
        mY = mouseY / 250.0;
    }
    else // If doing the inital paint, assume 50% fade
    {
        mX = 0.5;
        mY = 0.5;
        bInitial = false;
    }

    // Coefficients
    float coeffA = pow((1 - mX), 0.5);
    float coeffC = pow(mX, 0.5);
    float coeffB = (1 - mY);

    for (int y = 0; y < 250; y++)
    {
        for (int x = 0; x < 250; x++)
        {
            int offs = y * 250 + x;
            float amb = ambs[offs];

            // Contribution of each light source
            float contrA = diffA[offs] * coeffA;
            float contrB = diffB[offs] * coeffB;
            float contrC = diffC[offs] * coeffC;

            // Calculate components
            float cmpR = red(clrAmb) * amb +
                red(clrA) * contrA +
                red(clrB) * contrB +
                red(clrC) * contrC;

            float cmpG = green(clrAmb) * amb +
                green(clrA) * contrA +
                green(clrB) * contrB +
                green(clrC) * contrC;

            float cmpB = blue(clrAmb) * amb +
                blue(clrA) * contrA +
                blue(clrB) * contrB +
                blue(clrC) * contrC;

            set(x, y, color(cmpR, cmpG, cmpB));
        }
    }
}

The original images I used are below. I had snatched them a while ago from a search result on Google Images but I can’t find the actual source anymore. So, this will have to go without credit. Please drop me a comment if you know the source of these images. They’re from the “Lighting direction” article at megapixel.net. I’ve submitted a belated permission to use these images in this article and I’m waiting for their response.

Ambient light

Ambient Light

 

Light coming from the left

Light coming from the left

 

Light coming from the top

Light coming from the top

 

Light coming from the right

Light coming from the right

Add a Comment