HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Extracting Pixels From Image Byte[]

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
imagebytepixelsextractingfrom

Problem

I have a requirement where I need to extract pixels of a given rectangle within an image 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 Skip and Take. Both of these methods operate on IEnumerable, meaning Skip may 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 a List is 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 the result.ToArray() call since result will already be an array.



  • Make bytesPerPixel a const. 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 height iteration (ie: move width * bytesPerPixel outside the loop since it won't change).

Context

StackExchange Code Review Q#51139, answer score: 5

Revisions (0)

No revisions yet.