Tutorial
Namespace
Emgu
All libraries implemented by Emgu® will be put under the namespace of Emgu.
Emgu.CV
The Emgu.CV namespace implement wrapper functions for OpenCV. To use this namespace in your code, it is recommended to include
using Emgu.CV;
in the begining of your C# code.
Function Mapping - Emgu.CV.CvInvoke
The CvInvoke class provides a way to directly invoke OpenCV function within .NET languages. Each method in this class corresponds to a function in OpenCV of the same name. For example, a call to
IntPtr image = CvInvoke.cvCreateImage(new MCvSize(400, 300), CvEnum.IPL_DEPTH.IPL_DEPTH_8U, 1);
is equivalent to the following function call in C
IplImage* image = cvCreateImage(cvSize(400, 300), IPL_DEPTH_8U, 1);
Both of which create a 400x300 of 8-bit unsigned grayscale image .
Enumeration Mapping - Emgu.CV.CvEnum
The CvEnum namespace provides direct mapping to opencv enumerations. For example, CvEnum.IPL_DEPTH.IPL_DEPTH_8U
is equivalent to the value in opencv IPL_DEPTH_8U
. Both of which has the value of 8
.
Structure Mapping - Emgu.CV.Mxxx
This type of structure is a direct mapping to opencv structures. For example
MIplImage
is equivalent toIplImage
structure in OpenCVMCvSize
is equivalent toCvSize
structureMxxxx
is equivalent toxxxx
structure
Working with images
Generic Support
An Image is defined by its generic parametes: 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(C color, Image<Gray, Byte> mask)
function in Image<C, D> 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 attemps 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
, we suggest to construct a Image< Color, Depth> object instead. There are serveral advantage of using the Managed Image<Color, Depth> class, among those are
- Memory is automatically released when the garbage collector dispose the Image< Color, Depth> Object
- Image< Color, Depth> class contains advanced method that is not available on OpenCV, for example, generic operation
To create an 480x320 image with Bgr color and 8-bit unsigned value, in C# you can call
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>(480, 320);
Note that the image initialized this way contains random pixel values, if you wants to specify the background value of the image, let's say in Blue, in C# you write
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>(480, 320, new Bgr(255, 0, 0));
Creating image from file is also simple, in C# just call
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>("MyImage.jpg");
assuming the image file is call "MyImage.jpg"
Image Color
The first generic parameter of the Image class specific the color of the image type, for example Image<Gray, ...> img1;
tells that img1
is a single channel gray color image.
Color Types supported in Emgu CV includes:
- Gray
- Bgr (Blue Green Red)
- Hsv (Hue Satuation Value)
- Hls (Hue Lightness Satuation)
- Lab (CIE L*a*b*)
- Luv (CIE L*u*v*)
- Xyz (CIE XYZ.Rec 709 with D65 white point)
- Ycc (YCrCb JPEG)
Automatic Garbage Collection
The Image class, implemented in C# will automatically take care of the memory management and garbage collection.
Once the garbage collector decided that there is no more reference to the Image object, it will call the Disposed
method, which involves the FreeUnmanagedObjects
method that release the unmanaged IplImage using CvInvoke.cvReleaseImage
.
The time of which garbage collector decides to dispose the image is not gurantee, therefore, 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
Image Depth
Image Depth is specified using the second generic parameter Depth
Available Color Depths are:
- Byte
- Single (float)
Methods
Naming Convention
- Method
XYZ
in Image< Color, Depth> class corresponse to the OpenCV functioncvXYZ
. For example, Image< Color, Depth>.Not() function corresponse tocvNot
function with the resulting image being returned. - Method
_XYZ
is usually the same as MethodXYZ
except that the operation is performed inplace rather than returning a value. For example, Image< Color, Depth>._Not() function performs the bitwise inversion inplace.
Generic Operation
One of the advantage of using Emgu CV is the ability to perform generic operations.
It's best if I demostrate this using with example. Suppose we have an gray scale 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 function using plain old CvInvoke
Image<Gray, Byte> img2 = img1.Not();
As an alternative, we can also use the generic method Convert
available from the Image< Color, Depth> 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 equailent 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. and you wants to create a single channel float point image of the same size, when each pixel of the new image, corresponse to the old image, can be describe in 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); } );
Which is simple and meaningfull. 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
Converting an Image< Color, Depth> 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>();
There is no need to worry about the color convertion code as it is handled by the Emgu CV library.
XML serialization
One of the future of Emgu CV is that Image< Color, Depth> 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< Color, Depth> class implements ISerializable, when you work in WCF (Windows Communication Fundation), you are free to use Image< Color, Depth> 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 recongnize different groups of object and have a center computer to coordinate the tasks. I will also be useful if your wants to implement remote monitoring software that constainly query image from a remote server, which use the Capture
class in Emgu CV to capture images from camera.
Code Documentation
Xml Documentation
Documentation is emmbedded in the code using xml format, which can then be compiled as HTML documentation using Sandcastle.
Intellisense in Visual Studio
If you are using Visual Studio as your development tools, you will have intellisense support when developping Emgu CV applications. For example, if you wants to create an image directly using cvCreateImage function, which is wrapped by the CvInvoke Class, just type CvInvoke.
and a list of functions belongs to CvInvoke
class is displayed along with a description for each of the function. Since you are creating an image, select the cvCreateImage
function
The list of parameters for this function will be displayed as well as a description for each of the parameters.
Examples
Hello, World
We will start by the Hello World sample, written in C#
String win1 = "Test Window"; //The name of the 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)))
using (Font f = new Font(CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0)) //Create the font
{
//Draw "Hello, world." on the image using the specific font
img.Draw("Hello, world", f, new Point2D<int>(10, 80), new Bgr(0, 255, 0));
CvInvoke.cvShowImage(win1, img.Ptr); //Show the image
CvInvoke.cvWaitKey(0); //Wait for the key pressing event
CvInvoke.cvDestroyWindow(win1); //Destory the window
}
The above code will create an image of 400x200 with blue background color and the String "Hello, world" in green on the forground. The image will be displayed a window named "Test Window".