2014-11-22 17 views
5

Tôi gặp phải sự cố lạ khi sử dụng trình giả lập Android & OpenCV CameraBridgeViewBase.OpenCV Android - vấn đề màu sắc bằng cách sử dụng CameraBridgeViewBase

Sử dụng onCameraFrame Tôi nhận được ảnh có vẻ như không được giải mã đúng cách.

public Mat onCameraFrame(CvCameraViewFrame inputFrame) { 
    return inputFrame.rgba(); 
} 

Sử dụng 'inputFrame.gray()' Tôi nhận được những gì mong đợi - hình ảnh đen trắng mà không có hiện vật hoặc bất kỳ vấn đề nào khác.

Đó là những gì tôi nhận được:

First picture

One more picture (a bigger one)

Những gì tôi đã cố gắng cho đến nay:

  1. các cấp API khác nhau (từ 15 đến 21).
  2. Trình mô phỏng khác nhau: Bộ mô phỏng & Google Android.
  3. Kiến trúc nền tảng khác nhau - cả ARM và Intel x86.
  4. Khởi chạy bộ mô phỏng trên máy tính xách tay khác nhau với Linux: hoạt động như mong đợi, sự cố đã biến mất!
  5. Khởi chạy ứng dụng, sử dụng OpenCV, được tải xuống từ Cửa hàng Play. Họ DO làm việc! Tuy nhiên:
    1. Khởi chạy ứng dụng hoạt động như mong đợi, sau đó đóng ứng dụng.
    2. Khởi chạy ứng dụng của bạn (hoặc một trong các hướng dẫn OpenCV), sau đó đóng ứng dụng.
    3. Khởi chạy lại ứng dụng từ bản 5.1, tôi thấy rằng nó bị ảnh hưởng bởi cùng một lỗi!
  6. Phiên bản OpenCV khác nhau (2.4.9 và 2.4.10).
  7. Các phiên bản khác nhau của trình quản lý OpenCV (một từ Cửa hàng Play và 2.4.9 & 2.4.10 từ gói OpenCV).
  8. Cuối cùng, như tôi đã nhận thấy trong 5.2, các tệp .apk được biên dịch trước từ gói OpenCV cũng bị ảnh hưởng bởi sự cố.

Mọi thứ hoạt động như mong đợi trên các thiết bị Android thực của tôi.

Sau khi xem các nguồn của các lớp máy ảnh CameraBridgeViewBase và Java/Native, tôi đã đưa ra quyết định rằng sự cố xảy ra trong khi giải mã hình ảnh. Có thể có vấn đề với định dạng đầu ra máy ảnh nền tảng cụ thể (YUV, NV21). Tuy nhiên, thật lạ lùng khi .gray() đưa ra một hình ảnh thích hợp (không có hiện vật).

Tôi đang sử dụng Mac OS X 10.10 Yosemite và MacBook Air với máy ảnh "FaceTime HD" nếu điều đó quan trọng.

Bất kỳ ý tưởng nào về cách khắc phục sự cố này & trợ giúp trong việc tìm ra thư mục gốc của vấn đề được đánh giá cao!

Trả lời

7

Vì vậy, sau khi xem xét sự cố, tôi đã tìm thấy thư mục gốc của vấn đề.

Hãy xem lớp OpenCV JavaCameraView và lớp cơ sở CameraBridgeViewBase của chúng tôi. Vấn đề là khung máy ảnh nhận được là byte[] mảng trong phương thức onPreviewFrame đã được giải mã không chính xác.

Nơi chính xác của mã nơi quá trình giải mã diễn ra là một thực hiện các phương pháp Mat rgba() trong nội JavaCameraFrame lớp của JavaCameraView: Phương pháp

public Mat rgba() { 
     Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4); 
     return mRgba; 
    } 

Như chúng ta thấy, Imgproc.cvtColor (...) được sử dụng để chuyển đổi khung hình từ YUV sang RGBA. NV21 YUV -> RGBA chuyển đổi diễn ra ở đó. Trong quá trình khởi tạo, chúng ta thiết lập định dạng cho NV21, vì vậy điều này sẽ đúng. Hơn nữa, every Android device should support NV21. Ngoài ra, chúng tôi có thể kiểm tra xem thiết bị có chấp nhận định dạng bằng trình gỡ lỗi hay không:

