Tutorial
Namespace
Emgu
All libraries provided by Emgu™ use the namespace Emgu.
Emgu.CV
The Emgu.CV namespace implement wrapper functions for OpenCV
Emgu.CV.CvInvoke class
This class is written to provided a way to directly invoke opencv function within .NET languages. Each method in this class corresponds to the same function in opencv. For example, a call to
CvInvoke.cvCreateImage(new MCvSize(400, 300), CvEnum.IPL_DEPTH.IPL_DEPTH_8U, 1);
is equivalent to calling the function in opencv
cvCreateImage(cvSize(400, 300), IPL_DEPTH_8U, 1);
Both of which create a 400x300 single-channel image of 8-bit depth.
Emgu.CV.CvEnum namespace
This 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 equals 8
.
Emgu.CV.Mxxx Structure
This type of structure is a direct mapping to opencv structures. For example
MIplImage
is equivalent toIplImage
structure in opencvMCvMat
is equivalent toCvMat
structureMxxxx
is equivalent toxxxx
structure
Working with images
Creating Image
Although it is possible to create image by calling CvInvoke.cvCreateImage
, we suggest using the generic class Image< Color, Depth> for image creation. 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
Image Color is specified using the first generic parameter Color
Available Color Types are:
- Gray
- Bgr (Blue Green Red)
- Hsv (Hue Satuation value)
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 are usually corresponse to cvXYZ
function in OpenCV. For example, Image< Color, Depth>.NOT() Function corresponse to cvNot
function with the resulting Image being returned.
- Method
_XYZ
is usually the equivalent function as XYZ
only that the operation is performed inplace rather than returning any value
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 provides the flexibility with minor performance cost.
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.
Examples
Hello, World
We will start by the Hello World sample, written in C#
String win1 = "Test Window"; //The name of the window
CvInvoke.cvNamedWindow(win1); //Create the window using the specific name
using (Image<Bgr, Byte> img = new Image<Bgr, byte>(400, 200, new Bgr(255, 0, 0))) //Create an image of 400x200 of Blue color
using (Font f = new Font(CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0)) //Create the font
{
img.Draw("Hello, world", f, new Point2D<int>(10, 80), new Bgr(0, 255, 0)); //Draw "Hello, world." on the image using the specific font
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 charaters "Hello, world" on the forground and displayed the image in a window call "Test Window".