patterncsharpMinor
Extracting Pixels From Image Byte[]
Viewed 0 times
imagebytepixelsextractingfrom
Problem
I have a requirement where I need to extract pixels of a given rectangle within an image
More specifically I have an image where I have narrowed an area that I wish to return and keep and the remainder discard. In my case I'm performing face recognition in real time so I don't want to store unnecessary data but obviously this could be useful elsewhere.
This method has been responsible for the vast amount of CPU time my application is using and I'm hoping to improve this.
The obvious suggestion is to remove the LINQ, but beyond this, is there anything else that can be improved?
byte[].More specifically I have an image where I have narrowed an area that I wish to return and keep and the remainder discard. In my case I'm performing face recognition in real time so I don't want to store unnecessary data but obviously this could be useful elsewhere.
public static byte[] ExtractPixelsFromImage(this byte[] pixels, int top, int left, int width, int height, int horizontalResolution)
{
List result = new List();
int bytesPerPixel = 4;
int rowLength = horizontalResolution * bytesPerPixel;
int rowLeftPixelStart = (rowLength * top) + (left * bytesPerPixel);
for (int i = 0; i < height; i++)
{
int currentPixelStart = (rowLength * i) + rowLeftPixelStart;
result.AddRange(pixels.Skip(currentPixelStart).Take(width * bytesPerPixel));
}
return result.ToArray();
}This method has been responsible for the vast amount of CPU time my application is using and I'm hoping to improve this.
The obvious suggestion is to remove the LINQ, but beyond this, is there anything else that can be improved?
Solution
At a quick glance it would appear that your code is likely getting slowed down by the use of
Linq as well as conversion between List and byte[]. Only profiling and determining a reasonable amount of time for this code to execute is going to tell you the real answer, but here are some things you can try:- Don't use
SkipandTake. Both of these methods operate onIEnumerable, meaningSkipmay iterate from 0-currentPixelStart despite the fact that the array can be accessed by index directly. It's possible that this optimization is done by these extension methods, but some quick searching seems to indicate it is not (and you don't want to rely on it's implementation sticking that way).
- Don't use
List. For starters, one of the benefits of using aListis that it can dynamically grow based on elements that are added. In most cases it does pretty well managing the overhead of resizing the internal collection, but if you need the absolute best performance you can just use a byte array. You can already calculate how big the resulting byte array will be, so just allocate the proper size from the start. This also means avoiding theresult.ToArray()call sinceresultwill already be an array.
- Make
bytesPerPixelaconst. This one isn't likely to gain you anything noticeable in the performance department, but other methods could make use of this value and right now it's hidden away in this method.
- Don't recalculate the new row size on every
heightiteration (ie: movewidth * bytesPerPixeloutside the loop since it won't change).
Context
StackExchange Code Review Q#51139, answer score: 5
Revisions (0)
No revisions yet.