FAST feature detector in CSharp

From Emgu CV: OpenCV in .NET (C#, VB, C++ and more)
Revision as of 18:32, 4 April 2013 by Jfcote (talk | contribs)
Jump to: navigation, search

For people like me who use EmguCV in a commercial application, the SURF feature detector can't be an option because it use patented algorithms. As far as I know, the FAST algorithm is not patented and is not in the "nonfree" DLL of openCV. Please note that I'm not a lawyer and that you may want to validate in your specific country.

So here is a modified version of the example using SURF. This time, I'm using the FAST detector to extract point of interest and then the BriefDescriptorExtractor to create a descriptor (Matrix). Then, with the brute force matcher, I compare my model to my observed image.

It's important to note that FAST is not scale invariant like SURF or SIFT but it can be useful in a lot of situation.

Source Code

public static Image<Bgr, Byte> Draw(Image<Gray, Byte> modelImage, Image<Gray, byte> observedImage)
{
   HomographyMatrix homography = null;

   FastDetector fastCPU = new FastDetector(10, true);
   VectorOfKeyPoint modelKeyPoints;
   VectorOfKeyPoint observedKeyPoints;
   Matrix<int> indices;

   BriefDescriptorExtractor descriptor = new BriefDescriptorExtractor();

   Matrix<byte> mask;
   int k = 2;
   double uniquenessThreshold = 0.8;
         
   //extract features from the object image
   modelKeyPoints = fastCPU.DetectKeyPointsRaw(modelImage, null);
   Matrix<Byte> modelDescriptors = descriptor.ComputeDescriptorsRaw(modelImage, null, modelKeyPoints);

   // extract features from the observed image
   observedKeyPoints = fastCPU.DetectKeyPointsRaw(observedImage, null);
   Matrix<Byte> observedDescriptors = descriptor.ComputeDescriptorsRaw(observedImage, null, observedKeyPoints);
   BruteForceMatcher<Byte> matcher = new BruteForceMatcher<Byte>(DistanceType.L2);
   matcher.Add(modelDescriptors);

   indices = new Matrix<int>(observedDescriptors.Rows, k);
   using (Matrix<float> dist = new Matrix<float>(observedDescriptors.Rows, k))
   {
      matcher.KnnMatch(observedDescriptors, indices, dist, k, null);
      mask = new Matrix<byte>(dist.Rows, 1);
      mask.SetValue(255);
      Features2DToolbox.VoteForUniqueness(dist, uniquenessThreshold, mask);
   }

   int nonZeroCount = CvInvoke.cvCountNonZero(mask);
   if (nonZeroCount >= 4)
   {
      nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints, indices, mask, 1.5, 20);
      if (nonZeroCount >= 4)
         homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(
         modelKeyPoints, observedKeyPoints, indices, mask, 2);
   }

   //Draw the matched keypoints
   Image<Bgr, Byte> result = Features2DToolbox.DrawMatches(modelImage, modelKeyPoints, observedImage, observedKeyPoints,
      indices, new Bgr(255, 255, 255), new Bgr(255, 255, 255), mask, Features2DToolbox.KeypointDrawType.DEFAULT);

   #region draw the projected region on the image
   if (homography != null)
   {  //draw a rectangle along the projected model
      Rectangle rect = modelImage.ROI;
      PointF[] pts = new PointF[] { 
         new PointF(rect.Left, rect.Bottom),
         new PointF(rect.Right, rect.Bottom),
         new PointF(rect.Right, rect.Top),
         new PointF(rect.Left, rect.Top)};
         homography.ProjectPoints(pts);

      result.DrawPolyline(Array.ConvertAll<PointF, Point>(pts, Point.Round), true, new Bgr(Color.Red), 5);
   }
   #endregion

   return result;
}