Minimal Example FCam Programs

These examples demonstrate basic API usage. To build them, see the examples subdirectory in the FCam source package.


Example 1

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <vector>

// Select the platform
#include <FCam/N900.h>
namespace Plat = FCam::N900;

/***********************************************************/
/* A program that takes a single shot                      */
/*                                                         */
/* This example is a simple demonstration of the usage of  */
/* the FCam API.                                           */
/***********************************************************/

void errorCheck();

int main(int argc, char **argv) {

    // Make the image sensor
    Plat::Sensor sensor;

    // Make a new shot
    std::vector<FCam::Shot> shot(3);
    for (size_t i = 0; i < shot.size(); i++) {
        shot[i].exposure = 50000; // 50 ms exposure
        shot[i].gain = 1.0f;      // minimum ISO
    }

    // Specify the output resolution and format, and allocate storage for the resulting image
    shot[0].image = FCam::Image(2592, 1968, FCam::RAW);
    shot[1].image = FCam::Image(1296, 984, FCam::RAW);
    shot[2].image = FCam::Image(648, 492, FCam::RAW);

    // Order the sensor to capture the shots
    sensor.capture(shot);

    // Check for errors
    errorCheck();

    assert(sensor.shotsPending() == shot.size()); // There should be exactly this many shots

    // Retrieve the frame from the sensor
    std::vector<FCam::Frame> frame(shot.size());
    for (size_t i = 0; i < shot.size(); i++) {
        frame[i] = sensor.getFrame();
    }

    sensor.stop();

    errorCheck();

    // Each frame should be the result of the shot we made
    for (size_t i = 0; i < shot.size(); i++) {
        printf("Checking frame %d\n", i);
        assert(frame[i].shot().id == shot[i].id);

        // This frame should be valid too
        assert(frame[i].valid());
        assert(frame[i].image().valid());
        printf("Frame %d OK!\n", i);
    }

    // Save the frames
    FCam::saveDNG(frame[0], "/home/user/MyDocs/DCIM/frame0.dng");
    FCam::saveDNG(frame[1], "/home/user/MyDocs/DCIM/frame1.dng");
    FCam::saveDNG(frame[2], "/home/user/MyDocs/DCIM/frame2.dng");

    // Check that the pipeline is empty
    assert(sensor.framesPending() == 0);
    assert(sensor.shotsPending() == 0);

    return 0;
}




void errorCheck() {
    // Make sure FCam is running properly by looking for DriverError
    FCam::Event e;
    while (FCam::getNextEvent(&e, FCam::Event::Error)) {
        printf("Error: %s\n", e.description.c_str());
        if (e.data == FCam::Event::DriverMissingError) {
            printf("example1: FCam can't find its driver. Did you install "
                   "fcam-drivers on your platform, and reboot the device "
                   "after installation?\n");
            exit(1);
        }
        if (e.data == FCam::Event::DriverLockedError) {
            printf("example1: Another FCam program appears to be running "
                   "already. Only one can run at a time.\n");
            exit(1);
        }
    }
}

Example 2

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <FCam/N900.h>

// Select the platform
namespace Plat = FCam::N900;
// namespace Plat = FCam::F2;

/***********************************************************/
/* Flash / No-flash                                        */
/*                                                         */
/* This example demonstrates capturing multiple shots with */
/* possibly different settings.                            */
/***********************************************************/

