Image Manipulator

<< Back to the EasyImage Toolkit page

Tutorial - Image Manipulator

What you will learn

This tutorial shows:

  • how to manipulate an image (in this case a running video) to apply
    • distortion effects such as various levels of blurring and sharpening, edge detection, and various embossing styles
    • dithering effects such as various levels of greys and color.

Notes:

  • A few image processing techniques are computationally expensive (e.g., color256 dithering) if done on running video and large images.
  • The program below combines a single distortion technique with a single dithering technique. HoWhile not done in this program, you can also combine various distortion techniques as many times as you want (e.g., blurring with edge detection, although things may slow down).

In the above picture,

  • the original video frame has undergone dithering to 16 grey levels, and then edge detection.

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.

  • 1 PictureBox will display your camera's frames after image processing
    • Name = cbDon'tDistort
    • Size = 320,240 (the Width and Height of the frame we will put in it)
    • BackColor = Black
  • 1 CheckBox
    • Name = lbDistortions, lbDither
    • Text = Don't Distort
  • 2 Listboxes
    • Name = lblDiffDegree, lblDiffPixels, lblThreshold

Step 3. Writing the program

The complete program is listed below. Its long, but only because it methodically lists all options. The actual logic is quite easy.

using System;
using System.Drawing;
using System.Windows.Forms;
using EasyImages;
namespace ImageManipulator
{
  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 = 15;
      camera.ReceivedFrame += new CameraClient.ReceivedFrameEventHandler(camera_ReceivedFrame);
      camera.Start();
      CreateListbox();
    }

    // Manipulate the frame according to the user' selections
    void camera_ReceivedFrame(object sender, CameraEventArgs e)
    {
        manipulateFrame(e.Bitmap);
        DisplayImageInPictureBox(pbCamera, e.Bitmap);
    }

    // Populate the listboxes with  the dither and distortion styles
    // This is a brute force methods; we could have used Enums to make this trivial,
    // but at least this way clearly shows how to use the various DitherStyle and DistortionStyle APIs
    void CreateListbox()
    {
      // Add the various Dither styles to the Dither listbox
      lbDither.Items.Add("None");
      lbDither.Items.Add(DitherStyle.BlackAndWhite.ToString());
      lbDither.Items.Add(DitherStyle.Gray4.ToString());
      lbDither.Items.Add(DitherStyle.Gray16.ToString());
      lbDither.Items.Add(DitherStyle.Gray256.ToString());
      lbDither.Items.Add(DitherStyle.Color16.ToString());
      lbDither.Items.Add(DitherStyle.Color256.ToString());
      lbDither.SetSelected(0, true);

      //Add the varioous Distortion styles to the Distortion listbox
      lbDistortions.Items.Add("None");
      lbDistortions.Items.Add(DistortionStyle.Blur1.ToString());
      lbDistortions.Items.Add(DistortionStyle.Blur2.ToString());
      lbDistortions.Items.Add(DistortionStyle.Blur3.ToString());
      lbDistortions.Items.Add(DistortionStyle.Blur4.ToString());
      lbDistortions.Items.Add(DistortionStyle.Blur5.ToString());
      lbDistortions.Items.Add(DistortionStyle.Blur6.ToString());
      lbDistortions.Items.Add(DistortionStyle.Blur7.ToString());
      lbDistortions.Items.Add(DistortionStyle.Sharpen.ToString());
      lbDistortions.Items.Add(DistortionStyle.SharpenMore.ToString());
      lbDistortions.Items.Add(DistortionStyle.MeanRemoval.ToString());
      lbDistortions.Items.Add(DistortionStyle.EdgeDetect.ToString());
      lbDistortions.Items.Add(DistortionStyle.EmbossHorizontal.ToString());
      lbDistortions.Items.Add(DistortionStyle.EmbossVertical.ToString());
      lbDistortions.Items.Add(DistortionStyle.EmbossHorizontalVertical.ToString());
      lbDistortions.Items.Add(DistortionStyle.EmbossAllDirections.ToString());
      lbDistortions.Items.Add(DistortionStyle.LaplascianEmboss.ToString());
      lbDistortions.Items.Add(DistortionStyle.EmbossLossy.ToString());
      lbDistortions.SetSelected(0, true);
    }

    // Given a bitmap, alter it to match the user's selection of Dither and/or Distortion style
    // This is a brute force methods; we could have used Enums to make this trivial,
    // but at least this way clearly shows how to use the ImageManipulator  APIs
    void manipulateFrame(Bitmap im)
    {
      // Don't do anything if the Don't Distort checkbox is selected, or
      if (cbDontDistort.Checked)  return;

      //Find out what dither style was selected and apply it to the image
      string choice = lbDither.SelectedItem.ToString();
      switch (choice)
      {
        case "None":
          break;
        case "BlackAndWhite":
          EasyImages.ImageManipulator.Dither(DitherStyle.BlackAndWhite, im);
          break;
        case "Gray4":
          EasyImages.ImageManipulator.Dither(DitherStyle.Gray4, im);
          break;
        case "Gray16":
          EasyImages.ImageManipulator.Dither(DitherStyle.Gray16, im);
          break;
        case "Gray256":
          EasyImages.ImageManipulator.Dither(DitherStyle.Gray256, im);
          break;
        case "Color16":
          EasyImages.ImageManipulator.Dither(DitherStyle.Color16, im);
          break;
        case "Color256":
          EasyImages.ImageManipulator.Dither(DitherStyle.Color256, im);
          break;
        default:
          break;
      }

      //Find out what distortion style was selected and apply it to the image
      choice = lbDistortions.SelectedItem.ToString();
      switch (choice)
      {
        case "None":
            break;
        case "Blur1":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur1, im);
            break;
        case "Blur2":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur2, im);
            break;
        case "Blur3":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur3, im);
            break;
        case "Blur4":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur4, im);
            break;
        case "Blur5":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur5, im);
            break;
        case "Blur6":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur6, im);
            break;
        case "Blur7":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Blur7, im);
            break;
        case "Sharpen":
            EasyImages.ImageManipulator.Distort(DistortionStyle.Sharpen, im);
            break;
        case "SharpenMore":
            EasyImages.ImageManipulator.Distort(DistortionStyle.SharpenMore, im);
            break;
        case "MeanRemoval":
            EasyImages.ImageManipulator.Distort(DistortionStyle.MeanRemoval, im);
            break;
        case "EdgeDetect":
            EasyImages.ImageManipulator.Distort(DistortionStyle.EdgeDetect, im);
            break;
        case "EmbossHorizontal":
            EasyImages.ImageManipulator.Distort(DistortionStyle.EmbossHorizontal, im);
            break;
        case "EmbossVertical":
            EasyImages.ImageManipulator.Distort(DistortionStyle.EmbossVertical, im);
            break;
        case "EmbossHorizontalVertical":
            EasyImages.ImageManipulator.Distort(DistortionStyle.EmbossHorizontalVertical, im);
            break;
        case "EmbossAllDirections":
            EasyImages.ImageManipulator.Distort(DistortionStyle.EmbossAllDirections, im);
            break;
        case "LaplascianEmboss":
            EasyImages.ImageManipulator.Distort(DistortionStyle.LaplascianEmboss, im);
            break;
        case "EmbossLossy":
            EasyImages.ImageManipulator.Distort(DistortionStyle.EmbossLossy, im);
            break;
        default:
              break;
      }
    }

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

