Webcam Based Laser Tracking for Human-Computer Interaction

Published 10 April 08 05:47 PM | Coding4Fun 
  In this article, we will put together a program which will allow us to move the mouse cursor on our computers with a laser pointer, and even generate mouse clicks using only a webcam for computer vision. One really cool use of this would be with a projector. With a projector, you could use this application and turn its projected image into an interactive screen, and even open files/menus by just pointing at them with a laser pointer!
http://ashishrd.blogspot.com

Difficulty: Intermediate
Time Required: 1-3 hours
Cost: Free
Software: Visual C# Express Editions,
Hardware: Webcam, Laser Pointer
Download:

I will be making use of Andrew Kirillov's motion detection code for image acquisition, and the AForge.NET framework, for certain image processing tasks. I'll start off by showing you how the image processing works for this program, and then I'll walk you through the important parts of the code. So, let's begin!

Image processing and laser tracking...

The laser tracking code works by finding the brightest pixel in the webcam's field of view. It is pretty much similar to the code I had written for my previous article - Laser Tracking Camera. However, since quick image processing is necessary for this program to work in real-time, I have modified the code a bit, and now it's much faster than before. The two image processing techniques I have used for optimization are - image cropping and image resizing.

Image cropping is basically just trimming off the edges of an image to keep unwanted things outside the camera's view. Image cropping also reduces the number of pixels in an image, and makes image processing fast. On the other hand, resizing images reduces the pixel resolution of an image. The pixel resolution of an image describes the resolution of an image with the set of two positive integer numbers, where the first number is the number of pixel columns (width), and the second is the number of pixel rows (height). (Examples: 320x 40, 640x480, 1024x768). An image from Wikipedia illustrates:

clip_image002[4]

The picture on the left is sampled at 20x20, and the image on the right is sampled at a higher pixel resolution, 100x100. Obviously, the higher resolution image has more detail. However, in image processing, while increased resolution results in greater information and detail, it comes at the price of memory and computing speed.
For cropping the video feed from a webcam, you can click-and-drag a selection rectangle around the area you would like to keep, and the program would remove everything else.
clip_image003[4]

The selection rectangle is a semi-transparent rubber band rectangle (picture above). A rubber band rectangle (aka focus rectangle), is a reversible rectangle that tracks with the mouse pointer while you move it around. This makes it easy to select the area you want to work on. If you are working with a projector, you can easily select its projected area, and the program would map its coordinates to the coordinates on your computer screen, and remove everything else.

Here's how you can make a rubber-band rectangle between two points (say x1,y1 and x2, y2):

//Compute width and height of rectangle
int width = Math.Abs(x2 - x1);
int height = Math.Abs(y2 - y1);                
//Decide x and y of rectangle
int x = 0, y = 0;
if (x1 < x2)
    x = x1;
else if (x1 > x2)
    x = x2;
if (y1 < y2)
    y = y1;
else if (y1 > y2)
    y = y2;
//Draw the rectangle
Rectangle rect = new Rectangle(x, y, width, height);
Graphics g = Graphics.FromImage(image);
g.FillRectangle(new SolidBrush(Color.FromArgb(60, 184, 184, 0)), rect); //Draws a semi-transparent rectangle using alpha blending
g.Dispose();


You will find this code in the ProcessFrame event in MotionDetector1.cs. Here, x1 and y1 are updated in the MouseDown event of the camera window, whereas x2 and y2 are updated in the MouseMove event.
After we know how big the selected area is, we can trim the edges by using the Bitmap.Clone method:

Bitmap tmpImage0 = image.Clone(new Rectangle(x, y, width, height), 
System.Drawing.Imaging.PixelFormat.Format24bppRgb);


For resizing the video feed by a certain factor, adjust the resize factor numeric up/down control. If you take a resize factor, say 2, then the program would divide the length and width of the webcam images by 2, and the resulting images would actually be 2^2 = 4x smaller. For example, if your webcam captures images of size 320 by 240, the total number of pixels in each image would be 320 x 240 = 76800.  If we resize these images by a factor of 2, the resulting 160 by 120 size images would contain only 160 x 120 = 19200 pixels (which is 4x less than 76800).

clip_image004[4]

Here's how we can resize an image by a given factor using the Resize filter in the AForge.Imaging library:

AForge.Imaging.Filters.Resize resize = new Resize(image.Width / resizeFactor, image.Height / resizeFactor, InterpolationMethod.NearestNeighbor);

