my reference manual emucv.pdf
DESCRIPTION
Example how to using Emgu Cv Library for Image processing (Fundamental)TRANSCRIPT
1
Suriya Phiokham 2013 06, 20 Reference : http://www.emgu.com/wiki/index.php/
Working with Images
Depth and Color as Generic Parameter
An Image is defined by its generic parameters: color and depth. To create a 8bit unsigned Grayscale image, in Emgu CV it is done by calling
Image<Gray, Byte> image = new Image<Gray, Byte>( width, height);
Not only this syntax make you aware the color and the depth of the image, it also restrict the way you use functions
and capture errors in compile time. For example, the SetValue(TColor color, Image<Gray, Byte>
mask) function in Image<TColor, TDepth> class (version >= 1.2.2.0) will only accept colors of the same type, and
mask has to be an 8-bit unsigned grayscale image. Any attempts to use a 16-bit floating point or non-grayscale image as a mask will results a compile time error!
Creating Image
Although it is possible to create image by calling CvInvoke.cvCreateImage, it is suggested to construct a
Image<TColor, TDepth> object instead. There are several advantages using the managed Image<TColor, TDepth> class
Memory is automatically released by the garbage collector
Image<TColor, TDepth> class can be examined by Debugger Visualizer
Image<TColor, TDepth> class contains advanced method that is not available on OpenCV, for example, generic operation on image pixels, conversion to Bitmap etc.
Image Color
The first generic parameter of the Image class specific the color of the image type. For example
Image<Gray, ...> img1;
indicates that img1 is a single channel grayscale image.
Color Types supported in Emgu CV 1.3.0.0 includes:
Gray
Bgr (Blue Green Red)
Bgra (Blue Green Red Alpha)
Hsv (Hue Saturation Value)
Hls (Hue Lightness Saturation)
Lab (CIE L*a*b*)
Luv (CIE L*u*v*)
Xyz (CIE XYZ.Rec 709 with D65 white point)
Ycc (YCrCb JPEG)
Image Depth
Image Depth is specified using the second generic parameter Depth. The types of depth supported in Emgu CV
1.4.0.0 include
Byte
SByte
2 Single (float)
Double
UInt16
Int16
Int32 (int)
Creating a new image
To create an 480x320 image of Bgr color and 8-bit unsigned depth. The code in C# would be
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>(480, 320);
If you wants to specify the background value of the image, let's say in Blue. The code in C# would be
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>(480, 320, new Bgr(255, 0, 0));
Reading image from file
Creating image from file is also simple. If the image file is "MyImage.jpg", in C# it is
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>("MyImage.jpg");
Creating image from Bitmap
It is also possible to create an Image<TColor, TDepth> from a .Net Bitmap object. The code in C# would be
Image<Bgr, Byte> img = new Image<Bgr, Byte>(bmp); //where bmp is a Bitmap
Automatic Garbage Collection
The Image<TColor, TDepth> class automatically take care of the memory management and garbage collection.
Once the garbage collector decided that there is no more reference to the Image<TColor, TDepth> object, it will
call the Disposed method, which release the unmanaged IplImage structure.
The time of when garbage collector decides to dispose the image is not guaranteed. When working with large
image, it is recommend to call the Dispose() method to explicitly release the object. Alternatively, use
the using keyword in C# to limit the scope of the image
using (Image<Gray, Single> image = new Image<Gray, Single>(1000, 800))
{
... //do something here in the image
} //The image will be disposed here and memory freed
Getting or Setting Pixels
The safe (slow) way
Suppose you are working on an Image<Bgr, Byte>. You can obtain the pixel on the y-th row and x-th column by calling
Bgr color = img[y, x];
Setting the pixel on the y-th row and x-th column is also simple
img[y,x] = color;
The fast way
The Image pixels values are stored in the Data property, a 3D array. Use this property if you need to iterate through the pixel values of the image.
For example, in an grayscale image (Image<Gray, Byte>), instead of doing this:
Gray byCurrent = imageGray[x, y];
3 You would do this:
Byte byCurrent = imageGray.Data[x, y, 0];
Methods
Naming Convention
Method XYZ in Image<TColor, TDepth> class corresponds to the OpenCV function cvXYZ. For example,
Image<TColor, TDepth>.Not() function corresponds to cvNot function with the resulting image being
returned.
Method _XYZ is usually the same as Method XYZ except that the operation is performed inplace rather than
returning a value. For example, Image<TColor, TDepth>._Not() function performs the bit-wise inversion inplace.
Operators Overload
The operators + - * / has been overloaded (version > 1.2.2.0) such that it is perfectly legal to write codes like:
Image<Gray, Byte> image3 = (image1 + image2 - 2.0) * 0.5;
Generic Operation
One of the advantage of using Emgu CV is the ability to perform generic operations.
It's best if I demonstrate this with an example. Suppose we have an grayscale image of bytes
Image<Gray, Byte> img1 = new Image<Gray, Byte>(400, 300, new Gray(30));
To invert all the pixels in this image we can call the Not function
Image<Gray, Byte> img2 = img1.Not();
As an alternative, we can also use the generic method Convert available from the Image<TColor, TDepth> class
Image<Gray, Byte> img3 = img1.Convert<Byte>( delegate(Byte b) { return (Byte) (255-
b); } );
The resulting image img2 and img3 contains the same value for each pixel.
At first glance it wouldn't seems to be a big gain when using generic operations. In fact, since OpenCV already has
an implementation of the Not function and performance-wise it is better than the generic version of the
equivalent Convert function call. However, there comes to cases when generic functions provide the flexibility
with only minor performance penalty.
Let's say you have an Image<Gray, Byte> img1 with pixels set. You wants to create a single channel floating
point image of the same size, where each pixel of the new image, correspond to the old image, described with the following delegate
delegate(Byte b) { return (Single) Math.cos( b * b / 255.0); }
This operation can be completed as follows in Emgu CV
Image<Gray, Single> img4 = img1.Convert<Single>( delegate(Byte b) { return (Single)
Math.cos( b * b / 255.0); } );
The syntax is simple and meaningful. On the other hand, this operation in OpenCV is hard to perform since
equivalent function such as Math.cos is not available.
Drawing Objects on Image
The Draw( ) method in Image< Color, Depth> can be used to draw different types of objects, including fonts,
lines, circles, rectangles, boxes, ellipses as well as contours. Use the documentation and intellisense as a
guideline to discover the many functionality of the Draw function.
Color and Depth Conversion
4 Converting an Image<TColor, TDepth> between different colors and depths are simple. For example, if you
have Image<Bgr, Byte> img1 and you wants to convert it to a grayscale image of Single, all you need to do is
Image<Gray, Single> img2 = img1.Convert<Gray, Single>();
Displaying Image
Using ImageBox
Emgu CV recommends the use of ImageBox control for display purpose, for the following reasons
ImageBox is a high performance control for displaying image. Whenever possible, it displays a Bitmap that shares memory with the Image object, therefore no memory copy is needed (very fast).
The user will be able to examine the image pixel values, video frame rates, color types when the image is being displayed.
It is convenient to perform simple image operations with just a few mouse clicks.
Converting to Bitmap
The Image class has a ToBitmap() function that return a Bitmap object, which can easily be displayed on a
PictureBox control using Windows Form.
XML Serialization
Why do I care?
One of the future of Emgu CV is that Image<TColor, TDepth> can be XML serializated. You might ask why we need to serialization an Image. The answer is simple, we wants to use it in a web service!
Since the Image<TColor, TDepth> class implements ISerializable, when you work in WCF (Windows Communication Fundation), you are free to use Image<TColor, TDepth> type as parameters or return value of a web service.
This will be ideal, for example, if you are building a cluster of computers to recognize different groups of object and have a central computer to coordinate the tasks. I will also be useful if your wants to implement remote monitoring
software that constantly query image from a remote server, which use the Capture class in Emgu CV to capture
images from camera.
Conversion to XML
You can use the following code to convert an Image<Bgr, Byte> image to XmlDocument:
StringBuilder sb = new StringBuilder();
(new XmlSerializer(typeof(Image<Bgr, Byte>))).Serialize(new StringWriter(sb), o);
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(sb.ToString());
Conversion from XML
You can use the following code to convert a XmlDocument xDoc to Image<Bgr,Byte>
Image<Bgr, Byte> image = (Image<Bgr, Byte>)
(new XmlSerializer(typeof(Image<Bgr, Byte>))).Deserialize(new XmlNodeReader(xDoc));
Working with Matrices Depth as Generic Parameter
A Matrix is defined by its generic parameters depth. To create a 32bit floating point matrix, in Emgu CV it is done by calling
5 Matrix<Single> matrix = new Matrix<Single>(width, height);
Matrix Depth
The types of depth supported in Emgu CV 1.4.0.0 include
Byte
SByte
Single (float)
Double
UInt16
Int16
Int32 (int)
XML Serialization
Conversion to XML
You can use the following code to convert an Matrix<double> matrix to XmlDocument:
StringBuilder sb = new StringBuilder();
(new XmlSerializer(typeof(Matrix<double>))).Serialize(new StringWriter(sb), o);
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(sb.ToString());
Conversion from XML
You can use the following code to convert a XmlDocument xDoc to Matrix<double>
Matrix<double> matrix = (Matrix<double>)
(new XmlSerializer(typeof(Matrix<double>))).Deserialize(new XmlNodeReader(xDoc));
C# Image Processing Examples
Hello World - Version 1 We will start by the Hello World sample, written in C# using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Drawing;
...
//The name of the window
String win1 = "Test Window";
//Create the window using the specific name
CvInvoke.cvNamedWindow(win1);
//Create an image of 400x200 of Blue color
using (Image<Bgr, Byte> img = new Image<Bgr, byte>(400, 200, new Bgr(255, 0, 0)))
{
//Create the font
MCvFont f = new MCvFont(CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0);
//Draw "Hello, world." on the image using the specific font
img.Draw("Hello, world", ref f, new Point(10, 80), new Bgr(0, 255, 0));
6
//Show the image
CvInvoke.cvShowImage(win1, img.Ptr);
//Wait for the key pressing event
CvInvoke.cvWaitKey(0);
//Destory the window
CvInvoke.cvDestroyWindow(win1);
}
The above code will create an image of 400x200 with blue background color and the text "Hello, world" in green on the foreground. The image will be displayed a window named "Test Window".
Hello World - Version 2 Showing image using cvNamedWindow is good, but Emgu CV has an event better tool for the same purpose, that is, the ImageViewer class under Emgu.CV.UI namespace. using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using System.Drawing;
...
//Create an image of 400x200 of Blue color
using (Image<Bgr, Byte> img = new Image<Bgr, byte>(400, 200, new Bgr(255, 0, 0)))
{
//Create the font
MCvFont f = new MCvFont(CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0);
//Draw "Hello, world." on the image using the specific font
img.Draw("Hello, world", ref f, new Point(10, 80), new Bgr(0, 255, 0));
//Show the image using ImageViewer from Emgu.CV.UI
ImageViewer.Show(img, "Test Window");
}
7
Introduction The following article is designed to show new comers to EMGUcv how to set up a project step by step. This article is designed to make the process a little more user friendly. EMGU is a c# wrapper for OpenCV it differs from other wrappers as it written purely in c# and does not use unsafe code. EMGU opens the OpenCV (Open Source Computer Vision Library) library of programming functions mainly aimed at real time computer vision to C# developers. OpenCV was originally developed by Intel and now supported by Willow Garage. Current versions for both x86 and x64 architectures are available to download at their Sourceforge website. As EMGU is a wrapper for c++ code there are two types of Dynamic-link library’s (DLL’s) that are used. There are the EMGU ones with EMGU syntax always reference in the name and the opencv ones that vary. Setting up a first project is a common stumbling block for many newcomers and you are not alone. If you have downloaded the source code you will need to read “A Basic Program”. If you have copied an example from the EMGU extraction folder then take a look at The EMGU.CV.Invoke Exception and Troubleshooting section.
Assumed Knowledge It is assumed that a user has basic experience in c# and can generate a new c# project. It is assumed that each user has download the most recent update for their platform and has the HelloWorld Example running from the EMGU extraction folder\EMGU.Examples\Hello World.
The Basic Requirements As with any c# library there are some essential DLL’s that need referencing within your project. Start a new c# Windows Form Application and call it what you like. All DLL mentioned are in the EMGU extraction Folder\bin you will need to remember this. To start with you need to reference 3 EMGU DLL’s. Emgu.CV.dll Emgu.CV.UI.dll Emgu.Util.dll This is done by either right clicking on your project name or the References folder within the solution explorer. Go to Add Reference.
Or alternatively using the menu item Project > Add Reference. When the Add Reference window opens select the DLL’s listed above and click OK.
8
You will now see them listed in the References folder in the solution explorer window. These three DLL’s are the EMGU specific c# libraries mentioned previously. These alone will not allow you to use any of the image processing functions so please read the rest of the article. Now you need to reference these in any class of form that you will be using the code. The references you will use will depend on what you are doing in image processing terms. Look at the examples and these will have the ones your require. To get you started add the following to the top of the Form1.cs code behind.
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;
The Preferred Method Now for the more complicated c++ libraries, to load, display, access image data and do many of the more simpler functions you only need two files. Note that the "220" is the version number this will change according to updates (opencv_core***.dll, opencv_imgproc***.dll). opencv_core220.dll opencv_imgproc220.dll Now because these are wrapped c++ files you can’t reference them like you did with the EMGU files. You need to add these files to your project. This can be done in two ways, Right click on your project name within solution explorer (This is not the one starting with “Solution ‘Your Project Name’ ...” but the one bellow this). Go to Add > Existing Item using the standard open file dialog. Select the two files above, in case you forgot they are located in the EMGU extraction Folder\bin. Hint: if you can’t see .dll's make sure you change the file filter at the bottom right to Executable Files.
You will now be able to see your files within the solution explorer window. You will need to change there properties so select them both by holding down the Ctl key and left clicking on them (alternatively you can do this individually). Now look at Properties window, you will see 6 fields two of these will be filled with content. You are interested in the Copy to Output Directory. Change this from “Do not Copy” to “Copy always”.
9
If you are using the x64 compilations go to the x64 section and ensure you set up you project to compile to a x64 architecture other than that you are ready to start image processing. The reason this is the preferred method is that now, if you change from Debug to Release these files will always be available to your program and no errors will occur. Jump to the reading and displaying an image section A Basic Program to start you off.
The Less Preferred Method While not proffered this is often the simplest and if you have a complex project architecture this can prevent the solution explorer from looking very messy. Simply navigate in windows explorer to the EMGU extraction folder\bin copy the relevant dll files opencv_core220.dll and opencv_imgproc220.dll to your project bin\Debug folder or to bin\Release folder. This will change with x64 versions as it will be the bin\x64\Debug folder or alternative Release folder. While the benefits are not so clear here, imagine if you require all the opencv DLL files then you will have an extra 34 files within the solution explorer however, it is rare this will be the case.
x64 Architecture and the EMGU.CV.Invoke Exception If you are running an x64 system or designing for them you will have to download separate DLL’s. The steps on forming a project are identical however you will need to change an additional build parameter. Right click on your project file in the solution explorer and select “Properties” at the bottom. Select the “Build” tab from the ribbon bar on the right of this window. There will be an option for Platform Target: with a drop down menu change this from x86 to x64.
10
Hint: If you are using the express version of visual studio you may not see the x64 option in such a case go to menu option Tools > Options. In this window using the arrows to the left hand side to expand and collapse options. Select “Projects and Solutions” and select the Show advanced build configurations check box.
This will now allow the compilation to run if this is not done correctly. As soon as you access any EMGU code an
exception will be thrown ‘EMGU.CV.Invoke’ through an exception with the ‘InnerException’ "An attempt was
made to load a program with an incorrect format....”.
A Basic Program To get you started a simple program that loads an image and displays it in a picture box has been provided and a little bit more of an advanced one that will show how to access image data and convert between image types. Only x64 Versions are currently available, x86 will be provided shortly. If you have downloaded the sample code you will start with 3 warnings for the references not being found. Expand the References folder within the solution explorer delete the 3 with yellow warning icons and Add fresh references to them, the steps of which are available The Basic Requirements section.
There has been a button item and a picturebox item added to the main form. There default names have not
been changed. When we click on the button we wish to open a file dialog select and image and have it displayed in
the picturebox.
Double click on the button and add the following code:
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog Openfile = new OpenFileDialog();
if (Openfile.ShowDialog() == DialogResult.OK)
{
Image<Bgr, Byte> My_Image = new Image<Bgr, byte>(Openfile.FileName);
pictureBox1.Image = My_Image.ToBitmap();
}
11
}
The code is very simple an OpenFileDialog called 'Openfile' is used to select and image file. This image is then
read into an colour Image object called 'My_Image'. The image is displayed by assigning the Image property of
the picturebox. This requires a Bitmap and by calling the .ToBitmap() function of 'My_Image' this is
achieved. This is incredibly simple to achieve once the correct process has been taken in setting up the project. An alternative to the Picturbox item is made available through the EMGU.CV.UI library and is used in the examples. Please visit http://www.emgu.com/wiki/index.php/Add_ImageBox_Control to learn how to add this control to visual studio should you wish to use it.
A Little More Image Processing The slightly more advanced source code project will have the same warnings as described in A Basic Program has been provided. The references will need replacing. In this program there is a demonstration of converting
an Image from colour to greyscale and accessing the Data of individual pixels. While the methods of
suppressing the image spectrum data is not the most efficient it is a good example on accessing the
image Data property.
A little on Converting Images Image conversion in EMGU can be complex. In the example program a Bgr colour image is converted
the Gray or grayscale.
Image<gray,byte> gray_image = My_Image.Convert<gray,byte>();
However you will eventually want to use a different depth (Tdepth) of image rather than Byte. The problem with
this method is you can only convert a depth or colour once per call. Lets say we wish to convert from Image<bgr,byte> to Image<gray,double> you would have to use the following syntax.
Image<Gray,byte> gray_image = My_Image.Convert<Gray,byte>();
Image<Gray,double> gray_image = My_Image.Convert<Gray,double>();
//or alternatively in one line
Image<Gray,> gray_image = My_Image.Convert<Gray,byte>().Convert<Gray,double>();
//alternatively
Image<Gray,Byte> gray_image =
My_Image.Convert<Bgr,double>().Convert<Gray,double>();
Accesing Image Data There are a few ways of accessing image data and assigning values to it. There are two methods available, direct access using the Image Data property of a more remote access. Both are demonstrated here. Note it is important to respect the image spectrum depth when accessing the Data property. A grayscale image will have a depth of one so will be reference as [x,y,0] however a colour image as a depth of 3, [x,y,0], [x,y,1] & [x,y,2] representing the
Blue, Green & Red spectrums respectively (Bgr).
Lets say we wish to assign a value to a pixel at position [0,0] a value. Using the easier remote method we can use:
//Colour Image
My_Image[0, 0] = new Bgr(Color.Red);
//Gray Image
gray_image[0, 0] = new Gray(200);
Or we use the Data property
//Colour Image
12
Color R = Color.Red;
My_Image.Data[0,0,2] = R.R; //Write to the Red Spectrum
My_Image.Data[0,0,1] = R.G; //Write to the Green Spectrum
My_Image.Data[0,0,0] = R.B; //Write to the Blue Spectrum
//Gray Image
gray_image[0, 0] = new Gray(200);
So writing to a pixel is fairly simple but what about reading a pixel value.
//Colour Image
Bgr my_Bgr = My_Image[0, 0];
//Gray Image
Gray my_Gray = gray_image[0, 0];
Now in many cases you will not want to work with “Bgr” or “Gray” so converting them is important.
//BGR to Color
Color my_colour = Color.FromArgb((int)value.Red, (int)value.Blue, (int)value.Green);
//Gray to int
int my_intensity = (int) my_Gray.Intensity;
You will notice that each value is cast to an integer to allow data loss this is because the intensities are stored
naturally as doubles. However in this case the easier method is accessing the ImageData property. If you wish to
work with the image data there is not a requirement to constantly convert between Gray and integers etc. You can
access the image Data directly and use that.
//Colour
Color my_colour = Color.FromArgb(My_Image.Data[0, 0, 0],
My_Image.Data[0, 0, 1], My_Image.Data[0, 0, 2]);
//Gray Image
int my_intensity = gray_image.Data[0, 0, 0];
Much simpler and far easier to work with when processing the image Data within a loop. To examine how to
implement a loop please download the Little More Image Processing source code.
The DllNotFound Exception and Troubleshooting 0x8007007E Now at some point you are going to receive and error "Unable to load DLL...... (Exception from HRESULT: 0x8007007E)”. You need to read the Message section circled in red bellow.
13
If the exception is a EMGU.CV.Invoke Exception, chances are you are not targeting the correct platform for your
build. See the section regarding x64 Architecture for details. Now if you’ve progressed through to an advanced image processing method or simply have copied an example to an alternative location than the EMGU extraction folder you will possibly be seeing one of the following errors.
Unable to load DLL 'opencv_highgui220': The specified module could not be found. (Exception from HRESULT: 0x8007007E) Usually caused when you are trying to get a image from a web camera. The solution to this is extremely simple. As discussed in The Basic Requirements section you will need to either copy theopencv_highgui220.dll to the output directory or the more preferred method of adding the file to your project as an existing file and then changing its property “Copy to Output Directory” to “Copy always”. Look back at this section for reference if required.
Unable to load DLL 'cvextern': The specified module could not be found. (Exception from HRESULT: 0x8007007E) This error has a little more of a substantial solution. The cvextern.dll error can not be fixed by simply adding the this one file in fact this file requires all of the files listed bellow to correctly execute. As discussed in The Basic Requirements section you will need to either copy files to the output directory or the more preferred method of adding the files to your project as an existing file and then changing each of their properties “Copy to Output Directory” to “Copy always”. Look back at this section for reference if required. Note that the "220" is the version number this will change according to updates. cudart64_32_16.dll cufft64_32_16.dll cvextern.dll npp64_32_16.dll opencv_calib3d220.dll opencv_contrib220.dll opencv_core220.dll opencv_features2d220.dll opencv_flann220.dll opencv_gpu220.dll opencv_highgui220.dll opencv_imgproc220.dll opencv_legacy220.dll opencv_ml220.dll opencv_objdetect220.dll opencv_video220.dll Any other Unable to load DLL ‘...’ errors can be fixed by attempting the same process an loading the relevant listed DLLs into your project. If you still get stuck than feel free to ask the community for help.
14
System.TypeInitializationException: Convertion from Image<Emgu.CV.Structure.Bgr*,System.Byte*> to Image<Emgu.CV.Structure.Structure.Bgr*,System.Byte*> is not supported by OpenCV Where * is the the relavent image depth or data type. This error is thrown up in version 2.3.* onwards and is caused by the programs inability to access opencv_imgproc***.dll or opencv_core***.dll even though they are present in the output "bin" directory. There are two solutions, adding them to the project and set there properties to copy always as they are the two key files. Or by replacing the current ones in the Bin folder with new copies can also solve the problem. If both methods fail then there may be a problem with the build so download a new copy from SourceForge and try again. I hope this article sets you on the right path, Thanks for reading.
Camera Capture in 7 lines of code This example requires Emgu CV 1.5.0.0 Excluding the using statements in the beginning, only 7 lines of code are required to perform a camera capture loop. using Emgu.CV;
using Emgu.CV.UI;
using Emgu.CV.Structure;
using System.Drawing;
using System.Windows.Forms;
...
ImageViewer viewer = new ImageViewer(); //create an image viewer
Capture capture = new Capture(); //create a camera captue
Application.Idle += new EventHandler(delegate(object sender, EventArgs e)
{ //run this until application closed (close button click on image viewer)
viewer.Image = capture.QueryFrame(); //draw the image obtained from camera
});
viewer.ShowDialog(); //show the image viewer
Shape (Triangle, Rectangle, Circle, Line) Detection in CSharp
This project is part of the Emgu.CV.Example solution
Shape Detection In this tutorial, we demonstrate how to perform Hough Line and Circle detection using Emgu CV, as well as using the Contour class to detect Triangles and Rectangles in the image. The "pic3.png" file from the OpenCV sample folder is used here.
pic3.png from opencv
Source Code //Load the image from file
Image<Bgr, Byte> img = new Image<Bgr, byte>(fileNameTextBox.Text).Resize(400, 400,
true);
//Convert the image to grayscale and filter out the noise
Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp();
15
Gray cannyThreshold = new Gray(180);
Gray cannyThresholdLinking = new Gray(120);
Gray circleAccumulatorThreshold = new Gray(120);
CircleF[] circles = gray.HoughCircles(
cannyThreshold,
circleAccumulatorThreshold,
5.0, //Resolution of the accumulator used to detect centers of the circles
10.0, //min distance
5, //min radius
0 //max radius
)[0]; //Get the circles from the first channel
Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking);
LineSegment2D[] lines = cannyEdges.HoughLinesBinary(
1, //Distance resolution in pixel-related units
Math.PI / 45.0, //Angle resolution measured in radians.
20, //threshold
30, //min Line width
10 //gap between lines
)[0]; //Get the lines from the first channel
#region Find triangles and rectangles
List<Triangle2DF> triangleList = new List<Triangle2DF>();
List<MCvBox2D> boxList = new List<MCvBox2D>();
using (MemStorage storage = new MemStorage()) //allocate storage for contour
approximation
for (Contour<Point> contours = cannyEdges.FindContours(); contours != null;
contours = contours.HNext)
{
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05,
storage);
if (contours.Area > 250) //only consider contours with area greater than 250
{
if (currentContour.Total == 3) //The contour has 3 vertices, it is a
triangle
{
Point[] pts = currentContour.ToArray();
triangleList.Add(new Triangle2DF(
pts[0],
pts[1],
pts[2]
));
}
else if (currentContour.Total == 4) //The contour has 4 vertices.
{
#region determine if all the angles in the contour are within the range
of [80, 100] degree
bool isRectangle = true;
Point[] pts = currentContour.ToArray();
LineSegment2D[] edges = PointCollection.PolyLine(pts, true);
for (int i = 0; i < edges.Length; i++)
{
double angle = Math.Abs(
edges[(i + 1) % edges.Length].GetExteriorAngleDegree(edges[i]));
if (angle < 80 || angle > 100)
{
16 isRectangle = false;
break;
}
}
#endregion
if (isRectangle) boxList.Add(currentContour.GetMinAreaRect());
}
}
}
#endregion
originalImageBox.Image = img;
#region draw triangles and rectangles
Image<Bgr, Byte> triangleRectangleImage = img.CopyBlank();
foreach (Triangle2DF triangle in triangleList)
triangleRectangleImage.Draw(triangle, new Bgr(Color.DarkBlue), 2);
foreach (MCvBox2D box in boxList)
triangleRectangleImage.Draw(box, new Bgr(Color.DarkOrange), 2);
triangleRectangleImageBox.Image = triangleRectangleImage;
#endregion
#region draw circles
Image<Bgr, Byte> circleImage = img.CopyBlank();
foreach (CircleF circle in circles)
circleImage.Draw(circle, new Bgr(Color.Brown), 2);
circleImageBox.Image = circleImage;
#endregion
#region draw lines
Image<Bgr, Byte> lineImage = img.CopyBlank();
foreach (LineSegment2D line in lines)
lineImage.Draw(line, new Bgr(Color.Green), 2);
lineImageBox.Image = lineImage;
#endregion
Result
Creating First Emgu CV Project
Introduction
17 In the last article we read about Starting with Emgu CV, now here we will start our first Emgu CV project. Emgu CV is
not so difficult; all we have to do is to add certain references and make use of Emgu Controls. Let's get started.
Let's start creating a blank Windows Forms application.
You will get a new project created for you, before starting further enable "show all settings" under tools, this
enables many features like form designer layout, snap to grid and many others.
Now let's start. The first thing we will do is to Add References. Browse for the Emgu bin folder (by default it is
located at C:\Emgu\emgucv-windows-x86 2.3.0.1416\bin ), in the bin folder there must be some dlls add all those
starting with "Emgu.CV" (choose only one among Emgu.CV.DebuggerVisualizers.VS2008.dll
and Emgu.CV.DebuggerVisualizers.VS2010.dll depending on the Visual Studio you are using, in my case it
is Emgu.CV.DebuggerVisualizers.VS2010.dll)
18
Now we need to add some existing items. Go to "Project" > "Add Existing Items" and now again browse for the bin
directory of Emgu CV and this time choose all the dll files starting with "opencv_", these dll files are required each
time the output is generated via Emgu; that is why we added them to our project directory, we will also change
there the property so that they get copied always to the output folder. So, select all the DLLs added and select
properties and change the "Copy to Output Directory" to "Copy Always".
We already have added the Emgu custom controls to our toolbox, now let's design our form, we will be using two
ImageBox (Emgu Control), one Button and a Textbox, design the form as below.
19
Coding
Now go to the form1.cs code view, and add the following namespaces:
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
Next create some member variables :
Capture capturecam = null; //instance for capture using webcam
bool CapturingProcess = false; //boolean stating the capturing process status
Image<Bgr, Byte> imgOrg; //image type RGB (or Bgr as we say in Open CV)
Image<Gray, Byte> imgProc; //processed image will be grayscale so a gray image
Now it's time to add a "form load event", we will start capturing via webcam under it.
capturecam = new Capture();
This will associate the default webcam with the capturecam object.
20
We have added the association to the capture object in the try/catch block to avoid the error if the webcam is
already in use.
We added an event handler to "Application.Idle", so that it performs the task when the application is idle, and the
task is to get the next frame. "ProcessFunction" is called at every idle state of the application.
"QueryFrame" gets the next frame from the webcam, if it is null it means there is some problem and hence we stop
our app there.
The "InRange" function takes two parameters, the minimum and maximum values of the Bgr range.
"SmoothGaussian" applies the Gaussian smoothing with the x,y length = 9, we can pass other parameters for x and
y also.
Now let's come to the coding part of the "playorpause" button:
21
This is the simplest part, it checks the boolean value of CapturingProcess and changes the button text
correspondingly and stops the streaming from the webcam.
Sample Output
ANN MLP (Neural Network) in CSharp What is an Artificial Neural Network (ANN) According to wikipedia,
An artificial neural network (ANN), usually called "neural network" (NN), is a mathematical model or computational model based on biological neural networks. It consists of an interconnected group of artificial neurons and processes information using a connectionist approach to computation. In most cases an ANN is an adaptive system that changes its structure based on external or internal information that flows through the network during the learning phase.
In more practical terms neural networks are non-linear statistical data modeling tools. They can be used to model complex relationships between inputs and outputs or to find patterns in data. OpenCV implements Multi-Layer Perceptrons Neural Network, hence the name ANN_MLP.
Source Code using System.Drawing;
using Emgu.CV.Structure;
using Emgu.CV.ML;
using Emgu.CV.ML.Structure;
...
22
int trainSampleCount = 100;
#region Generate the traning data and classes
Matrix<float> trainData = new Matrix<float>(trainSampleCount, 2);
Matrix<float> trainClasses = new Matrix<float>(trainSampleCount, 1);
Image<Bgr, Byte> img = new Image<Bgr, byte>(500, 500);
Matrix<float> sample = new Matrix<float>(1, 2);
Matrix<float> prediction = new Matrix<float>(1, 1);
Matrix<float> trainData1 = trainData.GetRows(0, trainSampleCount >> 1, 1);
trainData1.SetRandNormal(new MCvScalar(200), new MCvScalar(50));
Matrix<float> trainData2 = trainData.GetRows(trainSampleCount >> 1, trainSampleCount,
1);
trainData2.SetRandNormal(new MCvScalar(300), new MCvScalar(50));
Matrix<float> trainClasses1 = trainClasses.GetRows(0, trainSampleCount >> 1, 1);
trainClasses1.SetValue(1);
Matrix<float> trainClasses2 = trainClasses.GetRows(trainSampleCount >> 1,
trainSampleCount, 1);
trainClasses2.SetValue(2);
#endregion
Matrix<int> layerSize = new Matrix<int>(new int[] { 2, 5, 1 });
MCvANN_MLP_TrainParams parameters = new MCvANN_MLP_TrainParams();
parameters.term_crit = new MCvTermCriteria(10, 1.0e-8);
parameters.train_method = Emgu.CV.ML.MlEnum.ANN_MLP_TRAIN_METHOD.BACKPROP;
parameters.bp_dw_scale = 0.1;
parameters.bp_moment_scale = 0.1;
using (ANN_MLP network = new ANN_MLP(layerSize,
Emgu.CV.ML.MlEnum.ANN_MLP_ACTIVATION_FUNCTION.SIGMOID_SYM, 1.0, 1.0))
{
network.Train(trainData, trainClasses, null, null, parameters,
Emgu.CV.ML.MlEnum.ANN_MLP_TRAINING_FLAG.DEFAULT);
for (int i = 0; i < img.Height; i++)
{
for (int j = 0; j < img.Width; j++)
{
sample.Data[0, 0] = j;
sample.Data[0, 1] = i;
network.Predict(sample, prediction);
// estimates the response and get the neighbors' labels
float response = prediction.Data[0,0];
// highlight the pixel depending on the accuracy (or confidence)
img[i, j] = response < 1.5 ? new Bgr(90, 0, 0) : new Bgr(0, 90, 0);
}
}
}
// display the original training samples
for (int i = 0; i < (trainSampleCount >> 1); i++)
{
PointF p1 = new PointF(trainData1[i, 0], trainData1[i, 1]);
img.Draw(new CircleF(p1, 2), new Bgr(255, 100, 100), -1);
PointF p2 = new PointF((int)trainData2[i, 0], (int)trainData2[i, 1]);
img.Draw(new CircleF(p2, 2), new Bgr(100, 255, 100), -1);
}
Emgu.CV.UI.ImageViewer.Show(img);