Camera Client/Camera Server Interaction

<< Back to the EasyImage Toolkit page

Tutorial - Camera Example

What you will learn

This tutorial illustrates the facilities in EasyImage's CameraClient API. Above and beyond what you learnt in the Minimal Camera Example, you will learn how to

  • discover several properties of the server, e.g., its frame rate
  • hook into server events, e.g., when its stopped and started
  • set the camera's properties, i.e., the desired frame rate
  • retrieve the frame's current size
  • using a timer, monitor the actual frame rate from the desired frame rate.

Background

There are several nuances about how the Camera Client receives frames that you need to understand.

  • It is the Camera Server, through its interactive controls, that let you set the actual size of a frame and the maximum frame rate
  • The Camera Server will try to generate frames at the maximum rate, but cannot guarantee it. Maximum frame rate is often limited by the actual camera hardware and by system load
  • The Camera Client can see if the size of the frame has changed by looking at the frame's Bitmap Width, Height or Size property
  • The Camera Client can request a frame rate from the server. If the frame rate is less than what the server setting is, the client may receive up to that amount (but often less!). If the frame rate is greater than what the server setting is, the client will likely receive multiple copies of a frame (i.e., it is over-sampling). Yes, this is not a great situation... but its what we are stuck with for now. Still, you can check to see what the server frame rate is and make sure you don't request a faster frame rate than it can really deliver.
  • Typically, most cameras/systems should be able to handle around 10 to 15 fps. If you set it higher, you are not likley to receive more 'real' frames.
  • Note that some of these client/sever interactions are buggy, e.g., if you start / stop the camera/test pattern, it may not always have the desired effect. These are known bugs.

Download

While we recommend you create this program from scratch, you can also download the source and executables.

Source and Executables of this and other examples: EasyImagesExamples.zip
  • Unzip all files into a single folder.
  • Try the executable; a shortcut is in the top-level directory, or look in the debug directory
  • You will need a web camera attached to your computer.

Preconditions

1. Including EasyImages in your new Visual Studio 2005 C# project. This was described in Minimal Camera Example. Make sure to include the using EasyImages; line in your project.

Step 2. Creating GUI controls

2). Add the following GUI controls to your form window, so it looks like the window at the top of this page.

  • PictureBox will display your camera's frames
    • Name = pbCamera
    • Size = 640,480 (the Width and Height of the frame we will put in it)
    • BorderStyle = FixedSingle
    • BackColor = Black
  • CheckBox (start and stop the camera)
    • Name = cbPlay
  • Two Group Boxes
    • Text = Frame Size, Frame Rate (frames / second)
  • 4 Labels (for annotation as seen in the form)
  • Text = width:, height:, desired:, actual:
  • 4 Labels (for displaying various values)
  • Name = lblFrameWidth, lbelFrameHeight, lblDesiredFrameRate, lblActualFrameRate
  • Text = ?, ?, 10, 0
  • TrackBar (interactively change the frame rate in frames per second)
    • Name = tbFrameRate
    • Minimum = 1
    • Maximum = 30
  • Timer (for calculating the actual frames per second)
    • Interval = 1000 (1 second)
    • Enabled = true

Step 3. Writing the program

The complete program is listed below. Its simpler than it looks, for most of it are just callbacks for the GUI controls. Enter it and try it. Then read the explanation that follows.

using System;
using System.Drawing;
using System.Windows.Forms;
using EasyImages;

// Author: Saul Greenberg, University of Calgary, http://www.cpsc.ucalgary.ca/~saul 
// Copyright: (c) June 7, 2007.
// Documentation: see http://grouplab.cpsc.ucalgary.ca/cookbook/ and select EasyImages.
// The API Documentation and a tutorial explaining this and other programs are available there
// License: See License details included in the distribution package. Essentialy, permission to
// use and/or alter this program for non-commerical and/or educational purposes is granted,
// as long as attribution to the above author is maintained.
namespace CameraClientServerInteraction
{
  public partial class Form1 : Form
  {
    private EasyImages.CameraClient camera;  // CameraClient retrieves frames from the camera server
    private delegate void SetPictureBoxImage(PictureBox pbox, Bitmap image);
    int frameCounter = 0;                    // A count of the number of frames we actually see per second

    public Form1()
    {
      InitializeComponent();
    }

    // Create a CameraClient that connects to the Camera server's default camera
    // Create all its event handlers, i.e., when a frame arrives, when the servers starts, and when it stops.
    private void Form1_Load(object sender, EventArgs e)
    {
      camera = new EasyImages.CameraClient("DefaultCamera");

      camera.ReceivedFrame += new CameraClient.ReceivedFrameEventHandler(camera_ReceivedFrame);
      camera.ServerStarted += new CameraClient.ReceivedServerStartedEventHandler(camera_ServerStarted);
      camera.ServerStopped += new CameraClient.ReceivedServerStoppedEventHandler(camera_ServerStopped);
    }

    //
    // Event handlers for the camera
    //

