2015-08-28 46 views
9

Hey, küçük kamera uygulaması oluşturuyorum Her şeyi uygulamam var ama NV21 bayt dizisini jpeg biçimine dönüştüren bir sorunum var
Birçok yol buldum ama hepsi bile ben bu pasajı çalıştı ve aynı cihazda çalışır Xperia z2 5.2 değil, galaxy s4 4.4.4 daNV21 bayt dizisini bitmap okunabilir biçime dönüştürün

bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 

bu yolda çalışmak ve diğer

başarısız çalışan ya
öncelikle bazı cihazlarda çalışmıyor ikincisi

ben kod çözme NV21 dönüştürmek için birçok çözüm çalıştı birincisi renderscript kod

public Bitmap convertYUV420_NV21toRGB8888_RenderScript(byte [] data,int W, int H, Fragment fragment) { 
    // http://stackoverflow.com/questions/20358803/how-to-use-scriptintrinsicyuvtorgb-converting-byte-yuv-to-byte-rgba 
    RenderScript rs; 
    ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; 
    rs = RenderScript.create(fragment.getActivity()); 
    yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); //Create an intrinsic for converting YUV to RGB. 

    Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length); 
    Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); //an Allocation will be populated with empty data when it is first created 

    Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H); 
    Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); //an Allocation will be populated with empty data when it is first created 

    in.copyFrom(data);//Populate Allocations with data. 

    yuvToRgbIntrinsic.setInput(in); //Set the input yuv allocation, must be U8(RenderScript). 
    yuvToRgbIntrinsic.forEach(out); //Launch the appropriate kernels,Convert the image to RGB. 


    Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888); 
    out.copyTo(bmpout); //Copy data out of Allocation objects. 
    return bmpout; 

} 

ve ayrıca bu kod

void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { 

    final int frameSize = 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); 
     } 

    } 
} 

ve nihayet sd kart üzerinde görüntüyü kaydetmek için çalıştı ve daha sonra yeniden 'u yeniden açın, ancak aynı zamanda

File pictureFile = new File(filename); 
      int pich = camera.getParameters().getPreviewSize().height; 
      int picw = camera.getParameters().getPreviewSize().width; 
      Rect rect = new Rect(0, 0,picw, pich); 
      YuvImage img = new YuvImage(data, ImageFormat.NV21, picw, picw, null); 

      try { 
       FileOutputStream fos = new FileOutputStream(pictureFile); 
       img.compressToJpeg(rect, 100, fos); 
       fos.write(data); 
       fos.close(); 

ve bu enter image description here

+0

Jpeg'i almak istiyorsanız, lütfen sorunuzu yeniden adlandırın, NV21'i RGB'ye dönüştürmek istediğiniz gibi görünüyor, bu tamamen farklı bir görev. –

+0

Resmi nasıl görüntülediniz? Jpeg dosyasını bir ImageView'a yükleyin? –

cevap

13

kamera, daha sonra bir YuvImage dönüştürerek olmak üzere kaydetmeden kolay yolu gelen bir NV21 çerçevesini kurtarmak için birkaç yol vardır izleyin Ben son 3 yaklaşımla sonucudur jpeg dosyası: Alternatif

FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/imagename.jpg"); 
YuvImage yuvImage = new YuvImage(nv21bytearray, ImageFormat.NV21, width, height, null); 
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, fos); 
fos.close(); 

, ayrıca Android Bitmap nesnesine dönüştürmek ve PNG veya başka bir biçim olarak kaydedebilirsiniz:

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(); 

Not t Son seçeneğe şapka bir NV21 -> JPEG -> Bitmap Object -> PNG file işlemi yapar, bu yüzden yüksek performansa ihtiyacınız varsa, fotoğraf makinesinden önizleme görüntülerini kaydetmenin çok verimli bir yol olmadığını unutmayın.

GÜNCELLEME: Ben kolayca bir satır kod bunu yapmanın RenderScript etrafında bir kitaplığı (easyRS) yazdı o kadar çalışması için bu dönüşüm için ne kadar sürdüğünü yoruldum:

Bitmap outputBitmap = Nv21Image.nv21ToBitmap(rs, nv21ByteArray, width, height); 

Yaklaşık beş olduğunu Moto G 2nd'da bir 2000x2000 görüntüdeki JPEG işleminden daha hızlı zamanlar.

2

İkinci denemeniz (ScriptIntrinsicYuvToRGB ile) ümit verici görünüyor. Daha yüksek Jellybean 4.3 (API18) veya aşağıdaki ( NV21 olmalıdır kamera önizleme biçimi) yapmak ile :

İlk olarak bir yöntemde veya bir döngü içinde rs, yuvToRgbIntrinsic ve tahsisleri oluşturmak Sakın nerede komut dosyası çalıştırılacak. Bu, uygulamanızı son derece yavaşlatır ve yetersiz bellek hatalarına neden olabilir. (Eğer Type.Builder nesneleri gerek yok!) Api18 ile

rs = RenderScript.create(this); // create rs object only once and use it as long as possible 
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); // ditto. 

+ tahsisleri çok daha kolay oluşturulur: onCreate() .. yöntemde bunlar koyun.senin cameraPreviewWidth ile ve tahsis Ain oluşturmak cameraPreviewHeight:

bmpout = Bitmap.createBitmap(cameraPreviewWidth, cameraPreviewHeight, Bitmap.Config.ARGB_8888); 

ve sadece bu Bitmap'ten août ayırma oluşturmak:

int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2; // this is 12 bit per pixel 
aIn = Allocation.createSized(rs, Element.U8(rs), yuvDatalength); 

Çıktı için bir Bitmap ihtiyaç

aOut = Allocation.createFromBitmap(rs, bmpout); 

senaryoyu Set ´s ayırma (yalnızca bir kez, döngü dışında ):

"Kamera loop" byte [] verilerle yapmak olarak
yuvToRgbIntrinsic.setInput(aIn); //Set the input yuv allocation, must be U8(RenderScript). 

: Örneğin

aIn.copyFrom(data); // or aIn.copyFromUnchecked(data); // which is faster and safe with camera data 

yuvToRgbIntrinsic.forEach(aOut); //Launch the appropriate kernels,Convert the image to RGB. 

aOut.copyTo(bmpout); // copy data from Allocation aOut to Bitmap bmpout 

, Nexus 7'de (2013, Jellybean 4.3) tam HD (1920x1080 piksel) kamera önizleme dönüşüm yaklaşık 7 alır MS.

İlgili konular