Thursday, January 29, 2009

Anaglyphs and 3D vision

Oh a post about vision systems (about time!)

So you can write alot of code to try and interpret the 3D space in images or you can cheat and use the same technique that the brian uses (well it probably does not use pointers but thats another conversation)

So if you have two cameras you can position them side by side like eyes, and using a bit of DirectX coding take some pictures at the same time:

left

right

In the pictures above you can see that the images are slightly offset from each other (the wall on the left is not visible in the right picture), and from this you can generate Anaglyph image:
Anaglyph

Now if you put your 3D spec's on (the kind that came with Shrek 3D DVD) you can see it in 3D!

The code? something like this does the trick (cue screams of fear! its unsafe code! it's got pointers and stuff! hide behind the sofa!
unsafe public Bitmap MakeAnaglyph()
  {
   Bitmap result = (Bitmap)_right.Clone();

   FastBitmap fbitRight = new FastBitmap(result, ImageLockMode.ReadWrite);
   FastBitmap fbitLeft = new FastBitmap(_left);

   FastBitmap.PixelData* pPixelRight;
   FastBitmap.PixelData* pPixelLeft;

   for (int y = 0; y < _right.Height; y++)
   {
    for (int x = 0; x < _right.Width; x++)
    {
     pPixelRight = fbitRight[x, y];
     pPixelLeft = fbitLeft[x, y];

     pPixelRight->red = pPixelLeft->red;
     pPixelRight->green = (byte)(pPixelRight->green * .82);
     pPixelRight->blue = (byte)(pPixelRight->blue * .95);
    }
   }

   fbitRight.Dispose();
   fbitLeft.Dispose();

   return result;
  }

This code uses my FastBitmap class, which justs makes working with the raw data a bit more obvious:
unsafe class FastBitmap: IDisposable
 {
  Bitmap _source;
  Rectangle _bounds;
  BitmapData _lockedBitmap;
  byte* _pBase;
  int _stride;

  [StructLayout(LayoutKind.Sequential)]
  public struct PixelData
  {
   public byte blue;
   public byte green;
   public byte red;
  }

  public FastBitmap(Bitmap source): this(source, ImageLockMode.ReadOnly)
  {
  }

  public FastBitmap(Bitmap source, ImageLockMode mode)
  {
   _source = source;
   _bounds = Bounds;
   _lockedBitmap = _source.LockBits(_bounds, mode, source.PixelFormat);
   _pBase = (byte*)(void*)_lockedBitmap.Scan0;
   _stride = _lockedBitmap.Stride;
  }
  public PixelData* this[int x, int y]
  {
   get
   {
    // Format32bppArgb - Specifies that the format is 32 bits per pixel; 
    // 8 bits each are used for the alpha, red, green, and blue components
    const int bytesPerPixel = 4; 

    PixelData* result = (PixelData*)(_pBase + (y * _stride) + (x * bytesPerPixel));

    return result;
   }
  }

  public Rectangle Bounds
  {
   get
   {
    GraphicsUnit unit = GraphicsUnit.Pixel;
    RectangleF bounds = _source.GetBounds(ref unit);

    Rectangle result = SizeToRectangle(bounds.Location, bounds.Size.ToSize());

    return result;
   }
  }


  private Rectangle SizeToRectangle(Size size)
  {
   return SizeToRectangle(new Point(0, 0), size);
  }

  private Rectangle SizeToRectangle(Point point, Size size)
  {
   return new Rectangle(point, size);
  }

  private Rectangle SizeToRectangle(PointF point, Size size)
  {
   return new Rectangle(new Point((int)point.X, (int)point.Y), size);
  }

  #region IDisposable Members

  public void Dispose()
  {
   if (_lockedBitmap != null)
   {
    _source.UnlockBits(_lockedBitmap);
    _lockedBitmap = null;
   }
  }

  #endregion
 }

How does this get you nearer to 3D vision? hint: red-blue differencing of the result...

No comments: