context: //*****************************************************************************************
  //  File:       TouchlessMgr.cs
  //  Project:    TouchlessLib
  //  Author(s):  Michael Wasserman (Michael.Wasserman@microsoft.com)
  //              Gary Caldwell (gacald@microsoft.com)
  //
  //  TODO: Implement additional marker data (ColorAvg, ColorSpace, Axis, Roundness...)
  //  TODO: Fix representative color.
  //  TODO: Add flood fill alrogithm to GetMarkerAppearance?
  //  TODO: Add RefineMarkerAppearance? (provide subsequent examples of a marker appearance)
  //  TODO: Periodically/continuously adopt surrounding pixels of confirmed marker pixels...
  //  TODO: Single function for RGB->HSV->Binned->Hash#... (reduce loop overhead)
  //  TODO: Fix the search bounds hack for smoothing enabled (store raw&smoothed values?)
  //  TODO: Smarter updating of command lists between consecutive images / row sections?
  //  TODO: Improve the search bounds of a previously absent marker. (or scan sparsely)
  //  TODO: Add Markers publicly accessible member...
  //  TODO: New marker add method: use n>1 consecutive images, detect motion... (maybe...)
  //*****************************************************************************************
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Text;
  using System.Runtime.InteropServices;
  using System.Diagnostics;
  using System.Drawing;
  using System.Drawing.Imaging;
  
  namespace TouchlessLib
  {
      /// <summary>
      /// Main class for the Touchless library.  Allows access to cameras on the
      /// system and manipulation of Markers
      /// </summary>
      public class TouchlessMgr : IDisposable
      {
          #region Public Interface
  
          /// <summary>
          /// Refreshes the list of available cameras.  All existing camera instances are invalidated
          /// </summary>
          public void RefreshCameraList()
          {
              int count = 0;
  
              CleanupCameras();
              _cameras = new List<Camera>();
  
              if (NativeMethods.WebCamRefreshCameraList(ref count) == 0)
              {
                  for (int n = 0; n < count; n++)
                  {
                      IntPtr name = IntPtr.Zero;
                      object nativeInterface = null;
                      if (NativeMethods.WebCamGetCameraDetails(n, out nativeInterface, out name) == 0)
                      {
  
                          Camera cam = new Camera(nativeInterface, Marshal.PtrToStringBSTR(name));
                          _cameras.Add(cam);
                      }
  
                      Marshal.FreeBSTR(name);
                  }
              }
          }
  
          /// <summary>
          /// Returns all available cameras 
          /// </summary>
          public IList<Camera> Cameras
          {
              get
              {
                  if (_cameras == null)
                  {
                      RefreshCameraList();
                  }
  
                  return _cameras.AsReadOnly();
              }
          }
  
          /// <summary>
          /// The camera currently acquiring images, only one camera can be acquiring at one time and 
          /// its starts acquiring as soon as it is set
          /// </summary>
          /// <example>
          /// <code>
          ///     TouchlessMgr _touch = new TouchlessMgr();
          ///     ...
          /// 
          ///     // Pick the first available camera 
          ///     _touch.CurrentCamera = _touch.Cameras[0];
          /// </code>
          /// </example>
          public Camera CurrentCamera
          {
              get { return _currentCamera; }
              set
              {
                  if (_currentCamera != null)
                  {
                      NativeMethods.WebCamStopCamera();
                      _currentCamera = null;
                  }
  
                  if (value == null)
                  {
                      return;
                  }
  
                  if (value.NativeInterface == null)
                  {
                      throw new InvalidComObjectException("The camera has been disposed");
                  }
  
                  _nativeCallback = new NativeMethods.CaptureCallbackProc(CaptureCallbackProc);
                  int rc = NativeMethods.WebCamStartCamera(value.NativeInterface, 
                      _nativeCallback,
                      ref _camWidth,
                      ref _camHeight);
                  if ( rc == 0)
                  {
                      _currentCamera = value;
                  }
                  else
                  {
                      throw new ApplicationException(string.Format("Unable to start camera. rc={0}", rc)); // TODO make a better exception
                  }
              }
          }
  
          /// <summary>
          /// Returns all tracked markers as an enumeration
          /// </summary>
          public IList<Marker> Markers
          {
              get { return _markers.AsReadOnly(); }
          }
  
          /// <summary>
          /// Get the current count of tracked markers
          /// </summary>
          public int MarkerCount
          {
              get { return _markers.Count; }
          }
  
          /// <summary>
          /// Adds a new marker given training data as an image and proposed marker region
          /// </summary>
          /// <param name="name">Caller supplied name for the new marker</param>
          /// <param name="image">The image to scan for the new marker</param>
          /// <param name="center">The center point of the new marker as pixel coordinates</param>
          /// <param name="radius">The radius of the new marker in pixels</param>
          /// <returns>A newly trained marker</returns>
          /// /// <example>
          /// The following is a code snippet that shows how to create a Marker
          /// <code>
          ///     TouchlessMgr _touch = new TouchlessMgr();
          ///     ...
          /// 
          ///     // Create a new marker using the current image at a fixed location and size
          ///     Marker m = _touch.AddMarker("marker", _touch.CurrentCamera.GetCurrentImage(), new Point(100, 100), 10);
          /// </code>
          /// </example>
          public Marker AddMarker(string name, Bitmap image, Point center, float radius)
          {
              Marker newMarker = new Marker(name);
              newMarker.SetMarkerAppearance(GetMarkerAppearance(image, center, radius));
              _markers.Add(newMarker);
              return newMarker;
          }
  
          /// <summary>
          /// Removes a currently active marker and stops all tracking
          /// </summary>
          /// <param name="index">Index of the marker to remove</param>
          public void RemoveMarker(int index)
          {
              if (index < 0 || index >= _markers.Count)
              {
                  throw new ArgumentOutOfRangeException("index");
              }
  
              _markers.RemoveAt(index);
          }
  
          /// <summary>
          /// The default contructor for a new TouchlessMgr
          /// </summary>
          public TouchlessMgr()
          {
              lock (_webcamLock)
              {
                  if (_webcamLibCount == 0)
                  {
                      if (NativeMethods.WebCamInitialize() != 0)
                      {
                          throw new ApplicationException("Unable to initialize the webcam API");
                      }
                  }
  
                  _webcamLibCount++;
              }
  
              _markers = new List<Marker>();
              // Initialize the per-axis lists of marker scan commands
              _markerScanCommandsX = new List<MarkerScanCommand>();
              _markerScanCommandsY = new List<MarkerScanCommand>();
              // Initialize the per-axis lists of markers to consider in the image loop
              _scanMarkersX = new List<Marker>();
              _scanMarkersY = new List<Marker>();
              // Initialize the marker scan command comparison function delegate
              _MarkerScanCommandComparison = new Comparison<MarkerScanCommand>(delegate(MarkerScanCommand msc1, MarkerScanCommand msc2) { return msc1.coordinate - msc2.coordinate; });
          }
  
          #endregion Public Interface
  
          #region Internal Implementation
  
          // Cameras
          static private int _webcamLibCount = 0;
          static private object _webcamLock = new object();
          private List<Camera> _cameras = null;
          //needed to avoid garbage collection problem
          private NativeMethods.CaptureCallbackProc _nativeCallback;
          private Camera _currentCamera = null;
          private int _camWidth = 0;
          private int _camHeight = 0;
  
          // Markers
          private List<Marker> _markers = null;
          // Per-axis lists of marker scan commands
          private List<MarkerScanCommand> _markerScanCommandsX = null;
          private List<MarkerScanCommand> _markerScanCommandsY = null;
          // The per-axis lists of markers to consider in the image loop
          private List<Marker> _scanMarkersX = null;
          private List<Marker> _scanMarkersY = null;
          // The marker scan command comparison function delegate
          private System.Comparison<MarkerScanCommand> _MarkerScanCommandComparison;
  
          /// <summary>
          /// Here is where the images come in as they are collected, as fast as they can and on a background thread
          /// </summary>
  
gt:         internal void CaptureCallbackProc(int dataSize, byte[] data)