From iLab Cookbook

Toolkits: VideoManipulatingBits

Attach:EasyImagesManipulatingBits.png Δ << Back to the EasyImage Toolkit page

Tutorial - Manipulating Bits in a Bitmap

What you will learn

This tutorial is a companion to the How-To: Understanding Bitmaps. Read that first! This tutorial shows:

In the above picture,

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.

Step 1. Preconditions

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

Add the following GUI controls to your form window. Thei locations and purpose should be obvious if you check the image at the top of this page.

Step 3. Writing the program

The complete program is listed below.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging; //Needed
using EasyImages;
namespace VideoManipulatingBits
{
  public partial class Form1 : Form
  {
    EasyImages.CameraClient camera;
    private delegate void SetPictureBoxImage(PictureBox pbox, Bitmap image);

    public Form1()
    {
      InitializeComponent();
    }

    //As the GUI is loaded, create a new camera object and set its initial properties
    private void Form1_Load(object sender, EventArgs e)
    {
      //Create a new camera object and set its initial properties
      camera = new EasyImages.CameraClient("DefaultCamera");
      camera.FramesPerSecond = 10;
      camera.ReceivedFrame += new EasyImages.CameraClient.ReceivedFrameEventHandler(camera_ReceivedFrame);
      camera.Start();
    }

    // Display the Image plus the altered image
    void camera_ReceivedFrame(object sender, EasyImages.CameraEventArgs e)
    {
      //Display the original video frame
      DisplayImageInPictureBox (this.pbOriginal, e.Bitmap);
      //Make a copy of the bitmap, manipulate it, and display it
      Bitmap bm = e.Bitmap.Clone() as Bitmap;
      ManipulateBits(bm);
      DisplayImageInPictureBox (this.pbAltered, bm);
    }

    //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;
      }
    }

  // Note: needs to be compiled in UNSAFE mode!
  // Select the Build tab in the Project Properties and check the 'Allow Unsafe Code' checkbox
  private void ManipulateBits (Bitmap bm)
  {
    // We must first lock the entire image so that we can manipulate it.
    // The BitmapData class allows us to manipulate it.
    System.Drawing.Imaging.BitmapData data =
      bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
                  ImageLockMode.ReadWrite,
                  PixelFormat.Format24bppRgb);
    unsafe
    {
      // Create a pointer to the first Byte of the structure
      byte* imgPtr = (byte*)(data.Scan0);
      // Now we will walk through the bitmap by row and column
      for (int row = 0; row < data.Height; row++)
      {
        for (int col = 0; col < data.Width; col++)
        {
          // The pixel is 3 bytes long one for each the blue, green, and red values:
          byte blue = (byte)(*imgPtr);
          ManipulateColor(imgPtr);
          // advance one step to the green value
          imgPtr++;
          byte green = (byte)(*imgPtr);
          ManipulateColor(imgPtr);
          imgPtr++;
          // advance one step to the red value
          byte red = (byte)(*imgPtr);
          ManipulateColor(imgPtr);
          imgPtr++;
        }
        // Go to the next row.  Stride gets the offset for the next row,
        // but we have already moved Data.Width*3 through the current row,
        // so we subtract that.
        imgPtr += data.Stride - data.Width * 3;
      }
    }
    // Our work is done, so we can unlock the bitmap.
    bm.UnlockBits(data);
  }

  //Depending on which radio button was selected,
  // either saturate the color held in the byte or wash it out
  //Note that color values range from 0 (none) to 255 (fully saturated)
  unsafe private void ManipulateColor (byte *b)
  {
    if (rbSaturate.Checked)
    {
      // Saturate the color if its above 127, otherwise nothing
      if (*b > 127)
        *b = 255;
      else
        *b = 0;
    }
    else if (rbWashOut.Checked)
    {
      // The maximum any color can have is reduced to 127
      if (*b > 127)
        *b = 127;
    }
   }
  }
}

Explanation

Much of this program is similar to what was seen in the Minimal Camera, so we only describe what is different. Full details on how the critical code in ManipulateBits works is found in the How-To: Understanding Bitmaps and should be read.

Retrieved from http://grouplab.cpsc.ucalgary.ca/cookbook/index.php/Toolkits/VideoManipulatingBits
Page last modified on July 17, 2007, at 07:48 PM