FAST feature detector in CSharp

From EMGU
Jump to navigation Jump to 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. You can use it with the FREAK descriptor that is scale invariant. Just replace the BriefDescriptorExtractor with Freak and it should do the trick.

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;
}