2015-05-28 27 views
9

Tôi đang viết một ứng dụng lấy nguồn cấp dữ liệu máy ảnh, chuyển đổi nó thành rgb, để thực hiện một số thao tác.Chuyển đổi máy ảnh Android2 api YUV_420_888 thành RGB

Nó hoạt động tốt trên triển khai máy ảnh cũ sử dụng định dạng NV21 Yuv. Sự cố tôi gặp phải là với định dạng Yuv mới, YUV_420_888. Hình ảnh không còn được chuyển đổi chính xác sang RGB trong Camera2 Api mới, sẽ gửi định dạng yUV_420_888 yuv thay vì định dạng NV21 (YUV_420_SP).

Ai đó có thể vui lòng cho tôi biết tôi nên chuyển YUV_420_888 thành RGB như thế nào?

Cảm ơn

+0

thể trùng lặp của [Chuyển đổi YUV-> RGB (Xử lý ảnh) -> YUV trong onPreviewFrame trong android ?] (http://stackoverflow.com/questions/9325861/converting-yuv-rgbimage-processing-yuv-during-onpreviewframe-in-android) – JAL

+0

Đó là để thực hiện máy ảnh cũ hơn, điều đó không giúp tôi. Cảm ơn bạn mặc dù. –

+0

Có ai đã chuyển YUV_420_888 thành NV21 (YUV_420_SP) không? –

Trả lời

5

Trong phương pháp của tôi, tôi sử dụng OpenCV Mat và kịch bản từ https://gist.github.com/camdenfullmer/dfd83dfb0973663a7974

Trước hết bạn chuyển đổi YUV_420_888 hình ảnh của bạn để Mat với mã trong liên kết ở trên.

* mImage là đối tượng hình ảnh của tôi mà tôi nhận được trong ImageReader.OnImageAvailableListener

Mat mYuvMat = imageToMat(mImage); 

public static Mat imageToMat(Image image) { 
    ByteBuffer buffer; 
    int rowStride; 
    int pixelStride; 
    int width = image.getWidth(); 
    int height = image.getHeight(); 
    int offset = 0; 

    Image.Plane[] planes = image.getPlanes(); 
    byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888)/8]; 
    byte[] rowData = new byte[planes[0].getRowStride()]; 

    for (int i = 0; i < planes.length; i++) { 
     buffer = planes[i].getBuffer(); 
     rowStride = planes[i].getRowStride(); 
     pixelStride = planes[i].getPixelStride(); 
     int w = (i == 0) ? width : width/2; 
     int h = (i == 0) ? height : height/2; 
     for (int row = 0; row < h; row++) { 
      int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888)/8; 
      if (pixelStride == bytesPerPixel) { 
       int length = w * bytesPerPixel; 
       buffer.get(data, offset, length); 

       if (h - row != 1) { 
        buffer.position(buffer.position() + rowStride - length); 
       } 
       offset += length; 
      } else { 


       if (h - row == 1) { 
        buffer.get(rowData, 0, width - pixelStride + 1); 
       } else { 
        buffer.get(rowData, 0, rowStride); 
       } 

       for (int col = 0; col < w; col++) { 
        data[offset++] = rowData[col * pixelStride]; 
       } 
      } 
     } 
    } 

    Mat mat = new Mat(height + height/2, width, CvType.CV_8UC1); 
    mat.put(0, 0, data); 

    return mat; 
} 

Chúng tôi có 1 kênh YUV Mát. Xác định Mat mới cho BGR (không RGB chưa) hình ảnh:

Mat bgrMat = new Mat(mImage.getHeight(), mImage.getWidth(),CvType.CV_8UC4); 

Tôi chỉ mới bắt đầu học OpenCV để propably này không nhất thiết phải là 4-kênh Mat và thay vào đó có thể là 3 kênh nhưng nó làm việc cho tôi. Bây giờ tôi sử dụng phương pháp chuyển đổi màu để thay đổi yuv Mat của tôi thành bgr Mat.

Imgproc.cvtColor(mYuvMat, bgrMat, Imgproc.COLOR_YUV2BGR_I420); 

Bây giờ chúng ta có thể làm tất cả những xử lý hình ảnh như tìm đường nét, màu sắc, hình tròn, vv Để in hình ảnh lại trên màn hình chúng ta cần phải chuyển nó sang bitmap:

Mat rgbaMatOut = new Mat(); 
Imgproc.cvtColor(bgrMat, rgbaMatOut, Imgproc.COLOR_BGR2RGBA, 0); 
final Bitmap bitmap = Bitmap.createBitmap(bgrMat.cols(), bgrMat.rows(), Bitmap.Config.ARGB_8888); 
Utils.matToBitmap(rgbaMatOut, bitmap); 

Tôi có tất cả của tôi xử lý hình ảnh trong chuỗi riêng biệt để thiết lập ImageView của tôi, tôi cần thực hiện điều này trên chuỗi giao diện người dùng.

runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         if(bitmap != null) { 
          mImageView.setImageBitmap(bitmap); 
         } 
        } 
       }); 
+0

Cảm ơn bạn đã nhập mã. Điều này làm việc cho tôi. – Brian

0

Khoảng 10 nhanh hơn so với đề cập "imageToMat" -Function trên lần là mã này:

Image image = reader.acquireLatestImage(); 
... 
Mat yuv = new Mat(image.getHeight() + image.getHeight()/2, image.getWidth(), CvType.CV_8UC1); 
ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 
final byte[] data = new byte[buffer.limit()]; 
buffer.get(data); 
yuv.put(0, 0, data); 
... 
image.close(); 
+0

Tôi không thấy câu trả lời của bạn có thể đúng ... imageToMat và chức năng đơn giản hơn của bạn mà tôi đã thử nghiệm tạo ra hai mảng byte khác nhau. Nó sẽ là tốt nếu OpenCV có thể xử lý định dạng YUV mới này từ Camera2 api.Nhưng chuyển đổi tiếp theo: Imgproc.cvtColor (mYuvMat, bgrMat, mgproc.COLOR_YUV2BGR_I420); là rất quan trọng và đối với tất cả thử nghiệm của tôi chỉ imageToMat tạo ra kết quả tốt. Nếu có YUV2BGR_CAMERA2_API câu trả lời của bạn sẽ tốt hơn. Và có lẽ bây giờ. Đã hai tháng sau rồi;) –

Các vấn đề liên quan