    // The camera server just started.
    void camera_ServerStarted(object sender, CameraServerStarted e)
    {
      toolStripServerStatus.Text = "Server - started " + camera.ServerMaxSpeed.ToString();
      Reset();
    }

    // The camera server just stopped
    void camera_ServerStopped(object sender, CameraServerStopped e)
    {
      toolStripServerStatus.Text = "Server - stopped " + camera.ServerMaxSpeed.ToString();
      Reset();
    }

    //When we receive a frame, display it in the picture box and increment the frame counter
    void camera_ReceivedFrame(object sender, CameraEventArgs e)
    {
      DisplayImageInPictureBox (pbCamera, e.Bitmap);
      frameCounter++;
    }

    // Display the image in the picture box in the correct thread
    private void DisplayImageInPictureBox(PictureBox pbox, Image image)
    {
      if (pbox.InvokeRequired) // We are in the wrong thread. Call ourselves in the correct thread
      {
        SetPictureBoxImage theDelegate = new SetPictureBoxImage(DisplayImageInPictureBox);
        BeginInvoke(theDelegate, new object[] { pbox, image });
      }
      else // we are in the correct thread, so assign the image
      {
        pbox.Image = image;
      }
    }

    //
    // Event handlers for user interactions
    //

    //Start or stop the camera client, i.e., how it retrieves frames from the camera server
    //Reset the camera to update the interface...
    private void cbPlay_CheckedChanged(object sender, EventArgs e)
    {
      if (cbPlay.Checked)
      {
        if (camera.Start() == true)
        {
          Reset();
          lblDesiredFrameRate.Text = tbFrameRate.Value.ToString();
          toolstripClientStatus.Text = "Client - started";
        }
        else
        {
          toolstripClientStatus.Text = "Client - could not start";
        }
      }
      else
      {
        camera.Stop();
        Reset();
        toolstripClientStatus.Text = "Client - stopped";
      }
    }

    //Interactively adjust the frame rate of the camera, in frames per second,
    // and display it as the Desired Frame Rate
    //Note that we cannot actually get more frames than those set by the camera server...
    private void tbFrameRate_Scroll(object sender, EventArgs e)
    {
      if (tbFrameRate.Value > 0 )
        camera.FramesPerSecond = tbFrameRate.Value;
      lblDesiredFrameRate.Text = tbFrameRate.Value.ToString();
    }

    //Display how many frames have actually been seen in the last second
    private void timer1_Tick(object sender, EventArgs e)
    {
      lblActualFrameRate.Text = frameCounter.ToString();
      frameCounter = 0;
    }

    //
    // Reset the interface and the camera settings to reflect the current state
    //
    private void Reset()
    {
      ResetMaxFrameRate ((int) camera.ServerMaxSpeed);

      //Get an image from the camera and find out its size.
      //Display the size and reset the size of the picture box to match it.
      Image img;
      int w, h;
      img = camera.GetFrame ();

      if (null == img)
      {
        w = h = 0;
      } else
      {
        w = img.Width;
        h = img.Height;
      }
      //Display the frame's current size
      lblFrameWidth.Text = w.ToString();
      lblFrameHeight.Text = h.ToString();
    }

    //Display the server's maximum frame rate
    //Then reset the trackbar to this maximum.
    private void ResetMaxFrameRate(int max)
    {
      tbFrameRate.Maximum = max;
      lblMaxFPS.Text = max.ToString() + "fps (Max)";

      //Make sure that that trackbar's current value is within the trackbar range,
      // and set the client's frame rate to that.
      if (tbFrameRate.Value <= 0 || tbFrameRate.Value > max) tbFrameRate.Value = max;
      lblDesiredFrameRate.Text = tbFrameRate.Value.ToString();
      if (tbFrameRate.Value > 0) camera.FramesPerSecond = (float)tbFrameRate.Value;
    }
  }
}

Explanation

Much of this program is similar to what was seen in the Minimal Camera, so we only describe what is different.

  • frameCounter will be incremented whenever a new frame is seen.
  • Form_Load is the Form Load event handler; it creates the camera client and sets its properties. In this case, we set the desired frame rate to the value in the trackbar (whose values range from 1-30 fps) and then display that frame rate in the label. We don't start the camera quite yet...
  • camera_ReceivedFrame is the camera event handler that displays the frame as a bitmap in the picturebox. At the same time, it displays the width and height of the frame in the labels. It also increments the frameCounter.
  • cbPlay_CheckedChanged is the cbPlay checkbox handler; it interactively starts / stops the Camera through a checkbox.
  • tbFrameRate_Scroll is the tbFrameRate event handler; it interactively adjusts the desired frame rate in frames per second via the tbFrameRate trackbar, and displays it as the desired frame rate.
  • timer1_Tick goes off every second. It displays the actual frame rate, i.e., the current value of the frameCounter (the number of frames seen in the last second). It then resets the frameCounter to 0.
  • Reset resets the camera settngs and the user interface to the current settngs.