2016-09-28 2 views
2

저는 onPreviewFrame()에서 얻은 NV21 바이트 []를 변환하려고합니다. 나는 다양한 솔루션을 찾기 위해 포럼과 구글을 수색했다. 나는 RenderScripts와 다른 코드 예제를 시도했다. 그들 중 일부는 나에게 노란색 색조로 이미지를주고, 일부는 빨간색과 파란색으로 뒤집힌 이미지를 제공합니다 (코드에서 뒤집어서 노란색 색조가 나타남). 일부는 이미지 전체에 이상한 컬러 기능을 제공합니다. 거의 네거티브와 같음), 일부는 저에게 그레이 스케일 이미지를 주며, 어떤 이미지는 어둡기 때문에 아무 것도 만들 수 없습니다.Android에서 Bitmap과 NV21, 매우 어두운 이미지, 회색 음영 또는 노란색 색조?

내가 질문을 입력 한 이래로, 나는 우리가 this post으로 시작할 것이므로 나는 방에서 바보가되어야한다는 것을 알았다. 이 특별한 해결책은 나에게 아주 어두운 이미지를 주지만, 나는 아직 코멘트 할 수 없을만큼 충분히 멋지지 않다. 누구나이 솔루션을 사용해 보았거나 원래 NV21 형식과 동일한 품질의 이미지를 생성 한 사람이 있습니까?

올바른 ARGB 바이트 [] 또는 유효한 비트 맵이 필요하며 둘 중 하나를 처리하도록 프로젝트를 수정할 수 있습니다. 그냥 참조를 위해 나는이 (이들 중 정말 탄소 복사하고 몇 가지 다른를) 시도 :

One solution I tried
Another solution I tried

답변

1

, 여기 당신이 시도 할 수있는 무언가이다 :

// import android.renderscript.* 
// RenderScript mRS; 
// ScriptIntrinsicYuvToRGB mYuvToRGB; 
// Allocation yuvPreviewAlloc; 
// Allocation rgbOutputAlloc; 

// Create RenderScript context, ScriptIntrinsicYuvToRGB and Allocations and keep reusing them. 
if (NotInitialized) { 
    mRS = RenderScript.create(this). 
    mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.YUV(mRS));  

    // Create a RS Allocation to hold NV21 data. 
    Type.Builder tYuv = new Type.Builder(mRS, Element.YUV(mRS)); 
    tYuv.setX(width).setY(height).setYuvFormat(android.graphics.ImageFormat.NV21); 
    yuvPreviewAlloc = Allocation.createTyped(mRS, tYuv.create(), Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT); 

    // Create a RS Allocation to hold RGBA data. 
    Type.Builder tRgb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); 
    tRgb.setX(width).tRgb(height); 
    rgbOutputAlloc = Allocation.createTyped(mRS, tRgb.create(), Allocation.USAGE_SCRIPT); 

    // Set input of ScriptIntrinsicYuvToRGB 
    mYuvToRGB.setInput(yuvPreviewAlloc); 
} 

// Use rsPreviewSurface as one of the output surface from Camera API. 
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java#L504 
Surface rsPreviewSurface = yuvPreviewAlloc.getSurface(); 
... 

// Whenever a new frame is available 
// Update the yuv Allocation with a new Camera buffer without any copy. 
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/ViewfinderProcessor.java#L109 
yuvPreviewAlloc.ioReceive(); 
// The actual Yuv to Rgb conversion. 
mYuvToRGB.forEach(rgbOutputAlloc); 

// Copy the rgb Allocation to a Bitmap. 
rgbOutputAlloc.copyTo(mBitmap); 

// continue processing mBitmap. 
... 
+0

카메라 버퍼가 "NV21"이 아닌 경우 "YUV_420_888"및 "YV12"로 재생할 수도 있습니다. –

+0

나는 이것을 시험해보고 있는데, 나는 전에 보지 못했던 오류를 얻는다 : "E/RenderScript : YuvToRGB가 데이터없이 실행되고, 각 미리보기 프레임을 건너 뛰고". 나는 "yuvPreviewAlloc.copyFrom (data);"을 추가하려고 시도했다. 그냥 그런 것이 아니라는 것을 확신하기 위해서입니다. 누구나 이걸 보니? –

