Android camera2 YUV 2048x1536 image captured is stretched (not the preview) - android

I'm trying to capture a YUV image but is stretched. I'm using Android Camera2 following this https://github.com/googlearchive/android-Camera2Basic. The Android SDK is 28.
I'm facing a weird behavior when I capture a camera frame in YUV 2048x1536 from the method setOnImageAvailableListener() using the ImageReader. The capture is stretched:
YUV 2048x1536 stretched
What I do:
pictureImageReader.setOnImageAvailableListener(
reader -> {
Image image = reader.acquireLatestImage();
if(image != null){
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
image.close();
}
}, mBackgroundHandler);
To convert image to bitmap I used this How to convert android.media.Image to bitmap object?:
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
However if I change the resolution my capture is fine (YUV 960x720):
YUV 960x720 ok
I don’t know why the capture in YUV 2048x1536 is stretched and in YUV 960x720 isn’t it. The only change is the resolution
Thanks

Does the device actually list 2048x1536 as a supported size in its stream configuration map? Sometimes camera devices will accept a resolution they don't actually list, but then can't properly output it.
If that size is listed, then this may just be a bug on that device's camera implementation, unfortunately.
(Also, it looks like you're capturing JPEG images, not uncompressed YUV, not that it necessarily matters here).

Related

Camera2 control image orientation

I have created camera screen based on Google camera2 sample, all code almost identical, the camera takes photo and saves it on the device in JPEG format, but I have some weird behavior.
For example, taking photo from emulator rotates the image 90 degrees(the image rotated, not preview), on my Huawei the image not rotated.
What weird is that screen rotation and sensor orientation values is identical both on Emulator and Huawei.
So how exactly the jpeg orientation is sets?
Also while exploring CaptureRequest.JPEG_ORIENTATION
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation))
I have noticed that this method have no effect on Emulator at all.
I have tried to get JPEG orientation from ExifInterface after bitmap saved, but in both Emulator and Huawei the value is ORIENTATION_UNDEFINED. Maybe while converting Image(from ImageReader) to File Exif tags ignored?
Maybe i need to set the ExifInterface manually while taking image, but if the values is identical what is the difference?
How we supposed to control the JPEG orientation?
Using this method to get orientation(from Google camera2 sample) result is 90 degrees for Emulator and Huawei.
private int getOrientation(int rotation) {
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
using this method to get Bitmap from ImageReader
public static Bitmap getBitmapFromReader(ImageReader reader) {
Bitmap bitmap = null;
Image image = null;
try {
image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
buffer.rewind();
byte[] data = new byte[buffer.capacity()];
buffer.get(data);
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
}
if (image != null) {
image.close();
}
return bitmap;
}
Emulator is a very bad starting point to work with Camera2 API. Essentially, it has LEGACY Camera2 support, with some quirks.
This said, Jpeg orientation is a very delicate topic on Android camera. The official docs explain that rotation request may apply to the image itself, or to EXIF flag only, but some devices (which Huawai did you test?) don't comply at all.
Also note that BitmapFactory.decodeByteArray() ignores the EXIF flag, since the very beginning.

WebP fast compression

I would like to use WebP format because it compresses (encodes) images very good (good quality and small size)
But on Android the next method to compress bitmap to WebP works quite slow
130-140 ms for bitmap with 640x360 resolution on device with Snapdragon 625
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP, 40, stream)
val webpBytes = stream.toByteArray()
Is there any faster method on Android to convert Bitmap or raw frame from camera (NV12) to compressed WebP image? Mb a third-party library?
I tried OpenCV and it works a little faster (100-107) but still it's not enough
MatOfInt params = new MatOfInt(Imgcodecs.IMWRITE_WEBP_QUALITY, 10);
MatOfByte matOfByte = new MatOfByte();
Imgcodecs.imencode(".webp", mat, matOfByte, params);
byte[] webpBytes = matOfByte.toArray();

Convert YUV imageformat to PNG

