I want to convert the bitmap image into the Grayscale.For that i am using the NDK to boost the app performance.I have apply the other effect successfully.
Problem ::
The code which i am using to apply the grayscale is taken from the C##.So,i want to convert it into the NDK.I am unable to do that part ..
For reference, i am putting the code of how i have applied the cyan effect to image.
Below pasted code is working fine.
void applyCyano(Bitmap* bitmap) {
//Cache to local variables
unsigned char* red = (*bitmap).red;
unsigned char* green = (*bitmap).green;
unsigned char* blue = (*bitmap).blue;
unsigned int length = (*bitmap).width * (*bitmap).height;
register unsigned int i;
register unsigned char grey, r, g, b;
for (i = length; i--;) {
grey = ((red[i] * 0.222f) + (green[i] * 0.222f) + (blue[i] * 0.222f));
r = componentCeiling(61.0f + grey);
g = componentCeiling(87.0f + grey);
b = componentCeiling(136.0f + grey);
grey = blackAndWhite(red[i], green[i], blue[i]);
red[i] = overlayPixelComponents(grey, r, 0.9f);
green[i] = overlayPixelComponents(grey, g, 0.9f);
blue[i] = overlayPixelComponents(grey, b, 0.9f);
}
}
The code to appply Grayscale effect(taken from C## example over the net) ::
void applyGrayscaleNatively(Bitmap* original)
{
//create an empty bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
//lock the original bitmap in memory
BitmapData originalData = original.LockBits(
new Rectangle(0, 0, original.Width, original.Height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
//lock the new bitmap in memory
BitmapData newData = newBitmap.LockBits(
new Rectangle(0, 0, original.Width, original.Height),
ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
//set the number of bytes per pixel
int pixelSize = 3;
for (int y = 0; y < original.Height; y++)
{
//get the data from the original image
byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);
//get the data from the new image
byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);
for (int x = 0; x < original.Width; x++)
{
//create the grayscale version
byte grayScale =
(byte)((oRow[x * pixelSize] * .11) + //B
(oRow[x * pixelSize + 1] * .59) + //G
(oRow[x * pixelSize + 2] * .3)); //R
//set the new image's pixel to the grayscale version
nRow[x * pixelSize] = grayScale; //B
nRow[x * pixelSize + 1] = grayScale; //G
nRow[x * pixelSize + 2] = grayScale; //R
}
}
//unlock the bitmaps
newBitmap.UnlockBits(newData);
original.UnlockBits(originalData);
}
What i want to do ::
I have taken this project from the here which have set the different effect to the image but not the grayscale.so how to apply the grayscale to the code so that all the other funcationality of the project won't stop.
Let me know if you need anything from me .
Many Thanks in Advance..
Please help me to resovle this issue as just because of this am not able to go further in my project.
Use the following function to convert bitmap to its grayscale equivalent in Android instead of converting the C# version
public Bitmap toGrayscale(Bitmap bmpOriginal){
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
I solved the issue ::
Here is my solution ...
void applyGrayscaleNatively(Bitmap* bitmap)
{
register unsigned int i;
unsigned int length = (*bitmap).width * (*bitmap).height;
register unsigned char grey;
unsigned char* red = (*bitmap).red;
unsigned char* green = (*bitmap).green;
unsigned char* blue = (*bitmap).blue;
float matrix[4][4];
identMatrix(matrix);
float saturation = 1.0f;
saturateMatrix(matrix, &saturation);
applyMatrix(bitmap, matrix);
for (i = length; i--;) {
float value;
getBrightness(red[i], green[i], blue[i], &value);
grey = grayScale(red[i], green[i], blue[i]);
red[i] = grey;
green[i] = grey;
blue[i] = grey;
}
}
Related
I am developing an application which includes filters and crop too. Here I am using cropping library. Here I used 8*8 luts like sample lut. Here I want to CROP the filtered image(8*8 lut)
Here is the logic to crop the image.
Bitmap cropbitmap = ivCropimageView.getCroppedImage();
Using this bitmap I generate a thumbnail bitmap like below.
Bitmap thumbImage = ThumbnailUtils.extractThumbnail(cropbitmap, 190, 250);
When I am trying to generate thumbnails for all filters then the thumbnails are displaying as too noise like this.
This result is when I implemented the answer from renderscript.
So if anyone has ab idea please help me..
I'm working on a LUT applier library which eases the use of LUT images in Android. Now it also guesses the color axes of the LUT:
https://github.com/dntks/easyLUT/wiki
It uses the algorythm I mentioned in the other post
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
I'm porting ios app to android and have issue with bitmap colors while creating it from byte array. This code works perfectly on ios (C# - Xamarin):
const int bitsPerComponent = 8;
const int bytePerPixel = 4;
var bytesPerRow = bytePerPixel * BarcodeImageWidth;
var colorSpace = CGColorSpace.CreateDeviceRGB();
var context = new CGBitmapContext(byteArray,
BarcodeImageWidth, BarcodeImageHeight,
bitsPerComponent, bytesPerRow,
colorSpace, CGImageAlphaInfo.NoneSkipFirst);
BarcodeImageView.Image = new UIImage(context.ToImage());
And this code on android makes bitmap with wrong colors:
var bitmap = Bitmap.CreateBitmap(barcode.Width, barcode.Height, Bitmap.Config.Argb8888);
bitmap.CopyPixelsFromBuffer(ByteBuffer.Wrap(imageBytes));
barcode.SetImageBitmap(bitmap);
Fixed that by manually created pixel array with skipped first (alpha) byte.
int pixelsCount = imageBytes.Length / 4;
int[] pixels = new int[pixelsCount];
for (int i = 0; i < pixelsCount; i++)
{
var offset = 4 * i;
int r = imageBytes[offset + 1];
int g = imageBytes[offset + 2];
int b = imageBytes[offset + 3];
pixels[i] = Color.Rgb(r, g, b);
}
var bitmap = Bitmap.CreateBitmap(pixels, barcode.Width, barcode.Height, Bitmap.Config.Argb8888);
barcode.SetImageBitmap(bitmap);
This question is base on link.
I tried out #miloslaw-smyk answer. However I could not get it to work. I am not sure what createPath(1) means. I am not sure how to create a path with a certain stroke width. We can do that using the fillpaint. Anyway below I have shown the complete code.Problem is I don't see any emboss effect shown by the original link (see output image below). Please let me know what I have done wrong. (I am using targetSdkVersion 23 and device is on updated 4.1.2 android)
private Bitmap puzzelImage; // screen size image
private Bitmap mBitmapIn;
private Bitmap mBitmapPuzzle;
private RenderScript mRS;
private Allocation mInAllocation;
private Allocation mPuzzleAllocation;
private Allocation mCutterAllocation;
private Allocation mOutAllocation;
private Allocation mOutAllocation2;
private Allocation mAllocationHist;
private ScriptIntrinsicBlur mScriptBlur;
private ScriptIntrinsicBlend mScriptBlend;
private ScriptIntrinsicHistogram mScriptHistogram;
private ScriptIntrinsicLUT mScriptLUT;
public Activity ctx;
private int bw = 780;
private int bh = 780; Path path2;
private void init() {
if (puzzel.mybitmap == null)
return;
bw = puzzelImage.getWidth();
bh = puzzelImage.getHeight();
mBitmapIn = puzzelImage ;
mBitmapPuzzle = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888); // this will hold the puzzle
Canvas c = new Canvas(mBitmapPuzzle);
createPath();
//path2 = path1;
fillPaint.setStrokeWidth(5);
c.drawPath(path2, fillPaint); // draw it on canvas
createScript(); // get renderscripts and Allocations ready
// Apply gaussian blur of radius 25 to our drawing
mScriptBlur.setRadius(25);
mScriptBlur.setInput(mPuzzleAllocation);
mScriptBlur.forEach(mOutAllocation);
// Now apply the blur of radius 1
mScriptBlur.setRadius(1);
mScriptBlur.setInput(mPuzzleAllocation);
mScriptBlur.forEach(mOutAllocation2);
// Subtract one blur result from another
mScriptBlend.forEachSubtract(mOutAllocation, mOutAllocation2);
// We now want to normalize the result (e.g. make it use full 0-255 range).
// To do that, we will first compute the histogram of our image
mScriptHistogram.setOutput(mAllocationHist);
mScriptHistogram.forEach(mOutAllocation2);
// copy the histogram to Java array...
int []hist = new int[256 * 4];
mAllocationHist.copyTo(hist);
// ...and walk it from the end looking for the first non empty bin
int i;
for(i = 255; i > 1; i--)
if((hist[i * 4] | hist[i * 4 + 1] | hist[i * 4 + 2]) != 0)
break;
// Now setup the LUTs that will map the image to the new, wider range.
// We also use the opportunity to inverse the image ("255 -").
for(int x = 0; x <= i; x++)
{
int val = 255 - x * 255 / i;
mScriptLUT.setAlpha(x, 255); // note we always make it fully opaque
mScriptLUT.setRed(x, val);
mScriptLUT.setGreen(x, val);
mScriptLUT.setBlue(x, val);
}
// the mapping itself.
mScriptLUT.forEach(mOutAllocation2, mOutAllocation);
Bitmap mBitmapCutter = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888);
c = new Canvas(mBitmapCutter);
createPath();
fillPaint.setStrokeWidth(1);
c.drawPath(path2, fillPaint);
mCutterAllocation = Allocation.createFromBitmap(mRS, mBitmapCutter);
// cookie cutter now
mScriptBlend.forEachDstIn(mCutterAllocation, mOutAllocation);
mScriptBlend.forEachMultiply(mOutAllocation, mInAllocation);
mInAllocation.copyTo(mBitmapPuzzle);
}
private void createScript() {
try {
mRS = RenderScript.create(ctx);
mPuzzleAllocation = Allocation.createFromBitmap(mRS, mBitmapPuzzle);
// three following allocations could actually use createSized(),
// but the code would be longer.
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
mOutAllocation = Allocation.createFromBitmap(mRS, mBitmapPuzzle);
mOutAllocation2 = Allocation.createFromBitmap(mRS, mBitmapPuzzle);
mAllocationHist = Allocation.createSized(mRS, Element.I32_3(mRS), 256);
mScriptBlur = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS));
mScriptBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS));
mScriptHistogram = ScriptIntrinsicHistogram.create(mRS, Element.U8_4(mRS));
mScriptLUT = ScriptIntrinsicLUT.create(mRS, Element.U8_4(mRS));
}catch (Exception e)
{
}
}
public void createPath()
{
path2 = new Path();
//path 1 samll one
Point[] araay = new Point[]{new Point(144,320),new Point(109,200), new Point(171,308),new Point(178,240),new Point(171,172),new Point(109,282),new Point(144,160)};
AddBeziers(path2, araay, 320, 144);
AddLine(path2, 216, 144 );
AddLine(path2, 216, 216 );
AddLine(path2, 144, 320);
fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
fillPaint.setColor(Color.WHITE);
fillPaint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
fillPaint.setAntiAlias(true);
fillPaint.setDither(true);
fillPaint.setStrokeJoin(Paint.Join.ROUND);
fillPaint.setStrokeCap(Paint.Cap.ROUND);
fillPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
protected Path AddLine(Path path, int endX, int endY) {
//path.moveTo(startX, startY);
path.lineTo(endX, endY);
return path;
}
protected Path AddBeziers(Path path, Point[] points, int lastX, int lastY) {
if (points[0].X != lastX && points[0].Y != lastY)
path.moveTo(points[0].X, points[0].Y);
int index = 1;
path.cubicTo(points[index].X, points[index].Y, points[index + 1].X,
points[index + 1].Y, points[index + 2].X, points[index + 2].Y);
index = index + 3;
path.cubicTo(points[index].X, points[index].Y, points[index + 1].X,
points[index + 1].Y, points[index + 2].X, points[index + 2].Y);
return path;
/*pointsCounter = points.length;
//point = new PointNew(new PointF(points[1].X, points[1].Y));
prev = new PointNew(new PointF(points[0].X, points[0].Y));
//next = new PointNew(new PointF(points[2].X, points[2].Y));
for (int i =1; i < points.length; i++)
appendToPath(path, new PointF(points[i].X, points[i].Y), null);
return path;*/
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmapPuzzle, 0, 0, fillPaint);
super.onDraw(canvas);
}
Can you try with my version of createPath()? I modified it slightly to draw larger puzzle and to accept stroke width as an argument.
public void createPath(int strokeWidth)
{
//path 2 Big one
Point[]araay = new Point[]{new Point(144,320),new Point(109,200), new Point(171,308),new Point(178,240),new Point(171,172),new Point(109,282),new Point(144,160)};
Point[]braay = new Point[araay.length];
int idx = 6;
for(Point p : araay)
braay[idx--] = new Point((200 + p.x), p.y);
path2.moveTo(144,320);
AddBeziers(path2, araay, 320, 144);
AddLine(path2, 216, 144);
AddBeziers(path2, braay, 320, 144);
AddLine(path2, 144, 320);
path2.close();
Matrix m = new Matrix();
m.setScale(2, 2);
path2.transform(m);
MaskFilter mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
fillPaint.setColor(Color.WHITE);
fillPaint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
fillPaint.setAntiAlias(true);
fillPaint.setDither(true);
fillPaint.setStrokeJoin(Paint.Join.ROUND);
fillPaint.setStrokeCap(Paint.Cap.ROUND);
fillPaint.setStrokeWidth(strokeWidth);
fillPaint.setStyle(Paint.Style.FILL_AND_STROKE);
fillPaint.setStrokeMiter(0);
}
While generating the qr code for android using zxing library is it possible to set the version number like version 4 or any other version .
Any guidance or link would be appreciable .
Thank you.
Yes check the EncodedHintType map:
private Bitmap stringToQRCode(String text, int width, int height) {
BitMatrix bitMatrix;
try {
HashMap<EncodeHintType, Object> map = new HashMap<>();
map.put(EncodeHintType.CHARACTER_SET, "utf-8");
map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
map.put(EncodeHintType.QR_VERSION, 9); // (1-40)
map.put(EncodeHintType.MARGIN, 2); // pixels
bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, map);
int bitMatrixWidth = bitMatrix.getWidth();
int bitMatrixHeight = bitMatrix.getHeight();
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
int colorWhite = 0xFFFFFFFF;
int colorBlack = 0xFF000000;
for (int y = 0; y < bitMatrixHeight; y++) {
int offset = y * bitMatrixWidth;
for (int x = 0; x < bitMatrixWidth; x++) {
pixels[offset + x] = bitMatrix.get(x, y) ? colorBlack : colorWhite;
}
}
Bitmap bitmap = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight, Bitmap.Config.ARGB_4444);
bitmap.setPixels(pixels, 0, width, 0, 0, bitMatrixWidth, bitMatrixHeight);
return bitmap;
} catch (Exception i) {
i.printStackTrace();
return null;
}
}
No. There would be no real point to this. The version can't be lower than what is required to encode the data, and setting it higher just makes a denser QR code that's slightly harder to read.
How can I convert byte array received using socket.
The C++ client send image data which is of type uchar.
At the android side I am receiving this uchar array as byte[] which is ranges from -128 to +127.
What I wanted to do is that receives this data and display it. For that I was trying to convert to Bitmap using BitmapFactory.decodeByteArray(), but no luck I am getting null Bitmap. Am I doing right or any other method available.
Thanks in advance....
From the comments to the answers above, it seems like you want to create a Bitmap object from a stream of RGB values, not from any image format like PNG or JPEG.
This probably means that you know the image size already. In this case, you could do something like this:
byte[] rgbData = ... // From your server
int nrOfPixels = rgbData.length / 3; // Three bytes per pixel.
int pixels[] = new int[nrOfPixels];
for(int i = 0; i < nrOfPixels; i++) {
int r = data[3*i];
int g = data[3*i + 1];
int b = data[3*i + 2];
pixels[i] = Color.rgb(r,g,b);
}
Bitmap bitmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
I've been using it like below in one of my projects and so far it's been pretty solid. I'm not sure how picky it is as far as it not being compressed as a PNG though.
byte[] bytesImage;
Bitmap bmpOld; // Contains original Bitmap
Bitmap bmpNew;
ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
bmpOld.compress(Bitmap.CompressFormat.PNG, 100, baoStream);
bytesImage = baoStream.toByteArray();
bmpNew = BitmapFactory.decodeByteArray(bytesImage, 0, bytesImage.length);
edit: I've adapted the code from this post to use RGB, so the code below should work for you. I haven't had a chance to test it yet so it may need some adjusting.
Byte[] bytesImage = {0,1,2, 0,1,2, 0,1,2, 0,1,2};
int intByteCount = bytesImage.length;
int[] intColors = new int[intByteCount / 3];
int intWidth = 2;
int intHeight = 2;
final int intAlpha = 255;
if ((intByteCount / 3) != (intWidth * intHeight)) {
throw new ArrayStoreException();
}
for (int intIndex = 0; intIndex < intByteCount - 2; intIndex = intIndex + 3) {
intColors[intIndex / 3] = (intAlpha << 24) | (bytesImage[intIndex] << 16) | (bytesImage[intIndex + 1] << 8) | bytesImage[intIndex + 2];
}
Bitmap bmpImage = Bitmap.createBitmap(intColors, intWidth, intHeight, Bitmap.Config.ARGB_8888);
InputStream is = new java.net.URL(urldisplay).openStream();
byte[] colors = IOUtils.toByteArray(is);
int nrOfPixels = colors.length / 3; // Three bytes per pixel.
int pixels[] = new int[nrOfPixels];
for(int i = 0; i < nrOfPixels; i++) {
int r = (int)(0xFF & colors[3*i]);
int g = (int)(0xFF & colors[3*i+1]);
int b = (int)(0xFF & colors[3*i+2]);
pixels[i] = Color.rgb(r,g,b);
}
imageBitmap = Bitmap.createBitmap(pixels, width, height,Bitmap.Config.ARGB_4444);
bmImage.setImageBitmap(imageBitmap );