int main(int argc, char **argv) {

    // Devices
    Plat::Sensor sensor;
    Plat::Flash flash;
    sensor.attach(&flash); // Attach the flash to the sensor


    // Make two shots
    std::vector<FCam::Shot> shot(2);

    // Set the first shot parameters (to be done with flash)
    shot[0].exposure = 80000;
    shot[0].gain = 1.0f;
    shot[0].image = FCam::Image(2592, 1968, FCam::UYVY);

    // Set the second shot parameters (to be done without flash)
    shot[1].exposure = 80000;
    shot[1].gain = 1.0f;
    shot[1].image = FCam::Image(2592, 1968, FCam::UYVY);

    // Make an action to fire the flash
    Plat::Flash::FireAction fire(&flash);
    fire.duration = flash.minDuration();          // flash briefly
    fire.time = shot[0].exposure - fire.duration; // at the end of the exposure
    fire.brightness = flash.maxBrightness();      // at full power

    // Attach the action to the first shot
    shot[0].addAction(fire);

    // Order the sensor to capture the two shots
    sensor.capture(shot);
    assert(sensor.shotsPending() == 2);    // There should be exactly two shots

    // Retrieve the first frame
    FCam::Frame frame = sensor.getFrame();
    assert(sensor.shotsPending() == 1);    // There should be one shot pending
    assert(frame.shot().id == shot[0].id); // Check the source of the request

    // Write out file if needed
    if (argc > 1) { FCam::saveJPEG(frame, argv[1]); }

    // Retrieve the second frame
    frame = sensor.getFrame();
    assert(frame.shot().id == shot[1].id); // Check the source of the request

    // Write out file
    FCam::saveJPEG(frame, "/home/user/MyDocs/DCIM/example2.jpg");

    // Check the pipeline is empty
    assert(sensor.framesPending() == 0);
    assert(sensor.shotsPending() == 0);
}

Example 3

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <FCam/N900.h>

// Select the platform
namespace Plat = FCam::N900;
// namespace Plat = FCam::F2;

/***********************************************************/
/* Focus sweep                                             */
/*                                                         */
/* This example demonstrates moving the lens during an     */
/* exposure via the use of Lens::FocusAction. It also      */
/* shows how to use the metadata tagged by the devices.    */
/* Because the lens on the N900 zooms slightly when it     */
/* focuses, you'll also get a zoom-blur effect.            */
/***********************************************************/
int main(int argc, char **argv) {

    // Devices
    Plat::Sensor sensor;
    Plat::Lens lens;

    // Attach the lens to the sensor
    sensor.attach(&lens);

    // First focus near with maximal speed
    lens.setFocus(lens.nearFocus(), lens.maxFocusSpeed());
    while (lens.focusChanging()) { ; } // Wait to be done


    // Now make a shot that will sweep the lens
    FCam::Shot shot1;

    FCam::Lens::FocusAction sweep(&lens);
    // Set the parameters of this action
    sweep.time = 0;
    sweep.focus = lens.farFocus();
    sweep.speed = lens.maxFocusSpeed()/4;
    // Calculate how long it takes to move the lens to the desired
    // location in microseconds
    float duration = 1000000.0f *
                     (lens.nearFocus() - lens.farFocus()) / sweep.speed;

    printf("The lens will sweep from near to far in %f milliseconds\n",
           duration / 1000.0);

    // Set the shot parameter accordingly
    shot1.exposure = duration;
    shot1.gain = 1.0f;
    // Use a lower resolution to minimize rolling shutter effects
    shot1.image = FCam::Image(640, 480, FCam::UYVY);

    // Attach the action to the shot
    shot1.addAction(sweep);

    // Order the sensor to capture the shot
    sensor.capture(shot1);
    assert(sensor.shotsPending() == 1); // There should be exactly one shot

    // Retrieve the frame
    FCam::Frame frame = sensor.getFrame();
    assert(frame.shot().id == shot1.id); // Check the source of the request

    // Print out some metadata
    const FCam::Lens::Tags lensTags(frame);
    printf("Aperture        : %.4f\n", lensTags.aperture);
    printf("Initial focus   : %.4f\n", lensTags.initialFocus);
    printf("Final focus     : %.4f\n", lensTags.finalFocus);

    // Save the resulting file
    FCam::saveJPEG(frame, "/home/user/MyDocs/DCIM/example3.jpg");

    assert(sensor.framesPending() == 0);
    assert(sensor.shotsPending() == 0);
}

Example 4

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <FCam/N900.h>
#include <FCam/AutoExposure.h>
#include <FCam/AutoWhiteBalance.h>

