Intereting Posts
Как импортировать проект студии Android в eclipse, который использует библиотеку? Обратное геокодирование – Сервис недоступен – Перезапустить устройство, не решающее окончательно – критиковать мое ручное обратное геокодирование Android IllegalStateException Не зарегистрировано ни одного инструментария! Должен работать под регистрирующим оборудованием Доступ к TextView Groupview из getChildView () в ExpandableListView Не может использовать Arrays.copyOfRange Более длительный тайм-аут экрана для конкретной активности Android? Прозрачность изображения на Android Тестовые события не были получены – Android Studio Экспортированная служба не требует разрешения: что это значит? Как получилось, что предварительный просмотр камеры в текстурном представлении гораздо более нечеткий, чем в плане поверхности? Можно ли изменить направление RatingBar? Android WebView SSL «Предупреждение о безопасности» Обновления местоположения не работают в помещении, как утверждают API-интерфейсы поставщика Fusion Location IllegalStateException: <MyFragment> в настоящее время отсутствует в FragmentManager Android_Chronometer pause

Android Camera2 API YUV_420_888 для JPEG

Я получаю кадры предварительного просмотра, используя OnImageAvailableListener :

@Override public void onImageAvailable(ImageReader reader) { Image image = null; try { image = reader.acquireLatestImage(); Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); byte[] data = new byte[buffer.capacity()]; buffer.get(data); //data.length=332803; width=3264; height=2448 Log.e(TAG, "data.length=" + data.length + "; width=" + image.getWidth() + "; height=" + image.getHeight()); //TODO data processing } catch (Exception e) { e.printStackTrace(); } if (image != null) { image.close(); } } 

Каждый раз длина данных различна, но ширина и высота изображения одинаковы.
Основная проблема: data.length слишком мала для такого разрешения, как 3264×2448.
Размер массива данных должен быть 3264 * 2448 = 7 990 272, а не 300 000 – 600 000.
Что не так?


 imageReader = ImageReader.newInstance(3264, 2448, ImageFormat.JPEG, 5); 

Solutions Collecting From Web of "Android Camera2 API YUV_420_888 для JPEG"

Я решил эту проблему, используя формат изображения YUV_420_888 и преобразовывая его в формат изображения JPEG вручную.

 imageReader = ImageReader.newInstance(MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT, ImageFormat.YUV_420_888, 5); imageReader.setOnImageAvailableListener(this, null); 

 Surface imageSurface = imageReader.getSurface(); List<Surface> surfaceList = new ArrayList<>(); //...add other surfaces previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); previewRequestBuilder.addTarget(imageSurface); surfaceList.add(imageSurface); cameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() { //...implement onConfigured, onConfigureFailed for StateCallback }, null); 

 @Override public void onImageAvailable(ImageReader reader) { Image image = reader.acquireLatestImage(); if (image != null) { //converting to JPEG byte[] jpegData = ImageUtils.imageToByteArray(image); //write to file (for example ..some_path/frame.jpg) FileManager.writeFrame(FILE_NAME, jpegData); image.close(); } } 

 public final class ImageUtil { public static byte[] imageToByteArray(Image image) { byte[] data = null; if (image.getFormat() == ImageFormat.JPEG) { Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); data = new byte[buffer.capacity()]; buffer.get(data); return data; } else if (image.getFormat() == ImageFormat.YUV_420_888) { data = NV21toJPEG( YUV_420_888toNV21(image), image.getWidth(), image.getHeight()); } return data; } private static byte[] YUV_420_888toNV21(Image image) { byte[] nv21; ByteBuffer yBuffer = image.getPlanes()[0].getBuffer(); ByteBuffer uBuffer = image.getPlanes()[1].getBuffer(); ByteBuffer vBuffer = image.getPlanes()[2].getBuffer(); int ySize = yBuffer.remaining(); int uSize = uBuffer.remaining(); int vSize = vBuffer.remaining(); nv21 = new byte[ySize + uSize + vSize]; //U and V are swapped yBuffer.get(nv21, 0, ySize); vBuffer.get(nv21, ySize, vSize); uBuffer.get(nv21, ySize + vSize, uSize); return nv21; } private static byte[] NV21toJPEG(byte[] nv21, int width, int height) { ByteArrayOutputStream out = new ByteArrayOutputStream(); YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, width, height, null); yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out); return out.toByteArray(); } } 

 public final class FileManager { public static void writeFrame(String fileName, byte[] data) { try { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName)); bos.write(data); bos.flush(); bos.close(); // Log.e(TAG, "" + data.length + " bytes have been written to " + filesDir + fileName + ".jpg"); } catch (IOException e) { e.printStackTrace(); } } } 

Я не уверен, но я думаю, что вы берете только один из плоскостей формата YUV_420_888 (часть яркости).

В моем случае я обычно преобразовываю свое изображение в байт [].

  Image m_img; Log.v(LOG_TAG,"Format -> "+m_img.getFormat()); Image.Plane Y = m_img.getPlanes()[0]; Image.Plane U = m_img.getPlanes()[1]; Image.Plane V = m_img.getPlanes()[2]; int Yb = Y.getBuffer().remaining(); int Ub = U.getBuffer().remaining(); int Vb = V.getBuffer().remaining(); data = new byte[Yb + Ub + Vb]; //your data length should be this byte array length. Y.getBuffer().get(data, 0, Yb); U.getBuffer().get(data, Yb, Ub); V.getBuffer().get(data, Yb+ Ub, Vb); final int width = m_img.getWidth(); final int height = m_img.getHeight(); 

И я использую этот байтовый буфер для преобразования в rgb.

Надеюсь это поможет.

Приветствия. Унаи.

Ваш код запрашивает изображения в формате JPEG, которые сжимаются. Они будут меняться по размеру для каждого кадра, и они будут намного меньше, чем несжатое изображение. Если вы не хотите ничего делать, кроме сохранения изображений JPEG, вы можете просто сохранить то, что у вас есть в байтах [], на диск, и все готово.

Если вы хотите что-то сделать с помощью JPEG, вы можете использовать BitmapFactory.decodeByteArray (), чтобы преобразовать его в Bitmap, например, хотя это довольно неэффективно.

Или вы можете переключиться на YUV, что более эффективно, но вам нужно сделать больше работы, чтобы получить Bitmap.