Bitmap tmpImage1 = resize.Apply(tmpImage0);

Just keep in mind that the lesser you resize your images, the more tracking resolution you'd get while tracking lasers. However, since tracking resolution comes at the cost of memory and computing speed, pick a resize factor which works best for your computer and webcam. A resize factor of 2 or 3 usually works fine for me.
After we're done with cropping and resizing, the program can go through the pixels on the image and find the brightest pixel (I'm assuming this would be the laser dot):

for (int y = 0; y < 240; y++)
{
    for (int x = 0; x < 320; x++) 
    {
        byte red, green, blue;

        red = uBitmap.GetPixel(x, y).red;
        green = uBitmap.GetPixel(x, y).green;
        blue = uBitmap.GetPixel(x, y).blue;
        
        float brightness = (299 * red + 587 * green + 114 * blue) / 1000; 

        if (brightness > certainValue)
            // Do something
    }
}


Here, uBitmap, is an instance of the UnsafeBitmap class I had discussed in my previous article.

NOTE:
If you find brightness tracking unreliable in certain lighting conditions, change the above code to perform color detection instead of brightness detection by writing something like "if ((red > 220) && (green < 170) && (blue < 170))" instead of writing "if (brightness > certainValue)".
After our program has the x and y coordinates of the laser dot, it can compute its position on the screen:

//Get screen width and height
int screenWidth = Screen.GetBounds(this).Width;
int screenHeight = Screen.GetBounds(this).Height;
float cursorX, cursorY;
//Compute location of laser dot into camera coordinates cursorX = ((float)screenWidth / imageWidth) * x; cursorY = ((float)screenHeight / imageHeight) * y;
//Set cursor position Cursor.Position = new Point((int)cursorX, (int)cursorY);

Now that you know how the code works, lets move on to the next section, in which I will tell you how to use it.

Some notes on using the software

  • The program searches for the brightest pixel in the camera's field of view, so the lighting conditions of your room can affect its performance. Adjust the brightness threshold and lighting conditions so that nothing (except the laser) exceeds the brightness threshold. If this doesn't work, change the brightness detection code to perform color detection instead (as described earlier).

clip_image005[4]

  • If you want to reset video cropping to normal, just right-click anywhere in the camera window.
  • For clicking on something with a laser pointer, just turn off the laser when the mouse cursor is over the item you want to click on. Turning the laser off simulates a left button, single-click. You might also want to change your Folder Options to allow files/folders to be opened with single-clicks.
  • While selecting a resize factor, remember that computing speed would come at the cost of tracking resolution. Say, for example, if I use a resize factor of 1, I'd get pretty good tracking resolution, but my program would slow down to a crawl. On the other hand, if I pick a resize factor greater than 4 or 5, I'd get a decent frame rate, but horrible tracking resolution. These values could be different for you (depending on your webcam and computer). For my computer, a resize factor of 2 or 3 works fine and I get about 27-30 frames/second.


Conclusion


We have reached the end of this article, and I hope you enjoyed reading it. Now, here's some homework for you: Try implementing features like double clicking, right clicking and click-drag. If you've watched the video for this article, you must have noticed that I was drawing stuff on MS-Paint using this program. For accomplishing this, I had to modify my code to perform click-drag. If you can think of an easier, laser-based way to switch between different clicking modes, I think that would be very cool. So, use your ideas, and if you end up doing something cool, I'd love to hear about it. :) Have fun!

About the Author

Ashish Derhgawen is an IT student, currently living in New Delhi, India. He has been coding since fourth grade. Some of his other interests are harmonica playing, wildlife and cricket. When he’s not at school, he spends his time working on unusual projects related to robotics, webcams, and electronics besides others. You can reach Ashish through his blog at http://ashishrd.blogspot.com.

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Gwyn said on April 11, 2008 9:14 PM:

Maybe a good method might be to perform both brightness tracking and colour detection. You would first go through the pixels and find the one(s) that were brighter than the threshhold. Then filter out the one(s) that matched the appropriate laser colour.

# Vishal Sood said on April 22, 2008 4:38 PM:

Bit Rate Throttling was Brian's pick of the week on channel 9. We love you Brian :) Here is the link

# Schoolkid said on May 25, 2008 8:56 AM:

this is the first thing im trying from this website (or other websites, im new to programming) could you tell me how to find the first code you see?

