Intel Integrated Performance Primitives, also known as IPP, is a library of highly optimized math software functions for digital media and data-processing applications. The functions use multiple threads and the most appropriate SIMD instructions to achieve the best performance according to instruction set architecture available in the underlying hardware. You can call IPP functions from your C# code through Platform Invokes, also known as P/Invokes.
Intel IPP 8.0 or higher includes all the necessary code that allows you to easily call IPP functions in any C# project. However, the necessary code is included in an almost hidden language-related samples zip file. Thus, you have to decompress the zip file in a new folder to find the necessary C# files that will allow you to call the different IPP functions. These samples are usually compressed into a file called "ipp-samples-language.zip" and located within the IPP subfolder of the Intel product that includes IPP. If you have problems locating this file, you can just search for it in the Intel folder found in Program Files (x86). For example, Intel Parallel Composer 2011 includes the IPP samples in Program Files (x86)\Intel\Parallel Studio 2011\Composer\Samples\en_US\IPP. See Figure 1. In a 32-bit Window version, instead of the Program Files (x86) folder, it will be just the Program Files folder.
When you decompress the ipp-samples-language.zip file, the following subfolders will appear within the main folder:
ipp-samples
|-> language-interface
|-> cpp
|-> doc
|-> src
|-> csharp
|-> application
|-> doc
|-> interface
|-> src
|-> tools
|-> env
In order to include all the necessary wrappers to call the IPP functions from C#, you have to add all the .cs files found in the ipp-samples-language\ipp-samples\language-interface\csharp folder to your C# project. Remember that the folder appears when you decompress the ipp-samples-language.zip file. Thus, the project will include the following C# files:
- ippcc.cs
- ippch.cs
- ippcore.cs
- ippcp.cs
- ippcv.cs
- ippdc.cs
- ippdefs.cs
- ippdi.cs
- ippgen.cs
- ippi.cs
- ippj.cs
- ippm.cs
- ippr.cs
- ipps.cs
- ippsc.cs
- ippvc.cs
- ippvm.cs
If you plan to use imaging filters, you need to activate an option to be able to use unsafe pointers to prepare the necessary data for the IPP filter. In order to do so, just right-click on the project's name in Solution Explorer and select Properties. Then, click the Build page and activate the Allow Unsafe Code checkbox. See Figure 2.
The following C# code listing defines the Click event handler for a ProcessImage button in a WPF application. A WPF project requires a reference to System.Drawing because the code uses the System.Drawing.Bitmap class to manipulate the pixels of a bitmap image. Notice that the code includes a using ipp line:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using ipp;
namespace IppCSharpExample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private BitmapData GetBitmapData(Bitmap bitmap, ImageLockMode lockMode)
{
return bitmap.LockBits(
new System.Drawing.Rectangle(0, 0,
bitmap.Width, bitmap.Height),
lockMode,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
}
unsafe private Bitmap ApplyFilterSobelHoriz(string fileName)
{
var originalImage = new Bitmap(fileName);
var sourceBitmapData = GetBitmapData(originalImage, ImageLockMode.ReadOnly);
var destinationImage = new Bitmap(originalImage.Width, originalImage.Height);
var destinationBitmapData = GetBitmapData(destinationImage, ImageLockMode.ReadWrite);
IppiSize roi = new IppiSize(originalImage.Width - 3, originalImage.Height - 3);
const int ksize = 5;
const int half = ksize / 2;
byte* pSrc = (byte*)sourceBitmapData.Scan0 + (sourceBitmapData.Stride + 3) * half;
byte* pDst = (byte*)destinationBitmapData.Scan0 + (destinationBitmapData.Stride + 3) * half;
IppStatus status = ipp.ip.ippiFilterSobelHoriz_8u_C3R(
pSrc, sourceBitmapData.Stride,
pDst, destinationBitmapData.Stride,
roi);
// Unlock bits for both source and destination
originalImage.UnlockBits(sourceBitmapData);
destinationImage.UnlockBits(destinationBitmapData);
return destinationImage;
}
private void ProcessImage_Click(object sender, RoutedEventArgs e)
{
ProcessImage.IsEnabled = false;
// This scheduler will execute tasks on the current SynchronizationContext
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var filterTask = Task.Factory.StartNew<Bitmap>(
() =>
{
return ApplyFilterSobelHoriz(@"C:\YOURPICTUREFOLDER\YOURPICTURE.JPG");
});
filterTask.ContinueWith(
(antecedentTask) =>
{
// This code runs in the UI thread
try
{
var outBitmap = antecedentTask.Result;
// Show the results
// in the Image control
ProcessedImage.Source =
Imaging.CreateBitmapSourceFromHBitmap(
outBitmap.GetHbitmap(),
IntPtr.Zero,
System.Windows.Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(
outBitmap.Width, outBitmap.Height));
}
catch (AggregateException ex)
{
foreach
(Exception innerEx in ex.InnerExceptions)
{
//// Aggregate Exception Handling
//// ....
//// Aggregate Exception Handling
}
}
ProcessImage.IsEnabled = true;
}, uiScheduler);
}
}
}


