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
- C#
- Visual Studio (2013 used in this tip)
- 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.
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:
Add the following references to your MainWindows.xaml.cs file to include Emgu CV references.
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:
<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:
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);
}
}
}
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.
Build and run your project. Hope it will do the trick.
Result
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:
Image<Bgr, Byte> image = null;
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)
{
image = new Image<Bgr, Byte>(openFileDialog.FileName);
cv_image.Source = BitmapSourceConvert.ToBitmapSource(image);
comboBox_colorspace.SelectedIndex = 0;
}
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var comboBox = (ComboBox)sender;
if (comboBox == null || image == null)
return;
ConvertTo(((ComboBoxItem)comboBox.SelectedItem).Content.ToString());
}
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.
*[Color Space Name] = Ycc, Hsv, Lab, Gray, Bgr and Type = Byte, int, double*
Result: (To grayscale Conversion)
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.
image.Data[0,0,0] = 0;
To assign green color to first pixel with 3 channels (Colored Image):
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++)
{
for (int channel = 0; channel < image.NumberOfChannels;channel++ )
for (int col = 0; col < image.Cols; col++)
{
image.Data[row, col, channel] = 0;
}
}
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
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 ;)