Преобразование кадра предварительного просмотра в растровое изображение - PullRequest
11 голосов
/ 22 января 2011

Я знаю, что тема была на доске много раз, но я все равно не могу заставить ее работать ... Я хочу сохранить кадры просмотра из предварительного просмотра в файлы JPEG.Это выглядит более или менее (код упрощен - без дополнительной логики, исключений и т. Д.) Вот так ...

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;

 }

Вот один из методов, которые я пытался преобразовать в цвета (я полагаю, из этой доски)

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;   
    } 

Проблема в том, что изображение всегда выглядит как три "странные зеленые картинки" ... Я новый пользователь, поэтому не могу опубликовать его: (

Я не знаю, еслиэто имеет отношение к размеру или к чему, но я застрял ... Можете ли вы поддержать меня с этим?

Ответы [ 5 ]

17 голосов
/ 04 апреля 2016

В качестве альтернативы, если вам DO по какой-то причине требуется растровое изображение и / или вы хотите сделать это без создания YUVImage и сжатия в JPEG, вы можете использовать удобный 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;
}
10 голосов
/ 11 сентября 2012

Простое сохранение в формате JPEG является более простой задачей, чем преобразование в растровое изображение, нет необходимости в этом коде декодирования YUV благодаря классу YuvImage.

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(); 
    } 
} 
1 голос
/ 08 февраля 2016

Чтобы избежать ухудшения изображения JPEG на выходе (например, с чередованием зеленых / красных пятен), вам необходимо очистить и закрыть FileOutputStream

FileOutputStream filecon = new FileOutputStream(file); 
image.compressToJpeg( 
            new Rect(0, 0, image.getWidth(), image.getHeight()), 90, 
        filecon);
filecon.flush();
filecon.close();
1 голос
/ 16 июля 2012

Если я не ошибаюсь, вы хотите, чтобы ширина и высота изображения декодировались, а не ширина и высота предварительного просмотра.

0 голосов
/ 11 февраля 2011

как я выяснил, ширина и высота, считанные из PreviewSize, были неправильными ... Другими словами, преобразование пошло не так, потому что оно основывалось на ложных значениях.После использования нового способа установки параметров предварительного просмотра (из примера, удаленного Google) все работает нормально.

РЕДАКТИРОВАТЬ:

Извините за быстрый ответ выше и длительной задержки.

Это было недавно, и я не могу выкопать код сейчас, но я думаю, что я использовал:

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

и взял первый элемент из списка и установить значения с помощью

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

Я сохранил ширину и высоту и использовал их для преобразования изображения.

Он не знает, было ли это лучшим решением, но это сработало.

...