# Coding4Fun said on June 2, 2008 7:42 PM:

@Schoolkid, download link is at the top of the page.

# Channel 9 said on June 3, 2008 11:56 PM:

eek on Channel 9, Dan and Brian cover:

# Jerome Demers said on June 26, 2008 5:21 PM:

Hey Ashish!

In your Laser Tracking Camera post I commented that the program crash asfter 5 minutes. Not this one!

It has been 22 minutes now and still going strong!

I thought it was Visual Studio 2008 automatic conversion that made this problem... but no

Thanks!

I will try the color tracking and change the line of code

if ((red > 220) && (green < 170) && (blue < 170))

Can't wait to try it out!

Thanks again!

Jerome

# Dom said on July 12, 2008 4:57 AM:

Do you have an execuatable for download? I don't have visual C++ and cannot download it (I'm on dialup)

# Coding4Fun said on July 14, 2008 6:18 PM:

@Dom:  Visual Studio c# Express or better is required.  It isn't that big of an install.

Are you US based?  Send me an email and I'll see if I can't get you a copy some how.

# Fergo said on July 20, 2008 1:19 AM:

Thanks for this article! Very interesting!

I compiled the code but I can't get my webcam to work above 6FPS (it seems that it's locked at that framerate). My webcam can reach 30fps in "My Computer" and other softwares, but not in the laser tracking application (already tried every setting).

Do you have any idea why this is happening?

The application was compiled in "Release" mode with optimizations and I have a quite nice PC, so I don't think the problem is due to "lack of processing speed" or something like that.

Regards,

Fergo

# fourier said on July 23, 2008 10:03 PM:

where i can get the "release" code.. can you help me with this.. i dont know what code to use in the "motion" folder.

# Coding4Fun said on July 24, 2008 1:26 PM:

@Fergo:  have you done any debugging on it?  Release mode doesn't imply it you'll get a 20% performance boost.

# Coding4Fun said on July 24, 2008 1:27 PM:

@fourier:  "release" is a type of compile you can do.  Most times you'll do a "debug" build for development.

Could you describe your issue a bit better?

# Joe said on August 9, 2008 12:08 AM:

Why can't I download it? It is so awesome!

# Coding4Fun said on August 11, 2008 1:20 PM:

http://www.codeplex.com/laserinteraction/SourceControl/ListDownloadableCommits.aspx

# noglobalwarming2 said on August 11, 2008 11:15 PM:

The video isnt shown on the program. (I have a logitech quickcam messanger). if anyone has the codes or something, can they please write it down?

# Drew said on August 29, 2008 2:13 PM:

After installing I had an issue with my projector screen being white and the laser pointer not showing properly on a white background.

I taped a peice of clear red plastic to my webcam lense and it is working perfectly

# Rabia Javed said on September 19, 2008 1:08 AM:

hello, i am very much impressed with your code .. i wanted to know ; which algorithm you are using for pointer tracking purpose (i.e kalman...)

waiting for your reply kindly reply as early as possible

Thanku

# Rabia said on September 20, 2008 1:59 AM:

Hi .. i'm really impressed by your code ....

but i wanted to know that which algo you are using for tracking purpose???

waiting for ur replay

thanku

# Mais uma utilidade para seu Laser Point &laquo; Manias de Geek said on September 22, 2008 1:13 PM:

PingBack from http://maniasdegeek.wordpress.com/2008/09/22/mais-uma-utilidade-para-seu-laser-point/

# salamat said on October 14, 2008 1:44 AM:

hi just want to know if i would put a blank negative film in my camera to lessen the noise or other light to be seen by the camera and so that the brightest light woud be seen (i think IR light could be better seen with the film)

# Alan said on November 20, 2008 12:00 AM:

Thanks for the interesting project. I will have to play around with the AForge Imaging library! It seems very powerful.

# jagadeesh said on December 23, 2008 3:42 AM:

Hi, I am Jagadeesh..doing my final year btech computer science. i thought of implementing similar process as my final year project.. On searching i found ur blog.

i need some help regarding  the com ports availabe for video input services..

# Coding4Fun said on December 29, 2008 5:13 PM:

@jagadeesh What type of help do you need?

# Pitt said on April 10, 2009 2:16 PM:

Is the source code available to download? Want to check the code to try to better understand what you did.

# Coding4Fun said on April 15, 2009 3:20 PM:

@Pitt the link is at the top of the screen under "Download"  http://www.codeplex.com/laserinteraction

