Video Slit Scanning

<< Back to the EasyImage Toolkit page

Tutorial - Slit Scanning

Slit scanning is a photographic technique where a photo is taken through a slit over time. This example shows a variation of slit-scanning applied to video. See our paper and video for more information on how this idea works and how it can be applied.

What you will learn

This tutorial is a companion to the How-To: Understanding Bitmaps. Read that first, and also go through the VideoSlitScanning tutorial before trying to understand this more advanced bitmap manipulation example. This tutorial shows:

  • how to create a slit-scanned image, where a column from a source frame is appended to the end of a destination bitmap.
  • specifically, it shows how to color a bitmap, how to effeciently move bitmap regions, and how to copy pixels from a source bitmap to a destination bitmap.
  • note that this is not really a tutorial on EasyImages, but knowing how you can manipulate successive frames at a low level is really useful if you need a novel effect.

In the above picture,

  • the image on the right is the result of appending a column from video frame on the left (marked with a red line) to the end of the image.
  • the user can move the column being copied via the trackbar


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:
  • 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.

  • 2 PictureBoxes
    • Name = pbOriginal, pbSlitScan
    • Size = 320,240 ; 640, 240 (the Width can vary, but the height must be the same)
  • 1 Label
    • Text = the text seen in the figure
  • '''1 Trackbar
    • Name = tbColumn
    • Minimum = 0
    • Maximum = 319 (the width of the original video frame - 1)
    • Value = 160 (the middle of the video frame)

Step 3. Writing the program

The complete program is listed below. Its long, but it does alot!

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging; //Needed
using EasyImages;
namespace VideoManipulatingBits
  public partial class Form1 : Form
    Bitmap bmSlitScan; //A bitmap that we will use to hold the slit-scanned image
    EasyImages.CameraClient camera;
    private delegate void SetPictureBoxImage(PictureBox pbox, Bitmap image);

    public Form1()

   //As the GUI is loaded...
    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);

      // Create and display blank black bitmap which will eventually hold the slit scanned image
      bmSlitScan = new Bitmap(pbSlitScan.Width, pbSlitScan.Height);
      BitmapColor( (Bitmap) bmSlitScan, 0, 0, 0);
      DisplayImageInPictureBox (pbSlitScan, bmSlitScan);

    // As we receive each frame...
    void camera_ReceivedFrame(object sender, EasyImages.CameraEventArgs e)
      // Shift the slit-scanned bitmap left by one column

      // Copy the column at the given location in the source frame to the end of the slit-scanned bitmap
      BitmapCopyColumn(e.Bitmap, tbColumn.Value, bmSlitScan, bmSlitScan.Width - 1);

      // Display both bitmaps
      DisplayImageInPictureBox(this.pbOriginal, e.Bitmap);
      DisplayImageInPictureBox(this.pbSlitScan, bmSlitScan);

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

    /// BITMAP Manipulation Routines

    //For a given bitmap, color all the bits to the provided RGB byte values   
    public static void BitmapColor(Bitmap bm, byte R, byte B, byte G)
      // Lock the bitmap so we can manipulate it
      BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
        int bheight = data.Height; // putting these data variables into local variables makes the loop run faster
        int bwidth = data.Width;
        int bstride = data.Stride;
        byte* imgPtr = (byte*)(data.Scan0)// the first Byte of the bitmap structure

        // Walk through each pixel in the bitmap by row and column
        for (int row = 0; row < bheight; row++)
          for (int col = 0; col < bwidth; col++)
            // Set each byte's color to the RGB colors supplied (each pixel is 3 bytes of color)
            *imgPtr++ = G;
            *imgPtr++ = B;
            *imgPtr++ = R;
          imgPtr += bstride - bwidth * 3// Go to the next row.
      bm.UnlockBits(data);       // Our work is done, so we can unlock the bitmap.

    //For a given bitmap, move the entire bitmap image 1 column to the left
    //To do this efficiently, we use the MoveMemory function
    [System.Runtime.InteropServices.DllImport("kernel32", EntryPoint = "RtlMoveMemory")]
    private unsafe static extern void MoveMemory(void* desination, void* source, int length);
    public static void BitmapShiftLeft(Bitmap bm)
      // Lock the bitmap so we can manipulate it
      BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
        IntPtr imgPtr = data.Scan0; // the first Byte of the bitmap structure
        int bstride = data.Stride;

        //Shift the entire bitmap left one pixel; we do this row by row
        int copy_length = 3 * (bm.Width - 1);
        int height = data.Height - 1;
        for (int row = height; row >= 0; row--)  //for each row
          byte* inpix = ((byte*)((void*)imgPtr)) + row * bstride;
          MoveMemory(inpix, inpix + 3, copy_length);

    // Copy the column located at the source bitmap's column number to the column at the destination bitmap's column number
    // At the same time, draw a red line on the bottom quarter of the source column so we know what column is being copied
    public static void BitmapCopyColumn(Bitmap source, int sourceColumnNumber, Bitmap destination, int destinationColumnNumber)
      /* Lock both bitmaps so we can manipulate it */
      BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
      BitmapData destData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        // Create a pointer to the first Byte of each bitmap
        IntPtr inp = sourceData.Scan0;
        IntPtr outp = destData.Scan0;

        // Get the stride for each one; for better performance in the loop, we save them as  local variables
        int sourceStride = sourceData.Stride;
        int destinationStride = destData.Stride;

        // Get the height of the source bitmap; again, for better performance in the loop, we save it as s local variable
        int height = sourceData.Height - 1;
        int quarterHeight = (height / 4) * 3 ;

        // For each row
        for (int row = height; row >= 0; row--)
          // Move to the appropriate columns in each bitmap
          byte* inpix = ((byte*)((void*)inp)) + row * sourceStride + sourceColumnNumber * 3;
          byte* outpix = ((byte*)((void*)outp)) + row * destinationStride + destinationColumnNumber * 3;

          // Copy the 3 bytes that make up this row/column pixel in the source to the destination
          outpix[0] = inpix[0];
          outpix[1] = inpix[1];
          outpix[2] = inpix[2];

          // color the bottom half of the source column red, so the person will know what column has been copied
          if (row > quarterHeight)
            inpix[0] = 0;
            inpix[1] = 0;
            inpix[2] = 255;


The critical code are in the several methods found in under the Bitmap Manipulation Routines banner. All these manipulate bits in one or both bitmaps. To understand these, make sure you read the How-To: Understanding Bitmaps. The key differences are:

  • BitmapColor gets a bitmap, walks through it pixel by pixel and byte by byte, and colors each pixel by the R,G or B value to give the bitmap a uniform color. This program sets the background to Black. (RGB = 0, 0, 0)
  • BitmapShiftLeft moves the entire bitmap image 1 column to the left. To do this efficiently, we use the MoveMemory function.
  • BitmapCopyColumn copies the column located at the source bitmap's column number to the column at the destination bitmap's column number. At the same time, it draws a red line on the bottom quarter of the source column so we know what column is being copied.