Shape recognition using C# and AForge

This post is about how to use the AForge API to recognize simple shapes. These shapes are poorly drawn on a paper and were captured on my camera.

 
CameraHandler
This class is used to list our connected cameras and update frames. I gues it’s selfexplaining.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using AForge.Video;
using AForge.Video.DirectShow;

namespace CameraTesting
{
    class CameraHandler
    {
        private FilterInfoCollection videoDevices = null;
        private VideoCaptureDevice videoSource = null;
        private PictureBox pbCamPreview = null;
        private Bitmap currentImage= null;


        // initialize with picturebox - used to load new frames later on
        public CameraHandler(PictureBox pbCamPreview)
        {
            this.pbCamPreview = pbCamPreview;
        }


        public Bitmap getSnapshot()
        {
            return currentImage;
        }

        // this function stops the image capturing 
        public void stopCapture()
        {
            if (!(videoSource == null))
                if (videoSource.IsRunning)
                {
                    videoSource.SignalToStop();
                    videoSource = null;
                }
        }

        // starts the video capturering function
        public bool startCapture()
        {
            try
            {
                videoSource.Start();
                return true;

            } 
            catch (Exception e)
            {
                return false;
            }
        }

        // sets a VideoSource to capture images
        public bool setVideoSourceByIndex(int index)
        {
            videoSource = null;
            try
            {
                videoSource = new VideoCaptureDevice(videoDevices[index].MonikerString);
                videoSource.NewFrame += new NewFrameEventHandler(setNewFrame);
                return true;
            }
            catch
            {
                
                return false;
            }
        }

        /* refreshes the list of video sources for further processing and 
         * returns a list of all devices, found on the system */
        public FilterInfoCollection refreshCameraList()
        {
            videoDevices = null;
            try
            {
                videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
                if (videoDevices.Count == 0)
                    throw new ApplicationException();
            }
            catch (ApplicationException)
            {

            }
            return videoDevices;
        }
     
        //eventhandler for every new frame
        private void setNewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            try
            {
                currentImage = (Bitmap)eventArgs.Frame.Clone();

                //do show image in assigned picturebox
                pbCamPreview.Image = currentImage;
            }
            catch (Exception e)
            {
 
            }
        }

    }
}

 
PictureModificator
This class converts a given bitmap to greyscale, removes all surfaces and applies a black background with less color depth. There is also a function which scans the picture for shapes and marks them on the picture itself.

using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Reflection;

using AForge;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge.Math.Geometry;


namespace CameraTesting
{
    class PictureModificator
    {
        private Bitmap currentImage;

        public PictureModificator(Bitmap currentImage)
        {
            this.currentImage = currentImage;
        }

        public PictureModificator()
        {
            this.currentImage = null;
        }

        public bool applySobelEdgeFilter()
        {
            if (currentImage != null)
            {
                try
                {
                    // create filter
                    SobelEdgeDetector filter = new SobelEdgeDetector();
                    // apply the filter
                    filter.ApplyInPlace(currentImage);
                    return true;
                }
                catch (Exception e)
                {

                }
            }
            return false;
        }

        public bool applyGrayscale()
        {
            if (currentImage != null)
            {
                try
                {
                    // create grayscale filter (BT709)
                    Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
                    // apply the filter
                    currentImage = filter.Apply(currentImage);
                    return true;
                }
                catch (Exception e)
                { }
            }
            return false;
        }