+0

이 오류 메시지는 일반적으로 yuvPreviewAlloc 할당이 카메라 API에서 데이터를 가져 오지 않았 음을 의미합니다. rsPreviewSurface가 카메라 출력 화면으로 올바르게 구성되어 있는지 다시 한 번 확인하십시오. 2. ioReceive가 호출 된 경우. 3. USAGE_IO_INPUT이 RenderScript 지원 lib (import android.support.v8.renderscript)와 작동하지 않기 때문에 "import android.renderscript. *"를 사용하고 있는지 확인하십시오. 또한 코드에 몇 가지 주석을 추가하여 설정에 대한 몇 가지 코드 참조를 알려줍니다. –

0

내가 일하는 다른 방법 (이전에 링크 된 하나)를 얻을 수 있었다 코드 here을 사용하여 그러나 그것은 빨강/파랑 색 플립을주고있었습니다. 그래서 저는 U와 V 라인을 재배치했습니다. RenderScript만큼 빠르지는 않습니다. 제대로 작동하는 RenderScript를 갖는 것이 좋을 것입니다. 다음은 코드입니다.

static public 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) { 
       u = (0xff & yuv420sp[uvp++]) - 128; //Just changed the order 
       v = (0xff & yuv420sp[uvp++]) - 128; //It was originally v then u 
      } 

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

색조 및 플립 문제가없는 RenderScript가 있습니까? 당신이 비트 맵에 카메라에서 YUV 변환하려는 경우

1

내가보기 엔 적어도 젤리 빈 4.3 이상 (API18)으로 업데이트하는 것이 좋습니다 ScriptIntrinsics를 사용하여. JB 4.2 (API 17)보다 사용하기가 훨씬 쉽습니다.

ScriptIntrinsicYuvToRGB는 그렇게 복잡하지 않습니다. 특히 Type.Builder 객체가 필요하지 않습니다. 카메라 미리보기 형식 이어야합니다. NV21!

onCreate() ...방법 RenderScript 객체 극한 생성 : 당신 cameraPreviewWidth 함께

mRS = RenderScript.create(this); 
mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.U8_4(mRS));  

와 카메라 데이터를 바이트 배열의 길이 계산 cameraPreviewHeight :

int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2 ; // this is 12 bit per pixel 

사용자가 출력하는 비트 맵을 필요

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

그런 다음 입력 및 출력 할당을 만듭니다 (API18 +의 변경 사항은 여기에 있음)

yuvPreviewAlloc = Allocation.createSized(mRS, Element.U8(mRS), yuvDatalength); 

rgbOutputAlloc = Allocation.createFromBitmap(mRS, mBitmap); // this simple ! 

과, (새로운 프레임이 사용 가능한 때마다) 카메라 루프 입력 할당

mYuvToRGB.setInput(yuvPreviewAlloc); // this has to be done only once ! 

에 스크립트 입력을 설정 yuvPreviewAlloc에 ​​NV21 바이트 배열을 (데이터 []) 복사 스크립트를 실행하고 비트 맵에 결과를 복사 : 예를 들어

yuvPreviewAlloc.copyFrom(data); // or yuvPreviewAlloc.copyFromUnchecked(data); 

mYuvToRGB.forEach(rgbOutputAlloc); 

rgbOutputAlloc.copyTo(mBitmap); 

: 넥서스 7 (2013, 젤리 빈 4.3) 전체의 HD (1920 × 1080) 카메라 미리보기 변환은 약 7 밀리합니다.

+0

이것은 효과가 있으며 잘 작동합니다! 결국 렌더링 스크립트 내에서 처리 작업을 최소한으로 유지하려면 추가 작업을해야했습니다. 그래서 커스텀 렌더 스크립트를 작성해야했습니다 (어느 정도 시간이 걸렸습니다). Renderscript 책에서 유용한 정보를 많이 찾았습니다 (아마존에서 얻었습니다). –