Convert preview frame to bitmap

I know that a theme has been on board many times, but I can’t get it to work anyway ... I want to save view frames from preview to jpeg files. It looks more or less (the code is simplified - without additional logic, exceptions, etc.), How is it ...

public void onPreviewFrame(byte[] data, Camera camera) { int width = camera.getParameters().getPreviewSize().width; int height = camera.getParameters().getPreviewSize().height; final int[] rgb = decodeYUV420SP(data, width, height); Bitmap bmp = Bitmap.createBitmap(rgb, width, height,Bitmap.Config.ARGB_8888); String filename="/sdcard/file" + (index++)+ ".jpg"; FileOutputStream out; out = new FileOutputStream(filename); bmp.compress(Bitmap.CompressFormat.JPEG, 90, out); out.flush(); out.close(); out=null; } 

Here is one of the methods that I tried to convert colors (from this board, I believe)

 public int[] decodeYUV420SP( byte[] yuv420sp, int width, int height) { final int frameSize = width * height; int rgb[]=new int[width*height]; for (int j = 0, yp = 0; j < height; j++) { int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); } } return rgb; } 

The problem is that the picture always looks like three "strange green pictures" ... I am a new user, so I can not post it :(

I don’t know if it has anything to do with size or what, but I'm stuck ... Can you support me?

+9
android camera preview frame yuv
source share
5 answers

since I found out that the width and height read from PreviewSize were wrong .... In other words, the conversion went wrong because it was based on false values. After using the new way to adjust the preview settings (from an example, remote Google), everything works fine.

EDIT:

Sorry for the quick answer above and the long delay.

It was a long time ago, and I can’t dig out the code now, but I think I used:

http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getSupportedPreviewSizes ()

and took the first item from the list and set the values ​​with

http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewSize (int, int)

I saved the width and height and used it to convert the image.

He does not know if this was the best solution, but it worked out.

0
source share

Alternatively, if for some reason you need a Bitmap image and / or want to do it without creating YUVImage and JPEG compression, you can use the convenient RenderScript 'ScriptIntrinsicYuvToRGB' (API 17+):

 @Override public void onPreviewFrame(byte[] data, Camera camera) { Bitmap bitmap = Bitmap.createBitmap(r.width(), r.height(), Bitmap.Config.ARGB_8888); Allocation bmData = renderScriptNV21ToRGBA8888( mContext, r.width(), r.height(), data); bmData.copyTo(bitmap); } public Allocation renderScriptNV21ToRGBA8888(Context context, int width, int height, byte[] nv21) { RenderScript rs = RenderScript.create(context); ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length); Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height); Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); in.copyFrom(nv21); yuvToRgbIntrinsic.setInput(in); yuvToRgbIntrinsic.forEach(out); return out; } 
+15
source share

Simple saving in jpeg is a simpler task than converting to a bitmap, no need for this YUV decoding code thanks to the YuvImage class.

 import android.graphics.YuvImage; @Override public void onPreviewFrame(byte[] data, Camera camera) { try { Camera.Parameters parameters = camera.getParameters(); Size size = parameters.getPreviewSize(); YuvImage image = new YuvImage(data, parameters.getPreviewFormat(), size.width, size.height, null); File file = new File(Environment.getExternalStorageDirectory(), "out.jpg"); FileOutputStream filecon = new FileOutputStream(file); image.compressToJpeg( new Rect(0, 0, image.getWidth(), image.getHeight()), 90, filecon); } catch (FileNotFoundException e) { Toast toast = Toast .makeText(getBaseContext(), e.getMessage(), 1000); toast.show(); } } 
+10
source share

If I'm not mistaken, you want the width and height of the image to be decoded, not the width and height of the preview.

+1
source share

To avoid degradation of the JPEG image at the output (for example, alternating green / red spots), you need to hide and close the FileOutputStream

 FileOutputStream filecon = new FileOutputStream(file); image.compressToJpeg( new Rect(0, 0, image.getWidth(), image.getHeight()), 90, filecon); filecon.flush(); filecon.close(); 
+1
source share

Source: https://habr.com/ru/post/651371/


All Articles