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.
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;
}
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);
}
}
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With