C# Image Processing Performance - Unsafe vs. Safe code, Part I
published mar 13 2008
It’s spring break at my school, and my travel plans fell through, so I’ve taken some time to get back into one of my favorite topics in C#, image processing. If you’re not familiar with doing this in C#, I’d highly encourage you to start reading the great series of articles on the subject by Code Project user Christian Graus. Reading and understanding that first article should get you far enough along to be able to follow this one.
I first became interested in C# image processing when I decided for some reason that I should write a program that would allow me to control a media player (e.g., Winamp) on my computer using a webcam and a laser pointer. This remains, to me, an interesting project, but it was simply too audacious for my skill level (and still is, to be honest, as I am but a beginner). One of the first problems I ran into in my naive approach was that using the
Bitmap.Setpixel methods was ridiculously slow. Some quick googling revealed that what I needed was the magic of unsafe code and pointers. I quickly rewrote my functions, and was on my way.
A Different Approach
Recently, however, I discovered that there is a middle ground between unsafe code and the
Setpixel methods which does not required the use of the unsafe keyword or pointers. I decided to give this a try to see how it performed, both objectively and subjectively.
The key thing to note here was that the Scan0 property of the
BitmapData class is an
IntPtr and not a pointer. This means that rather than dropping into an
unsafe block, we can simply use the overloads of the
System.Runtime.InteropServices.Marshal.Copy method to copy bytes to and from the location of the image in memory.
To test the performance of this method and the usual unsafe method, I wrote two methods which would each threshold an image. I also created a Windows form with a slider that would allow me to change the threshold value in real time, and watch how quickly the image responded (the subjective part of the test). The reasons I chose thresholding were that it’s often one of the first things done to an image during machine processing, and it’s simple to write. Aside from that, we’re really only interested in the time consumed by reading and writing the data to the image, which shouldn’t be affected by the operations perfomed on the data.
The first method, listed below, uses the IntPtr approach.
The second method uses pointers.
That basically covers the code and approach. In Part II (tomorrow, I promise!!), I’ll post a full .sln and results of the comparison.
Go read Part II for another approach, and the performance data!