Ứng dụng máy ảnh của tôi hiển thị xem trước máy ảnh trên màn hình và cũng xử lý nó ở chế độ nền. Đây là mã có liên quan, đặc càng nhiều càng tốt (ví dụ như không xử lý hoặc lĩnh vực khai báo lỗi hiển thị):Cách tải dữ liệu xem trước của máy ảnh Android?
public final class CameraView extends SurfaceView implements
SurfaceHolder.Callback, Runnable, PreviewCallback {
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
void openCamera() {
// Called from parent activity after setting content view to CameraView
mCamera = Camera.open();
mCamera.setPreviewCallbackWithBuffer(this);
}
public void surfaceCreated(SurfaceHolder holder) {
new Thread(this).start();
// Set CameraView to the optimal camera preview size
final Camera.Parameters params = mCamera.getParameters();
final List<Camera.Size> sizes = params.getSupportedPreviewSizes();
final int screenWidth = ((View) getParent()).getWidth();
int minDiff = Integer.MAX_VALUE;
Camera.Size bestSize = null;
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// Find the camera preview width that best matches the
// width of the surface.
for (Camera.Size size : sizes) {
final int diff = Math.abs(size.width - screenWidth);
if (diff < minDiff) {
minDiff = diff;
bestSize = size;
}
}
} else {
// Find the camera preview HEIGHT that best matches the
// width of the surface, since the camera preview is rotated.
mCamera.setDisplayOrientation(90);
for (Camera.Size size : sizes) {
final int diff = Math.abs(size.height - screenWidth);
if (Math.abs(size.height - screenWidth) < minDiff) {
minDiff = diff;
bestSize = size;
}
}
}
final int previewWidth = bestSize.width;
final int previewHeight = bestSize.height;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = previewHeight;
layoutParams.width = previewWidth;
setLayoutParams(layoutParams);
params.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(params);
int size = previewWidth * previewHeight *
ImageFormat.getBitsPerPixel(params.getPreviewFormat())/8;
mBuffer = new byte[size];
mCamera.addCallbackBuffer(mBuffer);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
public void onPreviewFrame(byte[] data, Camera camera) {
CameraView.this.notify();
}
public void run() {
mThreadRun = true;
while (mThreadRun) {
synchronized (this) {
this.wait();
processFrame(mBuffer); // convert to RGB and rotate - not shown
}
// Request a new frame from the camera by putting
// the buffer back into the queue
mCamera.addCallbackBuffer(mBuffer);
}
mHolder.removeCallback(this);
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
public void surfaceDestroyed(SurfaceHolder holder) {
mThreadRun = false;
}
}
Trên tất cả các thiết bị, màn hình máy ảnh xem trước đúng cách, và trên hầu hết (giả lập, Samsung Galaxy S3, vv .) Dữ liệu được lưu trữ trong mBuffer
cũng chính xác (sau khi chuyển đổi và xoay vòng NV21 sang RGB, tất nhiên). Tuy nhiên, một số thiết bị không cung cấp dữ liệu chính xác trong onPreviewFrame. Tôi chắc chắn rằng dữ liệu đang được chuyển đổi sang RGB một cách chính xác sau khi nó nhận được, do đó, vấn đề dường như trong dữ liệu thô được cung cấp cho mBuffer
. Tôi đã nhận thấy this bug report liên quan đến định dạng xem trước máy ảnh YV12 (bí danh YUV420p), nhưng tôi đang sử dụng giá trị mặc định cũ, NV21 (bí danh YUV420sp), phải được hỗ trợ theo số compatibility standard (xem 7.5.3.2, cuối trang 29)).
Ví dụ, đối với cảnh này (hiển thị ở đây trong Máy ảnh Preview trên Samsung Galaxy Tab 2):
dữ liệu truyền cho mBuffer
trên Tab 2 trông giống như:
và trên Motorola Droid 4 có dạng:
Cách chính xác để nhận dữ liệu xem trước máy ảnh Android trên tất cả các thiết bị là gì?
Chỉnh sửa: cho processFrame()
, tôi đã sử dụng OpenCV để chuyển đổi thành RGB và xoay. Xem this answer và this answer.
Làm thế nào để bạn hiển thị/quá trình hình ảnh? – EJTH
@EJTH Tôi sử dụng OpenCV (phương thức 'cvtColor' với cờ' COLOR_YUV420sp2RGBA'). –
Vì vậy, im đoán rằng bạn đang thực hiện chuyển đổi sang RGB trên một cái gì đó không phải là một thiết bị Android? Ngoài sự tò mò, 'YuvImage.compressToJpeg()' có tạo ra một hình ảnh méo mó tương tự không? – EJTH