Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Apply Color LUT to bitmap images for filter effects in android?

here i have a question on LUTs in android.

my question is, i have 4X4 LUTs, Using these LUTs apply filter effect for bitmap image in android. Below is my sample LUT file link. Lut link sample

Is it Possible in android? if possible please help me how to apply.

Thanks in advance.

like image 304
user512 Avatar asked Oct 02 '15 10:10

user512


3 Answers

I'm working on a LUT applier library which eases the use of LUT images in Android. It uses the algorythm below, but I'd like to enhance it in the future for optimising memory usage. Now it also guesses the color axes of the LUT: https://github.com/dntks/easyLUT/wiki

Your LUT image has the red-green-blue color dimension in an other order than what I've been used to, so I had to change the order of when getting the lutIndex (at getLutIndex()). Please check my edited answer:

final static int X_DEPTH = 16;
final static int Y_DEPTH = 16; //One little square has 16x16 pixels in it
final static int ROW_DEPTH = 4;
final static int COLUMN_DEPTH = 4; // the image consists of 4x4 little squares
final static int COLOR_DISTORTION = 16; // 256*256*256 => 256 no distortion, 64*64*64 => 256 dividied by 4 = 64, 16x16x16 => 256 dividied by 16 = 16

private Bitmap applyLutToBitmap(Bitmap src, Bitmap lutBitmap) {
    int lutWidth = lutBitmap.getWidth();
    int lutColors[] = new int[lutWidth * lutBitmap.getHeight()];
    lutBitmap.getPixels(lutColors, 0, lutWidth, 0, 0, lutWidth, lutBitmap.getHeight());

    int mWidth = src.getWidth();
    int mHeight = src.getHeight();
    int[] pix = new int[mWidth * mHeight];
    src.getPixels(pix, 0, mWidth, 0, 0, mWidth, mHeight);

    int R, G, B;
    for (int y = 0; y < mHeight; y++)
        for (int x = 0; x < mWidth; x++) {
            int index = y * mWidth + x;
            int r = ((pix[index] >> 16) & 0xff) / COLOR_DISTORTION;
            int g = ((pix[index] >> 8) & 0xff) / COLOR_DISTORTION;
            int b = (pix[index] & 0xff) / COLOR_DISTORTION;

            int lutIndex = getLutIndex(lutWidth, r, g, b);

            R = ((lutColors[lutIndex] >> 16) & 0xff);
            G = ((lutColors[lutIndex] >> 8) & 0xff);
            B = ((lutColors[lutIndex]) & 0xff);
            pix[index] = 0xff000000 | (R << 16) | (G << 8) | B;
        }
    Bitmap filteredBitmap = Bitmap.createBitmap(mWidth, mHeight, src.getConfig());
    filteredBitmap.setPixels(pix, 0, mWidth, 0, 0, mWidth, mHeight);
    return filteredBitmap;
}

//the magic happens here
private int getLutIndex(int lutWidth, int redDepth, int greenDepth, int blueDepth) {
    int lutX = (greenDepth % ROW_DEPTH) * X_DEPTH + blueDepth;
    int lutY = (greenDepth / COLUMN_DEPTH) * Y_DEPTH + redDepth;
    return lutY * lutWidth + lutX;
}
like image 148
abbath Avatar answered Oct 15 '22 15:10

abbath