I was struggeling to get YuvImage to a png imageformat on an Android 5.0.1 device where the png showed up as green images. On a Android 5.1.1 this did not happend, and the images was showing just fine.
After some time I found out that there is a bug in Android 5.0.1 which makes the images that are converted appear green. This was fixed in Android 5.1.1
However, does anyone know about a solution in order to make this work on devices that has not got this fix?
I don't think there is a way to workaround the bug because in my experience the images are already green when generated by the system, and it is not a problem of the conversion to PNG.
I see that you are using the Camera 2 API from your comment response, and since you are using YUV format I believe you are trying to save images from the continuous feed from the camera (as opposed from full resolution picture taking). If that is the case, I'll suggest using the older Camera API if at all possible, as I haven't seen a device that does not work when capturing preview images in YUV format (NV21), which can easily converted to a PNG, although having to go through a JPEG step:
YuvImage yuvImage = new YuvImage(nv21bytearray, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream os = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, os);
byte[] jpegByteArray = os.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length);
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/imagename.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
with nv21bytearray being the NV21 byte array returned by the old camera API onPreviewFrame(...) method.

Compress a 1080p video pngs into small size

I am developing an app which generate .png images from a 1080p video. But the pngs are in MBs, and even my app is crashing due to large size of pngs. I want to compress or something like that to reduce the size of each png. I have done a lot of methods like createScaledBitmap, or compress(CompressFormat.PNG, 20, stream); or Bitmap.createBitmap(source, 0, 0, source.getWidth(),source.getHeight(), m, true); also searched a lot of methods.
But it's not reducing the size as much as I want. it still remains in 2.2+ MB per png.
Any idea other than these. Thanks.
I am also building an app which deals with high resolution images but on server side. I am compressing and re-sizing the image on server side by using thumbnailator-0.4.8.jar. Example
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage bImageFromConvert = ImageIO.read( in );
BufferedImage newImage = Thumbnails.of(bImageFromConvert).size(213, 316).asBufferedImage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newImage, "jpg", baos);
baos.flush();
retVal = baos.toByteArray();
baos.close();

Android Camera Preview is corrupting image output on G2?

I'm using Android's Camera and SurfaceView to show a the preview image to the user before taking a picture. This appears fine on the screen but when I take the picture the resulting jpg is corrupted (horizontal lines).
As a starting point I used Mark Murphy's Camera/Picture example which exhibits the same issue on the G2.
The camera paramaters:
preview size: 800x480
picture format: JPEG
Both parameters are supported according to the getSupportedPreviewSizes() and getSupportedPictureFormats()
The Nexus One, which has the same size screen, works correctly with the same parameters.
The G2 works correctly when setting the preview size to 640x480
My question: Has anyone else run into this issue before (corrupted image despite using supported settings)? How frequent is it? How did you work around it?
So far I had the same issue and now I manage to fix mine using
setPictureFormat(ImageFormat.JPEG);
Camera parameter settings.
Just recently found out that the camera default picture output was YUV. That's is why it shows perfectly on preview but once the picture is taken you would get a green or pink or corrupted image output.
These are the ImageFormat values which camera might support.
JPEG = 256;
NV16 = 16;
NV21 = 17;
RAW10 = 37;
RAW_SENSOR = 32;
RGB_565 = 4;
UNKNOWN = 0;
YUV_420_888 = 35;
YUY2 = 20;
YV12 = 842094169;
So other than the supported size, on some cases we might need to check the PictureFormat as well.
http://i.stack.imgur.com/PlHFH.png
These are just sample images taken using ImageFormat YUV and thus saving it as JPEG compression.
But in any case that you don't want to change the ImageFormat and thus keep the settings in YUV format you may need to save the image in this workaround:
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
YuvImage image = new YuvImage(data, parameters.getPreviewFormat(),
size.width, size.height, null);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YuvImage.jpg");
FileOutptStream filecon = new FileOutputStream(file);
image.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 90,
filecon);

Categories

Resources