Você está na página 1de 23

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) (255b); } ); 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"); }

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 librarys (DLLs) 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 DLLs 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 DLLs. 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 DLLs listed above and click OK.

You will now see them listed in the References folder in the solution explorer window. These three DLLs 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 cant 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 cant 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.

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 DLLs. 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 Image Data 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 youve 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 using using using ... System.Drawing; Emgu.CV.Structure; Emgu.CV.ML; 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);

23

Result

Você também pode gostar