// Select the platform
namespace Plat = FCam::N900;
// namespace Plat = FCam::F2;

/***********************************************************/
/* Autoexposure                                            */
/*                                                         */
/* This example shows how to request streams and deal with */
/* the incoming frames, and also uses the provided         */
/* auto-exposure and auto-white-balance routines.          */
/***********************************************************/
int main(int argc, char **argv) {

    // Make a sensor
    Plat::Sensor sensor;

    // Shot
    FCam::Shot stream1;
    // Set the shot parameters
    stream1.exposure = 33333;
    stream1.gain = 1.0f;

    // We don't bother to set frameTime in this example. It defaults
    // to zero, which the implementation will clamp to the minimum
    // possible value given the exposure time.

    // Request an image size and allocate storage
    stream1.image = FCam::Image(640, 480, FCam::UYVY);

    // Enable the histogram unit
    stream1.histogram.enabled = true;
    stream1.histogram.region = FCam::Rect(0, 0, 640, 480);

    // We will stream until the exposure stabilizes
    int count = 0;          // # of frames streamed
    int stableCount = 0;    // # of consecutive frames with stable exposure
    float exposure;         // total exposure for the current frame (exposure time * gain)
    float lastExposure = 0; // total exposure for the previous frame

    FCam::Frame frame;

    do {
        // Ask the sensor to stream with the given parameters
        sensor.stream(stream1);

        // Retrieve a frame, make sure it's the latest
        frame = sensor.getFrame();

        assert(frame.shot().id == stream1.id); // Check the source of the request

        // Calculate the total exposure used (including gain)
        exposure = frame.exposure() * frame.gain();

        // Call the autoexposure algorithm. It will update stream1
        // using this frame's histogram.
        autoExpose(&stream1, frame);

        // Call the auto white-balance algorithm. It will similarly
        // update the white balance using the histogram.
        autoWhiteBalance(&stream1, frame);

        // Increment stableCount if the exposure is within 5% of the
        // previous one
        if (fabs(exposure - lastExposure) < 0.05f * lastExposure) {
            stableCount++;
        } else {
            // Reset stableCount to less than zero to account for latency through the pipeline
            // Otherwise, we might assume we're stable before we see the results of the latest
            // updates.
            stableCount = -sensor.shotsPending();
        }

        // Update lastExposure
        lastExposure = exposure;
        // Increment frame counter
        count++;
    } while (stableCount < 5); // Terminate when stable for 5 frames

    // Order the sensor to stop the pipeline and discard any frames still in it.
    sensor.stop();
    printf("Processed %d frames until stable for 5 frames!\n", count);
    printf("Final exposure: %.2f ms. Final gain: %.2f\n", frame.exposure()/1000.f, frame.gain());
    printf("Final color temperature: %d K\n", frame.whiteBalance());
    // Write out the last, well-exposed frame
    FCam::saveJPEG(frame, "/home/user/MyDocs/DCIM/example4.jpg");

    // Check that the pipeline is empty
    assert(sensor.framesPending() == 0);
    assert(sensor.shotsPending() == 0);
}

Example 5

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <FCam/N900.h>
#include <FCam/AutoFocus.h>

// Select the platform
namespace Plat = FCam::N900;
// namespace Plat = FCam::F2;

