NDK development series one -- image brightness and saturation processing

Posted by gerrydewar on Tue, 30 Jun 2020 18:28:03 +0200

github code gate: https://github.com/18380438200/NdkUse

First, the effect picture:


Preview

The implementation method of java is as follows:

public class JavaFilter {
    public static final float brightness = 0.2f;  //brightness
    public static final float contrainst = 0.2f;  //Contrast, color deepening

    public static Bitmap getImageBitmap(Bitmap bitmap){
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Bitmap result = Bitmap.createBitmap(width,height, Bitmap.Config.RGB_565); 
        int a,r,g,b;
        int bab = (int) (255*brightness);
        float ca = 1.0f + contrainst;
        //Change the rgb value of all pixels
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                int color = bitmap.getPixel(x,y);  //Gets the color value
                a = Color.alpha(color);
                r = Color.red(color); 
                g = Color.green(color);
                b = Color.blue(color);

                //skin whitening
                int ri = r + bab;
                int gi = g + bab;
                int bi = b + bab;

                //boundary detection 
                r = ri > 255 ? 255 : (ri<0?0:ri);
                g = gi > 255 ? 255 : (gi<0?0:gi);
                b = bi > 255 ? 255 : (bi<0?0:bi);

                //Enlarge contrast, need white more white, black more black
                //Strengthen above 128 and reduce below 128
                ri = r - 128;
                gi = g - 128;
                bi = b - 128;

                ri = (int) (ri * ca);
                gi = (int) (gi * ca);
                bi = (int) (bi * ca);

                ri += 128;
                gi += 128;
                bi += 128;

                //boundary detection 
                r = ri > 255 ? 255 : (ri<0?0:ri);
                g = gi > 255 ? 255 : (gi<0?0:gi);
                b = bi > 255 ? 255 : (bi<0?0:bi);

                result.setPixel(x,y,Color.argb(a,r,g,b));
            }
        }

        return result;
    }

Bitmap.createBitmap()

Create Bitmap (Bitmap source, int x, int y, int width, int height): starting from the coordinate point (x,y) specified in the original position map, dig out a piece of wide width and high height from it to create a new Bitmap object.

Create scaled bitmap (bitmap source, int dstwidth, int dstheight, Boolean filter): zooms the source bitmap to a new bitmap object of specified width and height.

•createBitmap(int width, int height, Bitmap.Config Config): create a new bitmap with wide width and high height.
Create Bitmap (Bitmap source, int x, int y, int width, int height, Matrix matrix, Boolean filter): starting from the coordinate point (x,y) specified in the original position map, dig out a piece of wide width and high height to create a new Bitmap object. And transform according to the rules specified by Matrix.

Bitmap.Config.RGB_ Understanding: the inner class of bitmap
public enum Config {
ALPHA_8 (1),
RGB_565 (3),
ARGB_4444 (4),
ARGB_8888 (5),
RGBA_F16 (6),
...
}
Alpha_ Eight is Alpha, which is made up of eight bits
ARGB_4444 is composed of four 4 bits, namely 16 bits,
ARGB_8888 is composed of 4 8 bits, namely 32 bits, the original color
RGB_565 means that R is 5 bits, G is 6 bits, B is 5 bits, totally 16 bits
The higher the number of bits, the richer the stored colors and the clearer the picture

C implementation code

extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_apple_ndkconfig_NdkFilter_getNdkBitmap(JNIEnv *env, jobject /* this */,
                                                           jintArray buffer_, jint width,
                                                           jint height) {
    float brightness = 0.2f;  //brightness
    float contrainst = 0.2f;  //Contrast, color deepening

    //All color values of the image are stored in an array
    jint* source = env->GetIntArrayElements(buffer_,NULL); 

    int a,r,g,b;
    int bab = (int) (255 * brightness);
    float ca = 1.0f + contrainst;
    //Change the rgb value of all pixels
    int x,y;
    for (x = 0; x < width; x++) {
        for (y = 0; y < height; y++) {
            int color = source[width*y + x];  //Gets the color value
            a = color >> 24;
            r = color >> 16 & 0xFF;
            g = color >> 8 & 0xFF;
            b = color & 0xFF;

            //Increase brightness (whitening)
            int ri = r + bab;
            int gi = g + bab;
            int bi = b + bab;

            //Boundary detection, argb values are in the range of [0-255]
            r = ri > 255 ? 255 : (ri < 0 ? 0 : ri);
            g = gi > 255 ? 255 : (gi < 0 ? 0 : gi);
            b = bi > 255 ? 255 : (bi < 0 ? 0 : bi);

            //Enlarge contrast, need white more white, black more black
            //Strengthen above 128 and reduce below 128
            ri = r - 128;
            gi = g - 128;
            bi = b - 128;

            ri = (int) (ri * ca);
            gi = (int) (gi * ca);
            bi = (int) (bi * ca);

            ri += 128;
            gi += 128;
            bi += 128;

            //Boundary detection again
            r = ri > 255 ? 255 : (ri < 0 ? 0 : ri);
            g = gi > 255 ? 255 : (gi < 0 ? 0 : gi);
            b = bi > 255 ? 255 : (bi < 0 ? 0 : bi);

            //result.setPixel(x, y, Color.argb(a, r, g, b));
            //argb synthesis of jni
            source[width * y + x] = a << 24| r << 16 | g << 8 | b;
        }
    }

    //The processing principle is the same as that of java, but the way to get data and objects is different
    int newSize = width * height;
    //According to the length of the array, save the source to jintararray and release the resources
    jintArray result = env->NewIntArray(newSize);
    env->SetIntArrayRegion(result,0,newSize,source); 
    env->ReleaseIntArrayElements(buffer_, source, 0);

    return result;
}
a = color >> 24;
r = color >> 16 & 0xFF;  // (color >> 16) & 0xFF
g = color >> 8 & 0xFF;
b = color & 0xFF;

Here, because the color value is a 32-bit int, argb occupies 8 bits respectively. Take r = color > > 16 & 0xff as an example,
Shift 16 bits to the right to get the high 16 bits, and then & 0xff, that is, the low eight bits of the process and 1 press the bit and still get the original value, so the corresponding r value is obtained

image.png

More NDK development features, see my next blog series.

Topics: github Java