Image Recognition With C# and Emgu Libraries - CodeProject
Image Recognition With C# and Emgu Libraries - CodeProject
Follow
In the following we'll see how to realize an image recognition program, using C# and EmGu, a .NET wrapper for the Intel OpenCV
image-processing library. At the end of the article, the reader will be able to develop a simple application which will search into a list
of images for the one containing a
Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or
has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm
your email address and start sending you newsletters again. Alternatively, you can update your subscriptions.
Abstract
In the following we'll see how to realize an image recognition program, using C# and EmGu, a .NET wrapper for the Intel OpenCV
image-processing library.
At the end of the article, the reader will be able to develop a simple application which will search into a list of images for the one
containing a smaller portion of the original one, graphically showing the points of intersection between the two.
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 1/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
Once downloaded, the package can be installed in a folder of choice. Upon completion, the install folder will appear like the
following, with the \bin folder containing the core components of the package, i.e. the DLLs that will be referenced in a project.
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 2/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
Important: to make the compiled solutions work, the x86 and x64 folders from \emgucv-windesktop 3.1.0.2504\binmust be copied
into the compiled executable path. Otherwise, the programs which use Emgu won't be able to referencecvextern.dll, msvcp140.dll,
opencv_ffmpeg310_64.dll, vcruntime140.dll, raising an exception and preventing them to run properly.
SURF detection
As said in the Wikipedia page for Speeded up robust features (https://en.wikipedia.org/wiki/Speeded_up_robust_features ), "[...] is
a patented local feature detector and descriptor. It can be used for tasks such as object recognition, image registration, classification
or 3D reconstruction. It is partly inspired by the scale-invariant feature transform (SIFT) descriptor. The standard version of SURF is
several times faster than SIFT and claimed by its authors to be more robust against different image transformations than SIFT. To
detect interest points, SURF uses an integer approximation of the determinant of Hessian blob detector , which can be computed
with 3 integer operations using a precomputed integral image. Its feature descriptor is based on the sum of the Haar wavelet
response around the point of interest. These can also be computed with the aid of the integral image. SURF descriptors have been
used to locate and recognize objects, people or faces, to reconstruct 3D scenes, to track objects and to extract points of interest."
FeatureMatching sample
In the \emgucv-windesktop 3.1.0.2504\Emgu.CV.Example\FeatureMatching folder, there is a sample which was written to show
image recognition capabilities described as above, so it's a great point to start further implementations. Let's start from the
FeatureMatching.cs file: few lines of code are present into the static method Main(). To the present means, those of interest are the
following:
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 3/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
long matchTime;
using(Mat modelImage = CvInvoke.Imread("box.png", ImreadModes.Grayscale))
using (Mat observedImage = CvInvoke.Imread("box_in_scene.png", ImreadModes.Grayscale))
{
Mat result = DrawMatches.Draw(modelImage, observedImage, out matchTime);
ImageViewer.Show(result, String.Format("Matched in {0} milliseconds", matchTime));
}
The Mat class can be roughly paired to an Image, with a set of method and properties serving for the most diverse purposes. As
previously said, here we'll be limited to the essential ones. A complete reference for the Mat class can be found at
http://www.emgu.com/wiki/files/3.1.0/document/html/2ec33afb-1d2b-cac1-ea60-0b4775e4574c.htm
Imread method will read an image from a given path and load type (grayscale, color, and so on), returning a Mat object for further
uses. We have two Mat variables from two different sources, i.e. "box.png" and "box_in_scene.png" (both included into the sample
folder).
So it's clear what is done here: two images will be loaded, with one of them being a subpart of the other one, and the two get
matched to show their common points, determining similarities/inclusiveness. That match is executed by theDraw() method of
the static class DrawMatches, that can be found into the sample folder or at the SURF detector URL listed above. The source code
is as follows:
//----------------------------------------------------------------------------
// Copyright (C) 2004-2016 by EMGU Corporation. All rights reserved.
//----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Features2D;
using Emgu.CV.Flann;
using Emgu.CV.Structure;
using Emgu.CV.Util;
namespace FeatureMatchingExample
{
public static class DrawMatches
{
public static void FindMatch(Mat modelImage, Mat observedImage, out long matchTime, out
VectorOfKeyPoint modelKeyPoints, out VectorOfKeyPoint observedKeyPoints, VectorOfVectorOfDMatch
matches, out Mat mask, out Mat homography)
{
int k = 2;
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 4/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
double uniquenessThreshold = 0.80;
Stopwatch watch;
homography = null;
watch = Stopwatch.StartNew();
}
matchTime = watch.ElapsedMilliseconds;
}
/// <summary>
/// Draw the model image and observed image, the matched features and homography projection.
/// </summary>
/// <param name="modelImage">The model image</param>
/// <param name="observedImage">The observed image</param>
/// <param name="matchTime">The output total time for computing the homography matrix.</param>
/// <returns>The model image and observed image, the matched features and homography projection.
</returns>
public static Mat Draw(Mat modelImage, Mat observedImage, out long matchTime)
{
Mat homography;
VectorOfKeyPoint modelKeyPoints;
VectorOfKeyPoint observedKeyPoints;
using (VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch())
{
Mat mask;
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 5/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
FindMatch(modelImage, observedImage, out matchTime, out modelKeyPoints, out observedKeyPoints,
matches,
out mask, out homography);
if (homography != null)
{
//draw a rectangle along the projected model
Rectangle rect = new Rectangle(Point.Empty, modelImage.Size);
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)
};
pts = CvInvoke.PerspectiveTransform(pts, homography);
#if NETFX_CORE
Point[] points = Extensions.ConvertAll<PointF, Point>(pts, Point.Round);
#else
Point[] points = Array.ConvertAll<PointF, Point>(pts, Point.Round);
#endif
using (VectorOfPoint vp = new VectorOfPoint(points))
{
CvInvoke.Polylines(result, vp, true, new MCvScalar(255, 0, 0, 255), 5);
}
}
#endregion
return result;
}
}
}
}
The core method is FindMatch(), used to discover similarities amongst the images, and populating arrays which will be used by
the Draw() method to show them graphically. We'll not analyze in detail the above code here, but we will modify it in the
following, to make it able not only to spot differences, but to tell the user how much of them are present, allowing the application to
tell - starting from a list of images - what image suits best the detailed one.
FindMatch() method could be customized to expose a count of matches found between images.
Its signature can be modified in:
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 6/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
public static void FindMatch(Mat modelImage, Mat observedImage, out long matchTime, out
VectorOfKeyPoint modelKeyPoints, out VectorOfKeyPoint observedKeyPoints, VectorOfVectorOfDMatch
matches, out Mat mask, out Mat homography, out long score)
Adding the score variable to serve as an output parameter. Its value can be calculated after the VoteForUniqueness()call,
looping between VectorOfVectorOfDMatch matches to increase score value every time we encounter a match:
score = 0;
for (int i = 0; i < matches.Size; i++)
{
if (mask.GetData(i)[0] == 0) continue;
foreach (var e in matches[i].ToArray())
++score;
}
public static void FindMatch(Mat modelImage, Mat observedImage, out long matchTime, out
VectorOfKeyPoint modelKeyPoints, out VectorOfKeyPoint observedKeyPoints, VectorOfVectorOfDMatch
matches, out Mat mask, out Mat homography, out long score)
{
int k = 2;
double uniquenessThreshold = 0.80;
Stopwatch watch;
homography = null;
watch = Stopwatch.StartNew();
}
matchTime = watch.ElapsedMilliseconds;
}
Note: for the sake of speed upon accuracy, in the above code LinearIndexParams has been substituted by KdTreeIndexParams.
Obviously, every method which calls FindMatch() must include the new score variable. So, Draw() method must be
customized accordingly. In short, every time we execute Draw() method we must pass a long variable in which the score will be
calculated, when it get passed to FindMatch() method. Please refer to the source code at the end of the article for further
references.
Declare a new form, naming it emImageViewer, adding to it a PictureBox (imgBox in the example), with Dock = Fill. The source code
will be the following:
using Emgu.CV;
using System.Drawing;
using System.Windows.Forms;
namespace ImgRecognitionEmGu
{
public partial class emImageViewer : Form
{
public emImageViewer(IImage image, long score = 0)
{
InitializeComponent();
if (image != null)
{
imgBox.Image = image.Bitmap;
The constructor requires two parameters: the first, image, of type IImage, constitutes the image (casted Mat object) to be visualized
inside imgBox. The second parameter, score, is the value calculated by the methods seen above. So, in we compare two images with
the following code
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 8/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
long score;
long matchTime;
Which shows a score of 144. Obviously, changing the model image will result in different score values. If, for example, we wish to
compare the scene image with itself, we will obtain
Let's assume we have a given directory, images, with its subfolder structure, each of which may contain images. What is needed now
is to traverse the entire directory tree and execute a comparison for every file found. The calculated score can be saved in an apt
memory structure, to be listed at the end of the process.
class WeightedImages
{
public string ImagePath { get; set; } = "";
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 9/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
public long Score { get; set; } = 0;
}
WeightedImages will be used to memorize the path of a complete image, with its calculated score. The class will be used in
conjunction with a List<>:
A simple method, ProcessFolder(), will parse every single file of each directory in the structure, recursively. For each of them,
it will call ProcessImage(), which is the heart of the process.
try
{
long score;
long matchTime;
ProcessImage() doesn't need to draw the resultant object, it can simply stop when the score is calculated, and that value (with
the file name) is added to imgList.
At the end of it, the imgList is ordered by descendant score value, and used as DataSource for a DataGridView, to show the results of
the process itself.
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 10/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
As it can be seen, the sample directories has been traversed, and for each found image, a score was calculated, comparing the
searched image to the complete one. Please note, since those image are not grayscaled, but coming in colours, that load type was
set accordingly ( ImreadModes.Color).
A second button allow to open the image represented by the current selected grid row, using the emImageViewer created above:
long score;
long matchTime;
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 11/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
And we can see how the correct image has been spotted by the higher score of the list.
Further implementations
The presented code must be considered valid in learning contexts only. A further implementation, to manage - for example - many
thousands images in a single run, can be made by making the program asynchronous / multi-threaded, in order to better split
resources and diminish elaboration time.
Source code
The source code used in the article can be downloaded at https://code.msdn.microsoft.com/Image-recognition-with-C-b13b2864
References
Emgu Wiki
Speeded up robust features
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
Share
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 12/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
Emiliano Musso
Software Developer Follow
Italy this Member
Working in IT since 2003 as Software Developer for Essetre Srl, a company in Northern Italy.
I was awarded in 2014, 2015 and 2016 with Microsoft MVP, for Visual Studio and Development Technologies expertise. My
technology interests and main skills are in .NET Framework, Visual Basic, Visual C# and SQL Server, but i'm proficient in PHP and
MySQL also.
Issue
Dhanish Balloo 2-Feb-18 0:13
Incredible Bug !
David Zenou 7-Aug-17 0:10
Nice work! 5+
Sergey Morenko 21-Jun-17 1:40
My vote of 5
D V L 15-Jun-17 18:04
My vote of 5
Alejandro Gaio 23-May-17 23:16
Re: My vote of 5
Emiliano Musso 30-May-17 3:11
Awesome!
Cr yptonite 23-May-17 3:47
Re: Awesome!
Emiliano Musso 23-May-17 19:12
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 13/14
15/9/2019 Image recognition with C# and Emgu libraries - CodeProject
My vote of 5
ThanhTrungDo 17-May-17 14:59
Re: My vote of 5
Emiliano Musso 30-May-17 3:11
Ver y good
ricardotrein 17-May-17 2:10
Great
Sophia95 16-May-17 3:45
Re: Great
Emiliano Musso 16-May-17 21:40
Refresh 1
General News Suggestion Question Bug Answer Joke Praise Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
https://www.codeproject.com/Articles/1187512/Image-recognition-with-Csharp-and-Emgu-libraries 14/14