        public bool markKnownForms()
        {
            if (currentImage != null)
            {
                try
                {
                    Bitmap image = new Bitmap(this.currentImage);
                    // lock image
                    BitmapData bmData = image.LockBits(
                        new Rectangle(0, 0, image.Width, image.Height),
                        ImageLockMode.ReadWrite, image.PixelFormat);

                    // turn background to black
                    ColorFiltering cFilter = new ColorFiltering();
                    cFilter.Red = new IntRange(0, 64);
                    cFilter.Green = new IntRange(0, 64);
                    cFilter.Blue = new IntRange(0, 64);
                    cFilter.FillOutsideRange = false;
                    cFilter.ApplyInPlace(bmData);
                   

                    // locate objects
                    BlobCounter bCounter = new BlobCounter();

                    bCounter.FilterBlobs = true;
                    bCounter.MinHeight = 30;
                    bCounter.MinWidth = 30;

                    bCounter.ProcessImage(bmData);
                    Blob[] baBlobs = bCounter.GetObjectsInformation();
                    image.UnlockBits(bmData);

                    // coloring objects
                    SimpleShapeChecker shapeChecker = new SimpleShapeChecker();

                    Graphics g = Graphics.FromImage(image);
                    Pen yellowPen = new Pen(Color.Yellow, 2); // circles
                    Pen redPen = new Pen(Color.Red, 2);       // quadrilateral
                    Pen brownPen = new Pen(Color.Brown, 2);   // quadrilateral with known sub-type
                    Pen greenPen = new Pen(Color.Green, 2);   // known triangle
                    Pen bluePen = new Pen(Color.Blue, 2);     // triangle

                    for (int i = 0, n = baBlobs.Length; i < n; i++)
                    {
                        List<IntPoint> edgePoints = bCounter.GetBlobsEdgePoints(baBlobs[i]);

                        AForge.Point center;
                        float radius;

                        // is circle ?
                        if (shapeChecker.IsCircle(edgePoints, out center, out radius))
                        {
                            g.DrawEllipse(yellowPen,
                                (float)(center.X - radius), (float)(center.Y - radius),
                                (float)(radius * 2), (float)(radius * 2));
                        }
                        else
                        {
                            List<IntPoint> corners;

                            // is triangle or quadrilateral
                            if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
                            {
                                PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
                                Pen pen;
                                if (subType == PolygonSubType.Unknown)
                                {
                                    pen = (corners.Count == 4) ? redPen : bluePen;
                                }
                                else
                                {
                                    pen = (corners.Count == 4) ? brownPen : greenPen;
                                }

                                g.DrawPolygon(pen, ToPointsArray(corners));
                            }
                        }
                    }
                    yellowPen.Dispose();
                    redPen.Dispose();
                    greenPen.Dispose();
                    bluePen.Dispose();
                    brownPen.Dispose();
                    g.Dispose();
                    this.currentImage = image;
                    return true;
                }
                catch (Exception e)
                {
                   
                }
            }
            return false;
        }

        private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
        {
            System.Drawing.Point[] array = new System.Drawing.Point[points.Count];

            for (int i = 0, n = points.Count; i < n; i++)
            {
                array[i] = new System.Drawing.Point(points[i].X, points[i].Y);
            }

            return array;
        }

        public void setCurrentImage(Bitmap currentImage)
        {
            this.currentImage = currentImage;
        }

        public Bitmap getCurrentImage()
        {
            return currentImage;
        }
    }
}

 
Example
Here is a example, which shows you how to use those classes.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using AForge.Video;
using AForge.Video.DirectShow;

namespace CameraTesting
{
    public partial class MainWindow : Form
    {
        private CameraHandler myCamHandler = null;
        private PictureModificator myPicAnalyzer = new PictureModificator();
        public MainWindow()
        {
            InitializeComponent();
            timer1.Start();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            myCamHandler = new CameraHandler(pbCamPreview);
            setNewListBoxContent();
            if (myCamHandler.setVideoSourceByIndex(lstDeviceList.SelectedIndex))
            {
                myCamHandler.startCapture();
            }
        }

        private void start_Click(object sender, EventArgs e)
        {
            if (myCamHandler.setVideoSourceByIndex(lstDeviceList.SelectedIndex))
            {
                myCamHandler.startCapture();
            }
           
        }

        public void setNewListBoxContent()
        {
            try
            {
                lstDeviceList.Items.Clear();
                FilterInfoCollection videoDevices = myCamHandler.refreshCameraList();
                foreach (FilterInfo device in videoDevices)
                {
                    lstDeviceList.Items.Add(device.Name);
                }
                lstDeviceList.SelectedIndex = 0; //make dafault to first cam
            }
            catch (Exception e)
            {
 
            }
        }

        private void refresh_Click(object sender, EventArgs e)
        {
            setNewListBoxContent();
        }



        private void btnSnapshot_Click(object sender, EventArgs e)
        {
            pbSnapshotView.Image = myCamHandler.getSnapshot();
        }


        private void analyzePicture()
        {
            try
            {
                myPicAnalyzer.setCurrentImage((Bitmap)pbSnapshotView.Image);
                myPicAnalyzer.applyGrayscale();
                myPicAnalyzer.applySobelEdgeFilter();
                myPicAnalyzer.markKnownForms();
                pbSnapshotView.Image = myPicAnalyzer.getCurrentImage();
            }
            catch (Exception exc)
            {

            }
        }

        private void btnAnalyze_Click(object sender, EventArgs e)
        {
            analyzePicture();

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            pbSnapshotView.Image = myCamHandler.getSnapshot();
            analyzePicture();
        }

    }
}

 
Result
My application looks like this:

Join the Conversation

13 Comments

  1. Thank you very much, but a couple of these codes was my job, have a problem with a full round objects that are yellow in color There is no shortage here, but I still amber yellow color, which is the number of objects and how do I do wanna get those hollow objects

Leave a comment