Click here to Skip to main content
15,867,756 members
Articles / Desktop Programming / Windows Forms

Laser Guided Tic Tac Toe Game using Webcam For Vision

Rate me:
Please Sign up or sign in to vote.
4.97/5 (52 votes)
1 Dec 2009CPOL3 min read 134.5K   8.4K   112   27
In this article, we will put together a program which will allow us to play Tic-Tac-Toe game against computer with laser light and webcam for vision.
Laser_Guided_Tic_Tac_Toe__source_code_files_

Introduction

Image processing and games programming may be the most technically challenging job that a programmer can have. The top level programs may require the best from both programmer and computer. Tic-tac-toe is a simple game that makes it easy to build algorithms for the computer to play its own move. In this article, a interactive webcam based Tic Tac Toe game is developed. Program in coded in C# .NET using AForge .NET Framework for certain image processing tasks and image acquisition.

Webcam in Application

The first step would be getting video feed from webcam within our program. We can use AForge .NET Framework for accomplishing this. Image acquisition is simple and pretty fast using AForge .NET Framework. Check out the code snippet below:

C#
private void getCamList()
{
    try
    {
        videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
        comboBox1.Items.Clear();
        if (videoDevices.Count == 0)
            throw new ApplicationException();

        DeviceExist = true;
        foreach (FilterInfo device in videoDevices)
        {
            comboBox1.Items.Add(device.Name);
        }
        comboBox1.SelectedIndex = 0; //make default to first cam
    }
    catch (ApplicationException)
    {
        DeviceExist = false;
        comboBox1.Items.Add("No capture device on your system");
    }
}

//refresh button
private void rfsh_Click(object sender, EventArgs e)
{
    getCamList();
}

//toggle start and stop button
private void start_Click(object sender, EventArgs e)
{
    if (start.Text == "&Start")
    {
        if (DeviceExist)
        {
            videoSource = 
	    new VideoCaptureDevice(videoDevices[comboBox1.SelectedIndex].MonikerString);
            videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
            CloseVideoSource();
            //videoSource.DesiredFrameRate = 10;
            videoSource.Start();
            label2.Text = "Device running...";
            start.Text = "&Stop";
        }
        else
        {
            label2.Text = "Error: No Device selected.";
        }
    }
    else
    {
        if (videoSource.IsRunning)
        {
            timer1.Enabled = false;
            CloseVideoSource();
            label2.Text = "Device stopped.";
            start.Text = "&Start";
        }
    }
}

//eventhandler if new frame is ready
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    Bitmap img = (Bitmap)eventArgs.Frame.Clone();
    // All the image processing is done here...
    pictureBox1.Image = img;
}

//close the device safely
private void CloseVideoSource()
{
    if (!(videoSource == null))
        if (videoSource.IsRunning)
        {
            videoSource.SignalToStop();
            videoSource = null;
        }
}

Think of video as a continuous stream of images, for real time image processing we need to process each and every image captured by the webcam. I'm getting an average of 7 fps within my application. More the fps, more smoothly your program will run.

Design and GUI

As you can see in the picture above, I've created a very basic design for Tic Tac Toe using GDI+ of C# .NET.

Laser Detection & Gameplay

The program searches for the brightest red blob in webcam's field of views. We can do so by using two of the filters defined in AForge .NET Framework.

  1. Color filter to filter out everything except red laser light.
  2. Blob Counter to retrieve the position of laser dot or red blob within image.
C#
ColorFiltering filter = new ColorFiltering(); // define a color filter
C#
// Define the range of RGB to retain within a processed image
filter.Red = new IntRange(254, 255);
filter.Green = new IntRange(0, 240);
filter.Blue = new IntRange(0, 240);
Bitmap tmp = filter.Apply(image); // apply the color filter to image 
C#
IFilter grayscale = new GrayscaleBT709();// define  grayscale filter
			// b'coz blobcounter supports grayscale 8 bpp indexed
 tmp = grayscale.Apply(tmp); // applying the filter
C#
// locking the bitmap data
 BitmapData bitmapData = tmp.LockBits(new Rectangle(0, 0, image.Width, image.Height),
     ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); 
C#
blobCounter blobCounter = new BlobCounter(); // define an object of blobcounter class
blobCounter.ProcessImage(bitmapData); // process the locked bitmap data to find blobs
blobCounter.ObjectsOrder = ObjectsOrder.Size; // arrange the blob in increasing size
Rectangle[] rects = blobCounter.GetObjectsRectangles(); //get the rectangle out a blob
tmp.UnlockBits(bitmapData);
tmp.Dispose();
if (rects.Length != 0)
{
   backpoint = GetCenter(rects[0]); // getcenter is a function to find
       // the center of any rectangle ( this is position of laser light)
   DrawLines(ref image, backpoint); // draw horizontal and vertical line on a
               // center point (see the picture above)
}

