C# Image Processing Performance - Unsafe vs. Safe code, Part II
published mar 14 2008
In Part I of this article, I outlined a method of performing pixel-level operations on an image that required neither unsafe code, nor the use of the GetPixel
and SetPixel
methods, which are notoriously slow. The one thing I neglected to include was an actual comparison of the IntPtr
and pointer methods with the GetPixel\SetPixel
methods. As such, I present such a method below. It looks tantalizingly simple, but we’ll soon see that it is basically worthless.
public Image ThresholdGS(float thresh)
{
Bitmap b = new Bitmap(_image);
for (int i = 0; i < b.Height; ++i)
{
for (int j = 0; j < b.Width; ++j)
{
Color c = b.GetPixel(j, i);
double magnitude = 1 / 3d * (c.B+c.G+c.R);
if (magnitude < thresh)
{
b.SetPixel(j,i,Color.FromArgb(0,0,0));
}
else
{
b.SetPixel(j,i, Color.FromArgb(255,255,255));
}
}
}
return b;
}
Results
As outlined in the previous post, I created a form that would allow me to run each threshold method repeatedly to find an average time per threshold operation. The results are given in the table below. For these tests, an arbitrary threshold of 125 was chosen. The image used 24 bits-per-color and had a size of 479 x 700 pixels.
Algorithm | Total Time (ms) | % Difference | |
---|---|---|---|
N=10 | |||
unsafe | 194 | 0 | |
IntPtr |
262 | 35% | |
GetPixel |
238,299 (~4 min.) | 122,734% | |
N=100 | |||
unsafe | 1951 | 0 | |
IntPtr |
2361 | 21% | |
N=500 | |||
unsafe | 9783 | 0 | |
IntPtr |
11,499 | 17% |
The first observation is simple: GetPixel\SetPixel
SUCKS! It took longer to do 10 operations using that method than it took to do 500 using either of the other two. We also see that the IntPtr
method, while not a terrible alternative (if, for some reason, the use of unsafe code was strictly not allowed) is also moderately slower than the pointer method.
Test Program
I wrote up a simple test program to perform these tests. It also includes a subjective test, wherein one can select the threshold method and then move a slider to set different threshold values to see how quickly the image changes. The subjective test agrees with the results above.
If you poke around in the program a bit, you’ll also discover a couple of extras, including some tests of using a square-root-of-squares type method for finding the magnitude of a pixel (applied to thresholding, and grayscaling). There is also a method that allows convolution filters to be applied to the image, though editing the filters is very cumbersome. Expect to see new, more-complete versions this program in the future.
The code is now available on GitHub.
Most of the code from this series is in Process.cs