Explanation

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

  • Form1_Load is the load even handler for the form; it creates a new camera client object, sets its initial properties, and creates the event handler to process generated frames as bitmaps, and initializes the listboxs' contents
  • CreateListbox populates each listbox with all the dither and image distortion styles (using the DitherStyle and DistortionStyle). It sets the first item (None) as the selected item.
  • camera_ReceivedFrame is the event handler for the camera. It first manipulates the image, and then displays it.
  • manipulateFrame finds, for each listbox, what item is selected and then applies that distortion and dither technique unless the checkbox is selected.

Alternative programming

The program could have been written much more tersely but perhaps less clearly by using Enumberator capabilities to get Distortion and Enumberation Styles (in the CreateListbox function) and then match and apply the choice (in the manipulateFrame function). An example is given in the ImageManipulatorShort program (included in the example step.) The code changes are the shown below.

// Populate the listboxes with  the dither and distortion styles
// We exploit the Enumerator to do this.
void CreateListbox()
{
  // Add the various Dither styles to the Dither listbox
  lbDither.Items.Add("None");
  foreach (string style in Enum.GetNames(typeof(EasyImages.DitherStyle)))
  {
    lbDither.Items.Add(style);
  }
  lbDither.SetSelected(0, true);

  //Add the varioous Distortion styles to the Distortion listbox
  lbDistortions.Items.Add("None");
  foreach (string style in Enum.GetNames(typeof(EasyImages.DistortionStyle)))
  {
    lbDistortions.Items.Add(style);
  }
  lbDistortions.SetSelected(0, true);
}

// Given a bitmap, alter it to match the user's selection of Dither and/or Distortion style
// We used Enums to make this trivial,
void manipulateFrame(Bitmap im)
{
  // Don't do anything if the Don't Distort checkbox is selected, or
  if (cbDontDistort.Checked)  return;

  //Find out what dither style was selected and apply it to the image
  string choice = lbDither.SelectedItem.ToString();
  if (choice != "None" )
   EasyImages.ImageManipulator.Dither ((EasyImages.DitherStyle)Enum.Parse(typeof(EasyImages.DitherStyle), choice), im);

  //Find out what distortion style was selected and apply it to the image
  choice = lbDistortions.SelectedItem.ToString();
  if (choice != "None")
    EasyImages.ImageManipulator.Distort((EasyImages.DistortionStyle)Enum.Parse(typeof(EasyImages.DistortionStyle), choice), im);
}