This question already has answers here:
Android Camera2 API YUV_420_888 to JPEG
(3 answers)
Closed 4 years ago.
I am working on AR project where i need to capture the current frame and save it to gallery. I am able to get the image using Frame class in AR core , but the format of image is YUV_420_888. I have already tried lots of solutions to covert this to bitmap but couldn't able to solve it.
This is how I convert to jpeg.
public Bitmap imageToBitmap(Image image, float rotationDegrees) {
assert (image.getFormat() == ImageFormat.NV21);
// NV21 is a plane of 8 bit Y values followed by interleaved Cb Cr
ByteBuffer ib = ByteBuffer.allocate(image.getHeight() * image.getWidth() * 2);
ByteBuffer y = image.getPlanes()[0].getBuffer();
ByteBuffer cr = image.getPlanes()[1].getBuffer();
ByteBuffer cb = image.getPlanes()[2].getBuffer();
ib.put(y);
ib.put(cb);
ib.put(cr);
YuvImage yuvImage = new YuvImage(ib.array(),
ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0,
image.getWidth(), image.getHeight()), 50, out);
byte[] imageBytes = out.toByteArray();
Bitmap bm = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
Bitmap bitmap = bm;
// On android the camera rotation and the screen rotation
// are off by 90 degrees, so if you are capturing an image
// in "portrait" orientation, you'll need to rotate the image.
if (rotationDegrees != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotationDegrees);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bm,
bm.getWidth(), bm.getHeight(), true);
bitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
}
return bitmap;
}
Related
I have a text recognition app and I only want the app to read text within a certain box on my screen. My approach is to crop AN image from my camera before I send it to text recognition. I am having an issue cropping my image first.
If I try to convert the byte to a bitmap then crop it using -
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap resizedbitmap=Bitmap.createBitmap(bmp, 100, 100, 200, 200);
and then use create bitmap to create a new bitmap that is cropped with a RECT - but since it is null it is failing.
I am receiving null for the bitmap - I have tried changing the options, I have added read write permissions to the manifest - but it is still coming up null.
I am now trying to convert the byte array to a yuvimage but I think data is being lost in the compression so when I scan my image - the text recognition is giving me distorted text blocks and it is not very accurate.
int correctRotation = RNCameraViewHelper.getCorrectCameraRotation(rotation, getFacing(),
getCameraOrientation());
if (data.length < (1.5 * width * height)) {
return;
}
if (willCallTextTask) {
textRecognizerTaskLock = true;
TextRecognizerAsyncTaskDelegate delegate = (TextRecognizerAsyncTaskDelegate) cameraView;
final byte[] compressedImage;
final YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
final ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
Log.d("Tag", "Image Stream" + getWidth());
Log.d("Tag", "WIDTH" + width);
Log.d("Tag", "HEIGHT" + height);
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, imageStream);
compressedImage = imageStream.toByteArray();
new TextRecognizerAsyncTask(delegate, mThemedReactContext, compressedImage, width, height, correctRotation,
getResources().getDisplayMetrics().density, getFacing(), getWidth(), getHeight(), mPaddingX, mPaddingY)
.execute();
}
}
});
}
Any suggestions would be great - or if theres a better way to do this that would be amazing!
I have to convert com.google.mlkit.vision.common.InputImage to equivalent Bitmap image in android using Java. Right now I am using the following code.
// iImage is an object of InputImage
Bitmap bmap = Bitmap.createBitmap(iImage.getWidth(), iImage.getHeight(), Bitmap.Config.RGB_565);
bmap.copyPixelsFromBuffer(iImage.getByteBuffer());
The above code is NOT converting the InputImage to Bitmap. Can anyone please suggest me the efficient way of converting InputImage to Bitmap.
You can create bitmap from byteBuffer, that can be received by call the method getByteBuffer().In the offical quick start example of ML Kit Vission you can find the vay how to achieve this. Below is a piece of code that can solve your problem:
Method getBitmap() thats converts NV21 format byte buffer to bitmap:
#Nullable
public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
data.rewind();
byte[] imageInBuffer = new byte[data.limit()];
data.get(imageInBuffer, 0, imageInBuffer.length);
try {
YuvImage image =
new YuvImage(
imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
return rotateBitmap(bmp, metadata.getRotation(), false, false);
} catch (Exception e) {
Log.e("VisionProcessorBase", "Error: " + e.getMessage());
}
return null;
}
Method rotateBitmap():
private static Bitmap rotateBitmap(
Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {
Matrix matrix = new Matrix();
// Rotate the image back to straight.
matrix.postRotate(rotationDegrees);
// Mirror the image along the X or Y axis.
matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
Bitmap rotatedBitmap =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// Recycle the old bitmap if it has changed.
if (rotatedBitmap != bitmap) {
bitmap.recycle();
}
return rotatedBitmap;
}
The full code can be seen by clicking on the link: https://github.com/googlesamples/mlkit/blob/master/android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/BitmapUtils.java
In Android Studio I can use the following lines of code to get an array from Bitmap
Bitmap bitmap = get_Image();
Bitmap resizeBitmap = getResizedBitmap(bitmap);
int[] iArr = new int[(resizeBitmap.getWidth() * resizeBitmap.getHeight())];
resizeBitmap.getPixels(iArr, 0, resizeBitmap.getWidth(), 0, 0, resizeBitmap.getWidth(), resizeBitmap.getHeight());
Here is the resizer function:
public Bitmap getResizedBitmap(Bitmap bitmap) {
if (576 == bitmap.getWidth() && 1024 == bitmap.getHeight()) {
return bitmap;
}
Bitmap createBitmap = Bitmap.createBitmap(576, 1024, Config.RGB_565);
Matrix scaledMatrix = scaledMatrix(bitmap.getWidth(), bitmap.getHeight(), createBitmap.getWidth(), createBitmap.getHeight());
new Canvas(createBitmap).drawBitmap(bitmap, scaledMatrix, null);
return createBitmap;
}
However when I convert that int array back to bitmap the image is wrong
Bitmap bmp = Bitmap.createBitmap(1024, 576, Config.RGB_565);
bmp.setPixels(iArr, 0, 1024, 0, 0, 1024, 576);
textViewToChange.setText("Bitmap created");
This is the image when i save it to a file or display it https://imgur.com/a/ZQ0DJAy The above image is how it looks like and below is how it should had looked like
If i read the incorrect image in python, the RGB pixels are placed exactly where they should be like in the correct image but the image dosen't look the same. Why? How can i fix this?
I have checked many discussion but i can't seem to find an answer. How can i crop and large image taken by a camera and crop it to a 640x640 pixel size? Im returning a URI
EDIT: I would like to allow the user to crop the image!
Another solution would be to use the createScaledBitmap people use to create thumbnails.
byte[] imageData = null;
try
{
final int THUMBNAIL_SIZE = 64;
FileInputStream fis = new FileInputStream(fileName);
Bitmap imageBitmap = BitmapFactory.decodeStream(fis);
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
imageData = baos.toByteArray();
}
catch(Exception ex) {
}
Your bitmap imageBitmap would probably have to come directly from your camera instead of a file, but the general idea stays the same.
You may use
private Bitmap crop(Bitmap src, int x, int y, int width, int height) {
Bitmap dst = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(dst);
canvas.drawBitmap(src, new Rect(0, 0, src.getWidth(), src.getHeight()),
new Rect(x, y, width, height), null);
return dst;
}
Type arguments are self explanatory.
Good luck.
Try this code, using the intent object:
intent.setType("image/*");
intent.putExtra("outputX", int_Height_crop);
intent.putExtra("outputY", int_Width_crop);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
use the below code
You can use this link also for your reference
Click Crop image using rectengle!
int targetWidth = 640;
int targetHeight = 640;
Bitmap targetBitmap = Bitmap.createBitmap(
targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addRect(rectf, Path.Direction.CW);
canvas.clipPath(path);
canvas.drawBitmap(sourceBitmap,
new Rect(0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth, targetHeight), null);
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
imageView.setImageBitmap(targetBitmap);
My question might be old but I am suffering because of this issue from last 2 weeks and now its too much, in my application I need to send large image bitmap to server and I am doing this by below coding:
BitmapFactory.Options bfOptions=new BitmapFactory.Options();
bfOptions.inDither=false; //Disable Dithering mode
bfOptions.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
bfOptions.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
bfOptions.inTempStorage=new byte[32 * 1024];
File file=new File(TabGroupActivity.path);
FileInputStream input=null;
try {
input = new FileInputStream(TabGroupActivity.path);
} catch (FileNotFoundException e) {
//TODO do something intelligent
e.printStackTrace();
}
if(input!=null)
{
bitmap = BitmapFactory.decodeStream(input, null, bfOptions);
}
Matrix mat = new Matrix();//removing rotations
if(TabGroupActivity.rotation==90 || TabGroupActivity.rotation==270)
{
mat.setRotate(90);
}
else if(TabGroupActivity.rotation==0 || TabGroupActivity.rotation==180)
{
mat.setRotate(0);
}
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int height= bitmap.getHeight();
int width=bitmap.getWidth();
{
//formula for calculating aspect ratio
float k= (float) height/width;
newHeight =Math.round(620*k);
}
byte[] buffer=new byte[10];
while(input.read(buffer)!=-1)
{
bos.write(buffer);
}
bitmap = Bitmap.createScaledBitmap(bitmap , 620, newHeight, true);
bitmap.compress(CompressFormat.JPEG, 90, bos);
byte[] imageData = bos.toByteArray();
ContentBody cb = new ByteArrayBody(imageData, "image/jpg", "image1.jpeg");
input.close();
but after sending 2,3 images I am getting out of memory error on BitmapFactory.decodeStream() please help me the resolve this issue the main thing I can not re-size or crop image, I need to send good quality image only to server.
Recycle your bitmaps every time you are done with them by calling bitmap.recycle(), this should help a bit. Also optimize your code a bit; this part:
if(TabGroupActivity.rotation==90 || TabGroupActivity.rotation==270)
{
mat.setRotate(90);
}
else if(TabGroupActivity.rotation==0 || TabGroupActivity.rotation==180)
{
mat.setRotate(0);
}
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true);
You can reduce to
if(TabGroupActivity.rotation==90 || TabGroupActivity.rotation==270)
{
mat.setRotate(90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true);
}
So you don't have to create a new bitmap in every case.
Also, you can experiment with the BitmapFactory.Options.inSampleSize to get smaller images.