Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

A .NET Approach to EmguCV

4.25/5 (3 votes)
25 Feb 2015CPOL4 min read 32.3K   88  
Complete guide for beginner to setup EmguCV project and run first program in Visual Studio

Introduction

This tip is designed for beginners with a little understanding of C# and no understanding of EmguCV. First, what is EmguCV? EmguCV is a collection of libraries written in C#, C++, VB and other languages. Is it similar to famous APIs like Matlab or OpenCV? No!

Background

In simple words, EmguCV is just a wrapper which calls OpenCV methods from supported languages like C#, VB, etc. Unlike other wrappers, it doesn't use unsafe code and is written purely in C# which makes EmguCV way different, better and more efficient than others.

Requirements

  1. C#
  2. Visual Studio (2013 used in this tip)
  3. EmguCV libraries Installer (Link, FileSize = 214MB approx, you can use the latest if you want)

Using the Code

After installing emguCV libraries via Installer, go to your My Computer->Properties->Advanced System Settings->Advanced->Environment Variables. In System Variable Groupbox, select Path and click Edit. In the textbox, add a semi-colon(;) at the end of text and add the path of the emguCV libraries (X\emgucv\bin\x86) where X = "Directory where your EmguCV libraries are installed". Click OK to confirm.

Image 1

Create a new project under File->New->Project and select WPF Application from project wizard.

You need three files to began working on Emgu CV located under "X\emgucv\bin\" where X = "Directory where your EmguCV libraries are installed".

  • Emgu.CV.dll
  • Emgu.CV.UI.dll
  • Emgu.Util.dll

After Project creation, right-click on References in Solution Explorer and click on Add Reference. In Add Reference window, browse and select the above three listed DLLs under specified directory (see above) and click OK to add them to your project references. If everything goes well, your solution explorer should look like this:

Image 2

Add the following references to your MainWindows.xaml.cs file to include Emgu CV references.

C#
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;

and add the following code to display an image.

Note: Add System.Drawing.dll (if not included) as reference provided in Add Reference->Assemblies->Check System.Drawing and click OK.

Drag and drop an image to your solution explorer(project) and then right-click to select properties. Set the Build Action to Content Type to Content and Copy to Output Directory Copy If Newer to copy image while building project to use it at runtime. Till now, Environment variables and references added.

Let's Run Your Neurons (Coding...)

Alright! Let's code.

In MainWindow.xaml:

XML
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="270*"/>
        <RowDefinition Height="60"/>
    </Grid.RowDefinitions>
    <Image x:Name="cv_image" Grid.Row="0" />
    <StackPanel HorizontalAlignment="Center"
    Orientation="Horizontal" Grid.Row="1" Margin="10">
        <Button Content="Browse" Width="70"
        Height="30" Click="Button_Click"></Button>
    </StackPanel>
</Grid>

In MainWindow.xaml.cs:

C#
public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Filter = "All Image Files (*.png,*.jpg,*.bmp)|*.png;*.jpg;*.bmp";
            var result = openFileDialog.ShowDialog();
            if(result.Value == true)
            {
                var image = new Image<Bgr, Byte>(openFileDialog.FileName);
                cv_image.Source = BitmapSourceConvert.ToBitmapSource(image);
            }
        }
    }
    //Using unsafe c# code to convert System.Drawing.Bitmap to WPF Media.Imaging
    public static class BitmapSourceConvert
    {
        [DllImport("gdi32")]
        private static extern int DeleteObject(IntPtr o);

        public static BitmapSource ToBitmapSource(IImage image)
        {
            using (System.Drawing.Bitmap source = image.Bitmap)
            {
                IntPtr ptr = source.GetHbitmap();

                BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    ptr,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

                DeleteObject(ptr);
                return bs;
            }
        }
    }

The code is pretty simple. In XAML file, there is a Root grid with rows. Image with name 'cv_image' is in the first row and a stackpanel in the second row which has a 'Browse' button to open file with an 'Click' event handler which calls Button_Click event in code behind. In Button_Click method, there is an OpenFileDialog with filter equal to Images extension. After selecting image from dialog, Image<Bgr, Byte>( "Image File Name" ) method will load the image in specified (RGB) format.

Handling emgu.cv.cvinvoke Exception

If you haven't faced emgu.cv.cvinvoke exception on build, then skip this step.

Current versions of Emgu CV support both x86 and x64 architectures you have to specify the architecture in order to build the program successfully on x64. To switch between x86 and x64, you have to set the architecture manually.

