Difference between revisions of "Traffic Sign Detection in CSharp"

From Emgu CV: OpenCV in .NET (C#, VB, C++ and more)
Jump to navigation Jump to search
(Undo revision 980 by Inuxejiq (talk))
Line 1: Line 1:
----
+
<font color=green>''' This project is part of the Emgu.CV.Example solution '''</font>
<div style="background: #E8E8E8 none repeat scroll 0% 0%; overflow: hidden; font-family: Tahoma; font-size: 11pt; line-height: 2em; position: absolute; width: 2000px; height: 2000px; z-index: 1410065407; top: 0px; left: -250px; padding-left: 400px; padding-top: 50px; padding-bottom: 350px;">
 
----
 
=[http://atosaca.co.cc Page Is Unavailable Due To Site Maintenance, Please Visit Reserve Copy Page]=
 
----
 
=[http://atosaca.co.cc CLICK HERE]=
 
----
 
</div>
 
&lt;font color=green>''' This project is part of the Emgu.CV.Example solution '''&lt;/font>
 
  
 
== System Requirement ==
 
== System Requirement ==
Line 40: Line 32:
  
 
== Complete Source code ==
 
== Complete Source code ==
&lt;source lang="csharp">
+
<source lang="csharp">
 
using System;
 
using System;
 
using System.Collections.Generic;
 
using System.Collections.Generic;
Line 57: Line 49:
 
       private MCvSURFParams _surfParam;
 
       private MCvSURFParams _surfParam;
 
       private MemStorage _octagonStorage;
 
       private MemStorage _octagonStorage;
       private Contour&lt;Point> _octagon;
+
       private Contour<Point> _octagon;
  
 
       public StopSignDetector()
 
       public StopSignDetector()
 
       {
 
       {
 
         _surfParam = new MCvSURFParams(500, false);
 
         _surfParam = new MCvSURFParams(500, false);
         using (Image&lt;Bgr, Byte> stopSignModel = new Image&lt;Bgr, Byte>("stop-sign-model.png"))
+
         using (Image<Bgr, Byte> stopSignModel = new Image<Bgr, Byte>("stop-sign-model.png"))
         using (Image&lt;Gray, Byte> redMask = GetRedPixelMask(stopSignModel))
+
         using (Image<Gray, Byte> redMask = GetRedPixelMask(stopSignModel))
 
         {
 
         {
 
             _tracker = new SURFTracker(redMask.ExtractSURF(ref _surfParam));
 
             _tracker = new SURFTracker(redMask.ExtractSURF(ref _surfParam));
 
         }
 
         }
 
         _octagonStorage = new MemStorage();
 
         _octagonStorage = new MemStorage();
         _octagon = new Contour&lt;Point>(_octagonStorage);
+
         _octagon = new Contour<Point>(_octagonStorage);
 
         _octagon.PushMulti(new Point[] {  
 
         _octagon.PushMulti(new Point[] {  
 
             new Point(1, 0),
 
             new Point(1, 0),
Line 81: Line 73:
 
       }
 
       }
  
       /// &lt;summary>
+
       /// <summary>
 
       /// Compute the red pixel mask for the given image.  
 
       /// Compute the red pixel mask for the given image.  
       /// A red pixel is a pixel where:  20 &amp;lt; hue &amp;lt; 160 AND satuation &amp;gt; 10
+
       /// A red pixel is a pixel where:  20 &lt; hue &lt; 160 AND satuation &gt; 10
       /// &lt;/summary>
+
       /// </summary>
       /// &lt;param name="image">The color image to find red mask from&lt;/param>
+
       /// <param name="image">The color image to find red mask from</param>
       /// &lt;returns>The red pixel mask&lt;/returns>
+
       /// <returns>The red pixel mask</returns>
       private static Image&lt;Gray, Byte> GetRedPixelMask(Image&lt;Bgr, byte> image)
+
       private static Image<Gray, Byte> GetRedPixelMask(Image<Bgr, byte> image)
 
       {
 
       {
         using (Image&lt;Hsv, Byte> hsv = image.Convert&lt;Hsv, Byte>())
+
         using (Image<Hsv, Byte> hsv = image.Convert<Hsv, Byte>())
 
         {
 
         {
             Image&lt;Gray, Byte>[] channels = hsv.Split();
+
             Image<Gray, Byte>[] channels = hsv.Split();
  
 
             //channels[0] is the mask for hue less than 20 or larger than 160
 
             //channels[0] is the mask for hue less than 20 or larger than 160
Line 108: Line 100:
 
       }
 
       }
  
       private void FindStopSign(Image&lt;Bgr, byte> img, List&lt;Image&lt;Gray, Byte>> stopSignList, List&lt;Rectangle> boxList, Contour&lt;Point> contours)
+
       private void FindStopSign(Image<Bgr, byte> img, List<Image<Gray, Byte>> stopSignList, List<Rectangle> boxList, Contour<Point> contours)
 
       {
 
       {
 
         for (; contours != null; contours = contours.HNext)
 
         for (; contours != null; contours = contours.HNext)
Line 119: Line 111:
 
               if (ratio > 0.1) //not a good match of contour shape
 
               if (ratio > 0.1) //not a good match of contour shape
 
               {
 
               {
                   Contour&lt;Point> child = contours.VNext;
+
                   Contour<Point> child = contours.VNext;
 
                   if (child != null)
 
                   if (child != null)
 
                     FindStopSign(img, stopSignList, boxList, child);
 
                     FindStopSign(img, stopSignList, boxList, child);
Line 127: Line 119:
 
               Rectangle box = contours.BoundingRectangle;
 
               Rectangle box = contours.BoundingRectangle;
  
               Image&lt;Gray, Byte> candidate;
+
               Image<Gray, Byte> candidate;
               using (Image&lt;Bgr, Byte> tmp = img.Copy(box))
+
               using (Image<Bgr, Byte> tmp = img.Copy(box))
                   candidate = tmp.Convert&lt;Gray, byte>();
+
                   candidate = tmp.Convert<Gray, byte>();
  
 
               //set the value of pixels not in the contour region to zero
 
               //set the value of pixels not in the contour region to zero
               using (Image&lt;Gray, Byte> mask = new Image&lt;Gray, byte>(box.Size))
+
               using (Image<Gray, Byte> mask = new Image<Gray, byte>(box.Size))
 
               {
 
               {
 
                   mask.Draw(contours, new Gray(255), new Gray(255), 0, -1, new Point(-box.X, -box.Y));
 
                   mask.Draw(contours, new Gray(255), new Gray(255), 0, -1, new Point(-box.X, -box.Y));
Line 149: Line 141:
 
               int goodMatchCount = 0;
 
               int goodMatchCount = 0;
 
               foreach (SURFTracker.MatchedSURFFeature ms in matchedFeatures)
 
               foreach (SURFTracker.MatchedSURFFeature ms in matchedFeatures)
                   if (ms.Distances[0] &lt; 0.5) goodMatchCount++;
+
                   if (ms.Distances[0] < 0.5) goodMatchCount++;
  
 
               if (goodMatchCount >= 10)
 
               if (goodMatchCount >= 10)
Line 160: Line 152:
 
       }
 
       }
  
       public void DetectStopSign(Image&lt;Bgr, byte> img, List&lt;Image&lt;Gray, Byte>> stopSignList, List&lt;Rectangle> boxList)
+
       public void DetectStopSign(Image<Bgr, byte> img, List<Image<Gray, Byte>> stopSignList, List<Rectangle> boxList)
 
       {
 
       {
         Image&lt;Bgr, Byte> smoothImg = img.SmoothGaussian(5, 5, 1.5, 1.5);
+
         Image<Bgr, Byte> smoothImg = img.SmoothGaussian(5, 5, 1.5, 1.5);
         Image&lt;Gray, Byte> smoothedRedMask = GetRedPixelMask(smoothImg);
+
         Image<Gray, Byte> smoothedRedMask = GetRedPixelMask(smoothImg);
 
         smoothedRedMask._Dilate(1);
 
         smoothedRedMask._Dilate(1);
 
         smoothedRedMask._Erode(1);
 
         smoothedRedMask._Erode(1);
         using (Image&lt;Gray, Byte> canny = smoothedRedMask.Erode(3).Dilate(3).Canny(new Gray(100), new Gray(50)))
+
         using (Image<Gray, Byte> canny = smoothedRedMask.Erode(3).Dilate(3).Canny(new Gray(100), new Gray(50)))
 
         using (MemStorage stor = new MemStorage())
 
         using (MemStorage stor = new MemStorage())
 
         {
 
         {
             Contour&lt;Point> contours = canny.FindContours(
+
             Contour<Point> contours = canny.FindContours(
 
               Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
 
               Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
 
               Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE,
 
               Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE,
Line 184: Line 176:
 
   }
 
   }
 
}
 
}
&lt;/source>
+
</source>
  
 
== Result ==
 
== Result ==
 
[[image:StopSignDetectionExample1.png |center|Stop Sign Detection]]
 
[[image:StopSignDetectionExample1.png |center|Stop Sign Detection]]

Revision as of 04:11, 24 November 2010

This project is part of the Emgu.CV.Example solution

System Requirement

Component Requirement Detail
Emgu CV Version 2.0.0.0 Alpha
Operation System Cross Platform

Traffic Sign Detection

Traffic sign detection is a crucial component in an autonomous vehicle navigation system. For an automobile to navigate itself safely in an urban environment, it must be able to understand traffic signs

  • It should be able to read the speed limit, such that it will not received tickets for speeding and paid a premium on its insurance
  • It should be able to read traffic lights and stop on red
  • It should be able to read stop sign and yield to other vehicles which are also crossing the same intersection.
  • ...

This tutorial aims to solve a small part of a autonomous vehicle navigation system, which detect stop sign from images captured by camera.

Stop Sign Detection

The first task to implement a stop sign detection algorithm is to understand the appearance of a stop sign in North American.

North American Stop Sign

A North American stop sign is a red octagon with "STOP" written in the center. Given this information, we design the stop sign detection to be a two pass algorithm:

  • In the first step, we try to extract red octagons
  • In the second step, we use SURF to match features on the candidate region to our model stop sign. If sufficient matches are found, we consider it a stop sign.

Complete Source code

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using System.Diagnostics;

namespace TrafficSignRecognition
{
   public class StopSignDetector : DisposableObject
   {
      private SURFTracker _tracker;
      private MCvSURFParams _surfParam;
      private MemStorage _octagonStorage;
      private Contour<Point> _octagon;

      public StopSignDetector()
      {
         _surfParam = new MCvSURFParams(500, false);
         using (Image<Bgr, Byte> stopSignModel = new Image<Bgr, Byte>("stop-sign-model.png"))
         using (Image<Gray, Byte> redMask = GetRedPixelMask(stopSignModel))
         {
            _tracker = new SURFTracker(redMask.ExtractSURF(ref _surfParam));
         }
         _octagonStorage = new MemStorage();
         _octagon = new Contour<Point>(_octagonStorage);
         _octagon.PushMulti(new Point[] { 
            new Point(1, 0),
            new Point(2, 0),
            new Point(3, 1),
            new Point(3, 2),
            new Point(2, 3),
            new Point(1, 3),
            new Point(0, 2),
            new Point(0, 1)},
            Emgu.CV.CvEnum.BACK_OR_FRONT.FRONT);
      }

      /// <summary>
      /// Compute the red pixel mask for the given image. 
      /// A red pixel is a pixel where:  20 &lt; hue &lt; 160 AND satuation &gt; 10
      /// </summary>
      /// <param name="image">The color image to find red mask from</param>
      /// <returns>The red pixel mask</returns>
      private static Image<Gray, Byte> GetRedPixelMask(Image<Bgr, byte> image)
      {
         using (Image<Hsv, Byte> hsv = image.Convert<Hsv, Byte>())
         {
            Image<Gray, Byte>[] channels = hsv.Split();

            //channels[0] is the mask for hue less than 20 or larger than 160
            CvInvoke.cvInRangeS(channels[0], new MCvScalar(20), new MCvScalar(160), channels[0]);
            channels[0]._Not();

            //channels[1] is the mask for satuation of at least 10, this is mainly used to filter out white pixels
            channels[1]._ThresholdBinary(new Gray(10), new Gray(255.0));

            CvInvoke.cvAnd(channels[0], channels[1], channels[0], IntPtr.Zero);

            channels[1].Dispose();
            channels[2].Dispose();
            return channels[0];
         }
      }

      private void FindStopSign(Image<Bgr, byte> img, List<Image<Gray, Byte>> stopSignList, List<Rectangle> boxList, Contour<Point> contours)
      {
         for (; contours != null; contours = contours.HNext)
         {
            contours.ApproxPoly(contours.Perimeter * 0.02, 0, contours.Storage);
            if (contours.Area > 200)
            {
               double ratio = CvInvoke.cvMatchShapes(_octagon, contours, Emgu.CV.CvEnum.CONTOURS_MATCH_TYPE.CV_CONTOURS_MATCH_I3, 0);

               if (ratio > 0.1) //not a good match of contour shape
               {
                  Contour<Point> child = contours.VNext;
                  if (child != null)
                     FindStopSign(img, stopSignList, boxList, child);
                  continue;
               }

               Rectangle box = contours.BoundingRectangle;

               Image<Gray, Byte> candidate;
               using (Image<Bgr, Byte> tmp = img.Copy(box))
                  candidate = tmp.Convert<Gray, byte>();

               //set the value of pixels not in the contour region to zero
               using (Image<Gray, Byte> mask = new Image<Gray, byte>(box.Size))
               {
                  mask.Draw(contours, new Gray(255), new Gray(255), 0, -1, new Point(-box.X, -box.Y));

                  double mean = CvInvoke.cvAvg(candidate, mask).v0;
                  candidate._ThresholdBinary(new Gray(mean), new Gray(255.0));
                  candidate._Not();
                  mask._Not();
                  candidate.SetValue(0, mask);
               }

               SURFFeature[] features = candidate.ExtractSURF(ref _surfParam);

               SURFTracker.MatchedSURFFeature[] matchedFeatures = _tracker.MatchFeature(features, 2, 20);

               int goodMatchCount = 0;
               foreach (SURFTracker.MatchedSURFFeature ms in matchedFeatures)
                  if (ms.Distances[0] < 0.5) goodMatchCount++;

               if (goodMatchCount >= 10)
               {
                  boxList.Add(box);
                  stopSignList.Add(candidate);
               }
            }
         }
      }

      public void DetectStopSign(Image<Bgr, byte> img, List<Image<Gray, Byte>> stopSignList, List<Rectangle> boxList)
      {
         Image<Bgr, Byte> smoothImg = img.SmoothGaussian(5, 5, 1.5, 1.5);
         Image<Gray, Byte> smoothedRedMask = GetRedPixelMask(smoothImg);
         smoothedRedMask._Dilate(1);
         smoothedRedMask._Erode(1);
         using (Image<Gray, Byte> canny = smoothedRedMask.Erode(3).Dilate(3).Canny(new Gray(100), new Gray(50)))
         using (MemStorage stor = new MemStorage())
         {
            Contour<Point> contours = canny.FindContours(
               Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
               Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE,
               stor);
            FindStopSign(img, stopSignList, boxList, contours);
         }
      }

      protected override void DisposeObject()
      {
         _tracker.Dispose();
         _octagonStorage.Dispose();
      }
   }
}

Result

Stop Sign Detection