After laser has been detected, the program keeps track on movement of laser dot and once laser is turned off, it places the user's move within that grid. To understand this, imagine a tic tac toe board with nine different grids as shown in the image below:

Image 2

The algorithm is designed so that it splits every frame from webcam into nine equal rectangles depicting nine different grids of tic tac toe game. User move is placed within grid in which laser light is turned off. If you don't have laser light or you can't visualize this program, then check out the video at YouTube. For code optimization, we can further add filters before playing any move like checking grid is empty and not occupied by cross or zero, we can also add some pause or sleep so that before program could confirm that there is no laser light within webcam view.

Algorithm For Tic Tac Toe

I tried to implement AI the best way I could, even with a long code. Algorithms are designed with humanistic approach to play tic tac tic. It tries to win the game at first, preventing the other player from winning, and then tries to make a move avoiding "traps" and putting two computer pieces in a row. If none of this is possible, a random move is made.

C#
using System;

namespace WebcamTicTacToe
{
    class ZeroCross
    {
        public bool winner_comp = false; // whether winner is computer
        public bool winner_you = false;// whether winner is user
        public bool tie = false;// game goes in tie
        private int[] zeros = { 0, 0, 0, 0, 0 };// stores moved played by user
        private int[] crosses = { 0, 0, 0, 0, 0 };//stores moves played by computer
        private int countero;//count the zeros played
        private int counterx;//count crosses played
        public int MakeAMove(int MyMove)//This function is called to make
			//a move by computer and takes user move as argument
        {
            zeros[countero] = MyMove; // stores the user move in member function
            countero++;
            if (counterx == 0) // if there is no crosses played make a random move
            {
                int rand_move = RandomMove();
                crosses[counterx] = rand_move;
                counterx++;
                return rand_move;
            }
            else
            {
                // this will  try to win the game at first,
	       // preventing the other player to win, and then tries to
	       // make a move avoiding "traps" and putting 
                // two computer pieces in a row
                //If none of this is possible, a random move is made.
                int[,] Pattern = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 },
		{ 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 }, { 1, 5, 9 }, { 7, 5, 3 } };
                int Compmove = 0;
                int FinalMove = 0;
                int winning_Move = 0;
                for (int i = 0; i < 8; i++)
                {
                    int oCounter = 0;
                    int xCounter = 0;
                    int Incase = 0;
                    for (int j = 0; j < 3; j++)
                    {

                        if (CrossSeek(Pattern[i, j]))
                        {
                            xCounter++;
                        }
                        else if (ZeroSeek(Pattern[i, j]))
                        {
                            oCounter++;
                        }
                        else
                        {
                            Incase = Pattern[i, j];
                        }
                    }
                    if (oCounter == 3)
                    {
                        winner_you = true;
                        return 0;
                    }
                    else if (xCounter == 2 && Incase != 0)
                    {
                        winning_Move = Incase;
                    }
                    else if (oCounter == 2 && Incase != 0)
                    {
                        Compmove = Incase;
                    }
                    else if (oCounter == 0 && xCounter == 1)
                    {
                        if (Compmove == 0)
                        {
                            Compmove = Incase;
                        }
                    }
                    else if (Incase != 0)
                    {
                        FinalMove = Incase;
                    }

                }
                if (winning_Move != 0)
                {
                    crosses[counterx] = winning_Move;
                    counterx++;
                    winner_comp = true;
                    return winning_Move;
                }
                if (Compmove != 0)
                {
                    crosses[counterx] = Compmove;
                    counterx++;
                    if (counterx == 5 || countero == 5)
                    {
                        winner_you = false;
                        winner_comp = false;
                        tie = true;
                    }
                    return Compmove;
                }
                if (FinalMove != 0)
                {
                    crosses[counterx] = FinalMove;
                    counterx++;
                    if (counterx == 5 || countero == 5)
                    {
                        tie = true;
                    }
                    return FinalMove;
                }
                tie = true;
                return 0;
            }
        }
        // In case computer play first move
        public int CompFirstTurn()
        {
            int CompMove = RandomMove();
            crosses[counterx] = CompMove;
            counterx++;
            return CompMove;
        }
        // get winner is called at end to find the winner
        public bool GetWinner()
        {
            if (winner_comp || winner_you || tie)
            {
                return true;
            }
            return false;
        }
        // this searches whether any zero is placed at position passed in argument
        public bool ZeroSeek(int zero)
        {
            for (int i = 0; i < countero; i++)
            {
                if (zeros[i] == zero)
                {
                    return true;
                }
            }
            return false;
        }
        // this searches whether any cross is placed at position passed in argument
        public bool CrossSeek(int cross)
        {
            for (int i = 0; i < counterx; i++)
            {
                if (crosses[i] == cross)
                {
                    return true;
                }
            }
            return false;
        }
        //make a random move
        private int RandomMove()
        {
            Random random = new Random();
            int CompMove;
            bool truth = false;
            do
            {
                CompMove = random.Next(1, 10);
                if (zeros[0] == CompMove || crosses[0] == CompMove)
                {
                    truth = true;
                }
                else
                {
                    truth = false;
                }
            }
            while (truth);
            return CompMove;
        }
    }
} 