Right-click on your Project->Properties and then select Build from left sidebar. In the Platform Target Combo Box, select x86 to switch to x86 architecture or x64 for 64-bit. (For x64, you might need x64 emguCV libraries, which you can copy from the installer extracted libraries.

Image 3

Build and run your project. Hope it will do the trick.

Result

Image 4

Conversion to Color Spaces

An image consists of picture elements called pixels. Human eye can detect 3 colors, i.e., Red, Green, Blue. So, the colored image is made up of three channels i.e RGB or BGR (in reverse). There are other color spaces like HSV, Lab, YCbCr, YUV, all of them are made up of three channels but channels differ in each type of color space. Grayscale image consist of only one channel, i.e., Grayshade having values of each pixel ranging from 0-255 of gray color.

Update your XAML code with the following code:

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="270*"/>
            <RowDefinition Height="60"/>
        </Grid.RowDefinitions>
        <Image x:Name="cv_image" Grid.Row="0" />
        <StackPanel HorizontalAlignment="Center" 
        Orientation="Horizontal" Grid.Row="1" Margin="15">
            <Button Content="Browse" Width="70" 
            Click="Button_Click"></Button>
            <Border Width="20" />
            <TextBlock VerticalAlignment="Center">Convert to: </TextBlock>
            <Border Width="5" />
            <ComboBox x:Name="comboBox_colorspace" SelectedIndex="0" 
		Width="80" SelectionChanged="ComboBox_SelectionChanged" 
		HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
                <ComboBoxItem Content="RGB" />
                <ComboBoxItem Content="YCbCr" />
                <ComboBoxItem Content="Lab" />
                <ComboBoxItem Content="Grayscale" />
            </ComboBox>
        </StackPanel>
    </Grid>

In MainWindow.xaml.cs:

C#
Image<Bgr, Byte> image = null;
//On browse button click
private void Button_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
    openFileDialog.Filter = "All Image Files (*.png,*.jpg,*.bmp)|*.png;*.jpg;*.bmp";
    //open file dialog
    var result = openFileDialog.ShowDialog();
    if (result.Value == true)
    {
        //load image - selected file path
        image = new Image<Bgr, Byte>(openFileDialog.FileName);
        cv_image.Source = BitmapSourceConvert.ToBitmapSource(image);
        //set comboBox to default color space RGB
        comboBox_colorspace.SelectedIndex = 0;
    }
}
//if combox box selection changed - event handler
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var comboBox = (ComboBox)sender;
    if (comboBox == null || image == null)
        return;
    ConvertTo(((ComboBoxItem)comboBox.SelectedItem).Content.ToString());
}
//Convert to selected colorspace
private void ConvertTo(string colorspace)
{
    switch(colorspace)
    {
        case "RGB":
            cv_image.Source =
                BitmapSourceConvert.ToBitmapSource(image.Convert<Bgr, Byte>());
            break;
        case "Grayscale":
            cv_image.Source =
                BitmapSourceConvert.ToBitmapSource(image.Convert<Gray, Byte>());
            break;
        case "YCbCr":
            cv_image.Source =
                BitmapSourceConvert.ToBitmapSource(image.Convert<Ycc, Byte>());
            break;
        case "Lab":
            cv_image.Source =
                BitmapSourceConvert.ToBitmapSource(image.Convert<Lab, Byte>());
            break;
        default:
            break;
    }
}

On selection changed event of combobox, image.Convert<[Color Space Name], [Type]>() method will convert the image into other selected color space.

C#
*[Color Space Name] = Ycc, Hsv, Lab, Gray, Bgr and Type = Byte, int, double*

Result: (To grayscale Conversion)

Image 5

A Little More Coding...

Changing the Color of Patch in Image

As described above, RGB, YUV, HSV, Lab are 3-dimensional (3 Channels) colorspaces, whereas grayscale is a 2-dimensional color space (1 Channel). If we want to change color of (let's say) first 5 rows of image, then replace color values of first 5 rows of 3 components of image.

C#
//convert first pixel color of first channel to black
image.Data[0,0,0] = 0;

To assign green color to first pixel with 3 channels (Colored Image):

C#
//get green color
Color G = Color.Green;

image.Data[0,0,0] = G.B;
image.Data[0,0,1] = G.G;
image.Data[0,0,2] = G.R;
private void ConvertToBlack(int rows)
        {
            for(int row=0;row<rows;row++)
            {
                //Iterate through channels of image-if Gray then 1, if colored then 3
                for (int channel = 0; channel < image.NumberOfChannels;channel++ )
                    for (int col = 0; col < image.Cols; col++)
                    {
                        image.Data[row, col, channel] = 0; //0 = black color value
                    }
            }
            cv_image.Source = BitmapSourceConvert.ToBitmapSource(image);
        }

The above code will convert given number of rows to black by iterating through columns and rows of three channels (for colored) or one channel (for grayscale) of image, assigning black value to each pixel.

Result of Coloring 100 Rows

Image 6

The source code is provided. Hope you get the idea of setting up and using EmguCV basic functions in WPF. In case of any query, feel free to comment. :)

Free advice: Work smarter not harder ;)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)