/***********************************************************/
/* Autofocus                                               */
/*                                                         */
/* This example shows how to request streams and deal with */
/* the incoming frames, and also uses the provided         */
/* autofocus routine.                                      */
/***********************************************************/
int main(int argc, char **argv) {

    // Devices
    Plat::Sensor sensor;
    Plat::Lens lens;
    sensor.attach(&lens); // Attach the lens to the sensor

    // Autofocus supplied by FCam API
    FCam::AutoFocus autoFocus(&lens);

    // Shot
    FCam::Shot stream1;
    // Set the shot parameters
    stream1.exposure = 50000;
    stream1.gain = 1.0f;

    // Request a resolution, and allocate storage
    stream1.image = FCam::Image(640, 480, FCam::UYVY);

    // Enable the sharpness unit
    stream1.sharpness.enabled = true;

    // We will stream until the focus stabilizes
    int count = 0;        // # of frames streamed

    // Order the sensor to stream
    sensor.stream(stream1);

    // Ask the autofocus algorithm to start sweeping the lens
    autoFocus.startSweep();

    // Stream until autofocus algorithm completes
    FCam::Frame frame;

    do {
        // Retrieve a frame
        frame = sensor.getFrame();
        assert(frame.shot().id == stream1.id); // Check the source of the request

        // The lens has tagged each frame with where it was focused
        // during that frame. Let's retrieve it so we can print it out.
        float diopters = frame["lens.focus"];
        printf("Lens focused at %2.0f cm\n", 100/diopters);

        // The sensor has attached a sharpness map to each frame.
        // Let's sum up all the values in it so we can print out
        // the total sharpness of this frame.
        int totalSharpness = 0;
        for (int y = 0; y < frame.sharpness().height(); y++) {
            for (int x = 0; x < frame.sharpness().width(); x++) {
                totalSharpness += frame.sharpness()(x, y);
            }
        }
        printf("Total sharpness is %d\n\n", totalSharpness);

        // Call the autofocus algorithm
        autoFocus.update(frame);

        // Increment frame counter
        count++;
    } while (!autoFocus.idle());

    printf("Autofocus chose to focus at %2.0f cm\n\n", 100/lens.getFocus());

    // Order the sensor to shut down
    sensor.stop();
    printf("Processed %d frames until autofocus completed!\n", count);

    // Write out the focused frame
    FCam::saveJPEG(frame, "/home/user/MyDocs/DCIM/example5.jpg");

    // Check that the pipeline is empty
    assert(sensor.framesPending() == 0);
    assert(sensor.shotsPending() == 0);
}

Example 6

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <FCam/N900.h>

#include "SoundPlayer.h"

// Select the platform
namespace Plat = FCam::N900;
// namespace Plat = FCam::F2;

/***********************************************************/
/* Shutter sound                                           */
/*                                                         */
/* This example shows how to declare and attach a device,  */
/* and write the appropriate actions. In this example, the */
/* camera will trigger two actions at the beginning of the */
/* exposure: a flash, and a shutter sound.                 */
/* See SoundPlayer class for more information.             */
/***********************************************************/
int main(int argc, char **argv) {

    // Devices
    Plat::Sensor sensor;
    Plat::Flash flash;

    // We defined a custom device to play a sound during the
    // exposure. See SoundPlayer.h/cpp for details.
    SoundPlayer audio;

    sensor.attach(&flash); // Attach the flash to the sensor
    sensor.attach(&audio); // Attach the sound player to the sensor

    // Set the shot parameters
    FCam::Shot shot1;
    shot1.exposure = 400000;
    shot1.gain = 1.0f;
    shot1.image = FCam::Image(2592, 1968, FCam::UYVY);

    // Action (Flash)
    FCam::Flash::FireAction fire(&flash);
    fire.time = 0;
    fire.duration = 60000;
    fire.brightness = flash.maxBrightness();

    // Action (Sound)
    SoundPlayer::SoundAction click(&audio);
    click.time = 0; // Start at the beginning of the exposure
    click.setWavFile("/usr/share/sounds/camera_snd_title_1.wav");

    // Attach actions
    shot1.addAction(fire);
    shot1.addAction(click);

    // Order the sensor to capture a shot.
    // The flash and the shutter sound should happen simultaneously.
    sensor.capture(shot1);
    assert(sensor.shotsPending() == 1); // There should be exactly one shot

    // Retrieve the frame from the sensor
    FCam::Frame frame = sensor.getFrame();
    assert(frame.shot().id == shot1.id); // Check the source of the request

    // Write out the file
    FCam::saveJPEG(frame, "/home/user/MyDocs/DCIM/example6.jpg");

    // Check that the pipeline is empty
    assert(sensor.framesPending() == 0);
    assert(sensor.shotsPending() == 0);
}