Using the Program

Well, the program needs a laser light and a webcam streaming images at 640 X 420, you can modify the source code provided in this article to match with your webcam's resolution.

I've added AI within the game for smooth gameplay even if your machine is not high end and it streams images at low frames per second. The program will try to predict the most probable move that you are uptop and will place it automatically even if your laser pointer is near it.

Conclusion

We have reached the end of this article. I might update this program to add more optimization for best game play. However, for now, have fun with it! You can find some videos of this application on my blog. You can also easily modify the code to make this program do much more than just playing tic tac toe. Have fun!

History

  • 1st December, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Canada Canada
cat me.txt

Comments and Discussions

 
QuestionHelp Pin
Tandra122-Jun-14 4:01
Tandra122-Jun-14 4:01 
QuestionGreat article Pin
sh1omi8-Nov-13 19:01
sh1omi8-Nov-13 19:01 
GeneralMy vote of 5 Pin
Gun Gun Febrianza3-Sep-13 8:36
Gun Gun Febrianza3-Sep-13 8:36 
QuestionGreat Pin
Amir Mohammad Nasrollahi28-Jul-13 2:00
professionalAmir Mohammad Nasrollahi28-Jul-13 2:00 
QuestionIt is cool Pin
nathalie_lb19-Jun-13 2:52
nathalie_lb19-Jun-13 2:52 
QuestionI'm getting 6 errors on compilation of code in visual studio 2010 Pin
Abhishek Pant10-Oct-12 4:53
professionalAbhishek Pant10-Oct-12 4:53 
Questionvideo display Pin
s3d3d22-Apr-12 19:56
s3d3d22-Apr-12 19:56 
QuestionWhat's the anatomy of ColorFiltering()? Pin
Member 22463003-Oct-11 18:52
Member 22463003-Oct-11 18:52 
AnswerRe: What's the anatomy of ColorFiltering()? Pin
shivamkalra16-Oct-11 12:49
shivamkalra16-Oct-11 12:49 
GeneralI modified your source... Pin
JCH00129-Jun-10 10:13
JCH00129-Jun-10 10:13 
GeneralRe: I modified your source... Pin
shivamkalra29-Jun-10 12:19
shivamkalra29-Jun-10 12:19 
Thanks your considering my code. I read your blog through Google translator and it's really interesting.
Generaluse thread Pin
h_sharifi_sh19-May-10 23:14
h_sharifi_sh19-May-10 23:14 
GeneralVery Very Good Pin
h_sharifi_sh19-May-10 23:11
h_sharifi_sh19-May-10 23:11 
GeneralVery good! Pin
sintesia8-Feb-10 22:42
sintesia8-Feb-10 22:42 
GeneralRe: Very good! Pin
shivamkalra20-Mar-10 22:01
shivamkalra20-Mar-10 22:01 
GeneralGreat again Pin
Marcelo Ricardo de Oliveira4-Dec-09 2:51
mvaMarcelo Ricardo de Oliveira4-Dec-09 2:51 
GeneralRe: Great again Pin
shivamkalra5-Dec-09 1:24
shivamkalra5-Dec-09 1:24 
GeneralCoolio Pin
Sacha Barber3-Dec-09 4:58
Sacha Barber3-Dec-09 4:58 
GeneralRe: Coolio Pin
shivamkalra20-Mar-10 22:03
shivamkalra20-Mar-10 22:03 
Generaltic tac toe game AI Pin
Chesnokov Yuriy2-Dec-09 1:32
professionalChesnokov Yuriy2-Dec-09 1:32 
GeneralRe: tic tac toe game AI Pin
shivamkalra2-Dec-09 2:37
shivamkalra2-Dec-09 2:37 
Generalgud work Pin
Varun Sindhu1-Dec-09 21:04
Varun Sindhu1-Dec-09 21:04 
GeneralRe: gud work Pin
shivamkalra3-Dec-09 17:05
shivamkalra3-Dec-09 17:05 
GeneralYou got my five, but... Pin
Paulo Zemek1-Dec-09 13:53
mvaPaulo Zemek1-Dec-09 13:53 
GeneralRe: You got my five, but... Pin
Paulo Zemek2-Dec-09 13:09
mvaPaulo Zemek2-Dec-09 13:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.