protected boolean initializeCamera(int width, int height) { 
    ... 
    params.setPreviewFormat(ImageFormat.NV21); 
    ... 
    mCamera.setParameters(params); 
    ... 
    params = mCamera.getParameters(); 
    Log.d(TAG, String.format("Actual preview format is 0x%X", params.getPreviewFormat())); 
} 

Cả điện thoại (HTC Sensation) và trình mô phỏng đều báo cáo đang sử dụng NV21.

Tuy nhiên, nếu chúng ta thay đổi COLOR_YUV2RGBA_NV21 thành COLOR_YUV2RGB_I420 (YV12 và I420 là giống nhau, chỉ với Y và V đảo ngược;), chúng ta sẽ thấy trình giả lập sẽ có một không gian màu thích hợp. Thay đổi NV21 thành YV12 trong params.setPreviewFormat(ImageFormat.NV21); chúng tôi sẽ nhận được kết quả tương tự. Có vẻ như có lỗi trong Imgproc.cvtColor hoặc trong Android.

Đây là giải pháp. Thay đổi public Mat rgba() theo cách sau:

public Mat rgba() { 
     if (previewFormat == ImageFormat.NV21) { 
      Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4); 
     } 
     else if (previewFormat == ImageFormat.YV12) { 
      Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 4); // COLOR_YUV2RGBA_YV12 produces inverted colors 
     } 
     return mRgba; 
    } 

previewFormat là một int biến mới, nó tuyên bố như sau:

private int previewFormat = ImageFormat.NV21; 

Add thay đổi đối với khởi tạo sau:

protected boolean initializeCamera(int width, int height) { 
     ... 
       params.setPreviewFormat(ImageFormat.NV21); 
       // "generic" = android emulator 
       if (Build.BRAND.equalsIgnoreCase("generic")) { 
        params.setPreviewFormat(ImageFormat.YV12); 
       } 
       ... 
       mCamera.setParameters(params); 
       params = mCamera.getParameters(); 
       previewFormat = params.getPreviewFormat(); 
     ... 
} 

quan trọng :
Xin lưu ý: đây chỉ là một giải pháp tạm thời để làm cho OpenCV có thể sử dụng được với trình giả lập trong trường hợp của tôi. Nghiên cứu thêm nên được thực hiện. Nó khá dễ dàng để kiểm tra xem thiết bị sử dụng định dạng hình ảnh chính xác trong onPreviewFrame. Tôi sẽ quay lại điều này khi tôi có thời gian.

+1

Sử dụng Android Studio 1.5.1 và mô phỏng API 23, ở trên chỉ hoạt động khi '" generic "' được đổi thành '" android "'.Hoạt động hoàn hảo sau sự thay đổi đó. –

+0

Tôi chỉ cố gắng này và nó hoạt động tốt. Mặc dù, tôi không chắc chắn đây có phải là cách tiếp cận ưa thích hay không, nó phải được cố định theo một cách khác. Tôi đã tạo ra một vấn đề trong kho lưu trữ OpenCV, nơi nếu điều này được chấp nhận, nó có thể được gửi như một yêu cầu kéo. –

+1

Để truy xuất nguồn gốc: https://github.com/opencv/opencv/issues/8166 –

0

Đối với những người bạn sử dụng genymotion, BRAND sẽ không gọi chung chung. Để giải quyết việc này chỉ đơn giản là thay đổi mã để

... 
if (Build.BRAND.equalsIgnoreCase("generic") | Build.BRAND.equalsIgnoreCase("Android")) { 
... 

và nó nên làm việc, hoặc chỉ in các THƯƠNG HIỆU bạn đang sử dụng và thay thế nó vào "Android"

PS Điều kiện thứ hai sẽ bao gồm các trường hợp rằng bạn đang sử dụng genymotion cũng là một trình giả lập.

Cheers

+0

Có lẽ tôi nên giải thích thêm, điều kiện thứ 2 hoặc "điều kiện" sẽ bao gồm nếu bạn đang sử dụng genymotion là trình giả lập và thường được sử dụng bởi một số người nhất định. – PDragon

+0

Lưu ý rằng điều kiện phải là || và không | –

0

Vấn đề này được cố định hiện nay trong các mã trong git, như Kéo Yêu cầu https://github.com/opencv/opencv/pull/8168 đã được sáp nhập. Nó sẽ có sẵn trong phiên bản phát hành tiếp theo.

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