This is how you would process an image with RenderScript's ScriptIntrinsic3DLUT

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsic3DLUT;
import android.renderscript.Type;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {
    ImageView imageView1;
    RenderScript mRs;
    Bitmap mBitmap;
    Bitmap mLutBitmap;
    ScriptIntrinsic3DLUT mScriptlut;
    Bitmap mOutputBitmap;
    Allocation mAllocIn;
    Allocation mAllocOut;
    Allocation mAllocCube;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView1 = (ImageView) findViewById(R.id.imageView);
        mRs = RenderScript.create(this);
        Background background = new Background();
        background.execute();
    }

    class Background extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            if (mRs == null) {
                mRs = RenderScript.create(MainActivity.this);
            }
            if (mBitmap == null) {
                mBitmap = BitmapFactory.decodeResource(getResources(),
                        R.drawable.bugs);

                mOutputBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());

                mAllocIn = Allocation.createFromBitmap(mRs, mBitmap);
                mAllocOut = Allocation.createFromBitmap(mRs, mOutputBitmap);
            }
            if (mLutBitmap == null) {
                mLutBitmap = BitmapFactory.decodeResource(getResources(),
                        R.drawable.dawizfe);
                int w = mLutBitmap.getWidth();
                int h = mLutBitmap.getHeight();
                int redDim = w / 4;
                int greenDim = h / 4;
                int blueDim = 16;
                android.renderscript.Type.Builder tb = new Type.Builder(mRs, Element.U8_4(mRs));
                tb.setX(redDim);
                tb.setY(greenDim);
                tb.setZ(blueDim);
                Type t = tb.create();
                mAllocCube = Allocation.createTyped(mRs, t);
                int[] pixels = new int[w * h];
                int[] lut = new int[w * h];
                mLutBitmap.getPixels(pixels, 0, w, 0, 0, w, h);
                int i = 0;
                for (int r = 0; r < redDim; r++) {
                   for (int g = 0; g < greenDim; g++) {
                        for (int b = 0; b < blueDim; b++) {
                            int gdown = g / 4;
                            int gright = g % 4;
                            lut[i] = pixels[b + r * w + gdown * w * redDim + gright * blueDim];
                            i++;
                        }
                    }
                }
//                This is an identity 3D LUT
//                i = 0;
//                for (int r = 0; r < redDim; r++) {
//                    for (int g = 0; g < greenDim; g++) {
//                        for (int b = 0; b < blueDim; b++) {
//                            int bcol = (b * 255) / blueDim;
//                            int gcol = (g * 255) / greenDim;
//                            int rcol = (r * 255) / redDim;
//                            lut[i] = bcol | (gcol << 8) | (rcol << 16);
//                            i++;
//                        }
//                    }
//                }
                mAllocCube.copyFromUnchecked(lut);
            }
            if (mScriptlut == null) {
                mScriptlut = ScriptIntrinsic3DLUT.create(mRs, Element.U8_4(mRs));

            }
            mScriptlut.setLUT(mAllocCube);
            mScriptlut.forEach(mAllocIn, mAllocOut);

            mAllocOut.copyTo(mOutputBitmap);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            imageView1.setImageBitmap(mOutputBitmap);
        }
    }
}
like image 20
user2985410 Avatar answered Oct 15 '22 14:10

user2985410


u can go through this, hope it will help you to get the right process.

photo is the main bitmap here.

mLut3D is the array of LUT images stored in drawable

    RenderScript mRs;
    Bitmap mLutBitmap, mBitmap;
    ScriptIntrinsic3DLUT mScriptlut;
    Bitmap mOutputBitmap;
    Allocation mAllocIn;
    Allocation mAllocOut;
    Allocation mAllocCube;
    int mFilter = 0;

mRs = RenderScript.create(yourActivity.this);
public Bitmap filterapply() {
        int redDim, greenDim, blueDim;
        int w, h;
        int[] lut;

        if (mScriptlut == null) {
            mScriptlut = ScriptIntrinsic3DLUT.create(mRs, Element.U8_4(mRs));
        }
         if (mBitmap == null) {
         mBitmap = photo;
}
        mOutputBitmap = Bitmap.createBitmap(mBitmap.getWidth(),
                mBitmap.getHeight(), mBitmap.getConfig());

        mAllocIn = Allocation.createFromBitmap(mRs, mBitmap);
        mAllocOut = Allocation.createFromBitmap(mRs, mOutputBitmap);
        // }

        mLutBitmap = BitmapFactory.decodeResource(getResources(),
                mLut3D[mFilter]);
        w = mLutBitmap.getWidth();
        h = mLutBitmap.getHeight();
        redDim = w / h;
        greenDim = redDim;
        blueDim = redDim;
        int[] pixels = new int[w * h];
        lut = new int[w * h];
        mLutBitmap.getPixels(pixels, 0, w, 0, 0, w, h);
        int i = 0;

        for (int r = 0; r < redDim; r++) {
            for (int g = 0; g < greenDim; g++) {
                int p = r + g * w;
                for (int b = 0; b < blueDim; b++) {
                    lut[i++] = pixels[p + b * h];
                }
            }
        }

        Type.Builder tb = new Type.Builder(mRs, Element.U8_4(mRs));
        tb.setX(redDim).setY(greenDim).setZ(blueDim);
        Type t = tb.create();
        mAllocCube = Allocation.createTyped(mRs, t);
        mAllocCube.copyFromUnchecked(lut);

        mScriptlut.setLUT(mAllocCube);
        mScriptlut.forEach(mAllocIn, mAllocOut);

        mAllocOut.copyTo(mOutputBitmap);
        return mOutputBitmap;
    }

you increase the mFilter value to get different filter effect with different LUT images, you have, check it out.

you can go through the this link on github for more help, i got the answer from here:- https://github.com/RenderScript/RsLutDemo

hope it will help

like image 43
Shubham Avatar answered Oct 15 '22 14:10

Shubham