Image-processing algorithm on mobile device I have written the following algorithm (for Android/NDK) to apply levels to a bitmap. The problem is that it is really very slow.  On a fast device such as the SGSIII, it can take up to 4 seconds for an 8MP image. And on devices with ARMv6 takes ages (over 10 seconds). I know that can be speed up with NEON instructions, but I don't have such knowledge.

Is there any way to optimize it?

void applyLevels(unsigned int *rgb, const unsigned int width, const unsigned int height, const float exposure, const float brightness, const float contrast, const float saturation)
{
    float R, G, B;

    unsigned int pixelIndex = 0;

    float exposureFactor   = powf(2.0f, exposure);
    float brightnessFactor = brightness / 10.0f;
    float contrastFactor   = contrast &gt; 0.0f ? contrast : 0.0f;
    float saturationFactor = 1.0f - saturation;

    for (int y = 0; y &lt; height; y++)
    {
        for (int x = 0; x &lt; width; x++)
        {
            const int pixelValue = buffer[pixelIndex];

            R = ((pixelValue &amp; 0xff0000) &gt;&gt; 16) / 255.0f;
            G = ((pixelValue &amp; 0xff00) &gt;&gt; 8) / 255.0f;
            B = (pixelValue &amp; 0xff) / 255.0f;

            // Clamp values

            R = R &gt; 1.0f ? 1.0f : R &lt; 0.0f ? 0.0f : R;
            G = G &gt; 1.0f ? 1.0f : G &lt; 0.0f ? 0.0f : G;
            B = B &gt; 1.0f ? 1.0f : B &lt; 0.0f ? 0.0f : B;

            // Exposure

            R *= exposureFactor;
            G *= exposureFactor;
            B *= exposureFactor;

            // Contrast

            R = (((R - 0.5f) * contrastFactor) + 0.5f);
            G = (((G - 0.5f) * contrastFactor) + 0.5f);
            B = (((B - 0.5f) * contrastFactor) + 0.5f);

            // Saturation

            float gray = (R * 0.3f) + (G * 0.59f) + (B * 0.11f);
            R = (gray * saturationFactor) + R * saturation;
            G = (gray * saturationFactor) + G * saturation;
            B = (gray * saturationFactor) + B * saturation;

            // Brightness

            R += brightnessFactor;
            G += brightnessFactor;
            B += brightnessFactor;

            // Clamp values

            R = R &gt; 1.0f ? 1.0f : R &lt; 0.0f ? 0.0f : R;
            G = G &gt; 1.0f ? 1.0f : G &lt; 0.0f ? 0.0f : G;
            B = B &gt; 1.0f ? 1.0f : B &lt; 0.0f ? 0.0f : B;

            // Store new pixel value

            R *= 255.0f;
            G *= 255.0f;
            B *= 255.0f;

            buffer[pixelIndex] = ((int)R &lt;&lt; 16) | ((int)G &lt;&lt; 8) | (int)B;

            pixelIndex++;
        }
    }
}
Just loop over the index.
The first clamp is unnecessary. (X &amp; 0xff) will always be between 0 and 255.
Look at it algebraically. There are some expressions that do not depend on R, B, or B that you can extract from the loop.
You can extract some common expressions and calculate them at the same time as grey.


.

void applyLevels(unsigned int *rgb, const unsigned int width, const unsigned int height, const float exposure, const float brightness, const float contrast, const float saturation)
{
    const float exposureFactor   = powf(2.0f, exposure);
    const float brightnessFactor = brightness / 10.0f;
    const float contrastFactor   = contrast &gt; 0.0f ? contrast : 0.0f;
    const float saturationFactor = 1.0f - saturation;

    const float f01 = exposureFactor / 255.0f * contrastFactor;
    const float f02 = 0.5f * (1.0f - contrastFactor);

    const unsigned int nPixel = width * height;
    for(unsigned int pixelIndex = 0; pixelIndex &lt; nPixel; ++pixelIndex)
    {
        const unsigned int pixelValue = rgb[pixelIndex];
        float R = static_cast&lt;float&gt;((pixelValue &gt;&gt; 16) &amp; 0xff);
        float G = static_cast&lt;float&gt;((pixelValue &gt;&gt;  8) &amp; 0xff);
        float B = static_cast&lt;float&gt;((pixelValue      ) &amp; 0xff);

        R = R * f01 + f02;
        G = G * f01 + f02;
        B = B * f01 + f02;

        const float f03 = ((R * 0.3f) + (G * 0.59f) + (B * 0.11f)) * saturationFactor + brightnessFactor;

        R = (R * saturation + f03) * 255.0f;
        G = (G * saturation + f03) * 255.0f;
        B = (B * saturation + f03) * 255.0f;

        R = R &gt; 255.0f ? 255.0f : R &lt; 0.0f ? 0.0f : R;
        G = G &gt; 255.0f ? 255.0f : G &lt; 0.0f ? 0.0f : G;
        B = B &gt; 255.0f ? 255.0f : B &lt; 0.0f ? 0.0f : B;

        rgb[pixelIndex] =
            (static_cast&lt;unsigned int&gt;(R) &lt;&lt; 16) |
            (static_cast&lt;unsigned int&gt;(G) &lt;&lt;  8) |
            (static_cast&lt;unsigned int&gt;(B)      );
    }
}


Other optimizations:


Do you need an entire 8MP image? Can you downscale the image or even grab a portion?
How often do you need to apply all four operations to an image? If it is common for some images to only require exposure and saturation then make separate functions.
Convert the for to a parallel for and use neon and other intrinsics.
Rather than doing the previous suggestion I would recommend using Renderscript. It will use your GPU if it can. If it uses the CPU it is automatically multithreaded.