# vivek said on May 29, 2009 11:43 AM:

hey ashish... m a huge fan of urs.. and m planning to do this project for my final year... could you be my tutor?? :) plzzzz

# Rob G said on July 5, 2009 4:15 AM:

I am trying this as my first go at C#.  I have installed the C# software and downloaded your code files, but when i try and build i get Reference path warnings and errors.  Being new to this i have been going around in circles.  is there a prefereed directory i am meant to download this to??

cheers

# Coding4Fun said on July 13, 2009 8:38 PM:

@Rob G, I just downloaded the solution.  All you need to do to get it to run is open up "Motion.sln" then hit F5 to run the program.  if you still have issues, email code4fun@microsoft.com

# Rob G said on July 14, 2009 6:17 AM:

Great to see such inovative coding!  I think a novel addition is to intergrate with standard presentation plug and play kit, that has page up, page down events built in to command powerpoint presentations, but surely some clever intercepts could make this mouse left mouse right comands and really make this application fly!

Wish i was as smart as you coders!

cheers Rob

# Rob G said on July 14, 2009 6:27 AM:

PS yes i have now worked out how C# works. I am an old engineer who worked previously in fortran but i am getting the hang of this!  Clueless on the intracacies though!

# Coding4Fun said on July 14, 2009 2:11 PM:

@Rob G: great to hear you're trying out c#!  I'd love to see what you create!  Put up a youtube or email us code4fun@microsoft.com

# Nisha said on July 21, 2009 12:41 PM:

hey Ashish...great work...i was planning to doing this for my final year project but could u plz tell me about some kinda new features to add to ur code to make it something more innovative?

# paulb said on July 27, 2009 1:08 AM:

hey Ashish.

I just tried this on my PC. It works great.

I then tried to use it as a mouse controller for a FPS game, but it does not work.

I tried it with the following FPS games:

# Arma

# Call of Duty

# Half life 2

I had "Control Cursor" checked. But as soon as each game loaded (the desktop was no longer visible), the cursor stopped responding to my laser pointer.

I then shutdown the game and returned to "Laser tracking and control" - but it appeared to have frozen (camera view was no longer updating). Re-opening my camera device un-froze the application.

Any idea on how to get this to work for FPS games?

thanks.

Paul.

# Coding4Fun said on July 28, 2009 2:28 PM:

@paulb, not sure how those programs operate but I'm assuming they prevent other applications from taking control of the mouse.

# Joe said on August 12, 2009 4:29 AM:

Could you please make it as .exe file to work under Vista. Thank you very much!

# Coding4Fun said on August 13, 2009 2:11 PM:

@Joe, download Visual Studio Express and try it out ofr yourself!  Just hit F5 to compile it.

# Nick said on September 22, 2009 5:27 AM:

Ashish, your project is great indeed!

When I tested it I found some details with my webcam (A4 Tech).

If I set via wmcap.exe the exposure manually to low value (-12 as minimum) I get fps (~17).

If the exposure is at maximum (-10) - fps is approximatelly 6-7.

In auto exposure mode I can reach all 30.5 fps if I do capture near very bright surfice (for example monitor screen) but for all that the webcam seems to be very hot by touch.

Could you explain this behavior?

Regards,

Nick

# JPF321 said on September 23, 2009 1:24 PM:

Ashish, thanks for the wonderful work and blog!

I'm wondering what mods/tweaks were needed to this codebase to write "Hello World" as you did in your demo. It seems that, as is, it only makes mouse-click when laser goes OFF. So how did you get to click & drag lift pen and then click & drag again?

I'm a newbie, but I think my question is a good one

Thanks,

jpf

# Coding4Fun said on September 23, 2009 3:03 PM:

@JPF321 Ashwin's code could do this with an ink control in .net but after PDC (Nov 17 to 19th, 2009) we'll have an article being released that can do this too but with XNA and WPF written by Jeremiah Morrill.

# JPF321 said on September 23, 2009 3:35 PM:

@Coding4Fun .. thanks for the quick response.  Thanks!

# Mike said on November 4, 2009 12:13 AM:

The download link isn't working :-(

There is no current recommended release for this Project

Please help

# Coding4Fun said on November 4, 2009 2:54 PM:

@Mike  http://laserinteraction.codeplex.com/SourceControl/ListDownloadableCommits.aspx  click the download link on the right side.

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker