[英]How can I show image taken from camera
I'm trying to write an android app, that works with the camera. 我正在尝试编写可与相机配合使用的android应用。 I show a preview of the camera in a textureview, that is working.
我在Textureview中显示了相机的预览,可以正常工作。 If you press a button the camera will take a picture and show it on an imageview on the second half of the screen.
如果按下按钮,相机将拍摄照片并将其显示在屏幕后半部分的图像视图中。 But everytime I press the button my app stops working, it tells me the error
但是每当我按下按钮时,我的应用就会停止运行,它会告诉我错误
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl $ CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。
So I looked it up, and it seems I can't change the image of the imageview as I try to. 所以我抬起头来,似乎无法更改imageview的图像。 But I don't know how else I could solve my problem.
但是我不知道我还能怎么解决我的问题。 Can you give me some advise?
你能给我一些建议吗? Here is my code: The image is changed in the "ImageReader.OnImageAvailableListener" in the method takePicture().
这是我的代码:在takePicture()方法的“ ImageReader.OnImageAvailableListener”中更改了图像。
public class MainActivityOld extends Activity {
private TextureView mTextureView;
private ImageView mImageView;
private CameraDevice mCameraDevice;
private Size mPreviewSize;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mPreviewSession;
private Button mBtnShot;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//no titlebar
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
mTextureView = (TextureView) findViewById(R.id.texture);
mTextureView.setSurfaceTextureListener(mSurfaceListener);
mImageView = (ImageView) findViewById(R.id.lastPicture);
mBtnShot = (Button) findViewById(R.id.btn_takepicture);
mBtnShot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePicture();
}
});
}
private void takePicture() {
Log.e("MyTag", "Take picture");
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
Size[] jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
int width = jpegSizes[0].getWidth();
int height = jpegSizes[0].getHeight();
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mImageView.setImageBitmap(bitmap);
}
};
HandlerThread thread = new HandlerThread("CameraPicture");
thread.start();
final Handler backgroundHandler = new Handler(thread.getLooper());
reader.setOnImageAvailableListener(readerListener,backgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
startPreview();
}
};
mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];
manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e("MyTag", "openCamera");
}
private TextureView.SurfaceTextureListener mSurfaceListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Log.e("myLog", "onSurfaceTextureAvailable, width=" + width + ",height=" + height);
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
Log.e("myTag", "onOpened");
mCameraDevice = camera;
startPreview();
}
@Override
public void onDisconnected(CameraDevice camera) {
Log.e("myTag", "onDisconnected");
}
@Override
public void onError(CameraDevice camera, int error) {
Log.e("myTag", "onDisconnected");
}
};
protected void startPreview() {
if (mCameraDevice == null || mTextureView.isAvailable() || mPreviewSize == null) {
Log.e("MyTag", "startPreview failed, still working, so just ignore it");
// return;
}
SurfaceTexture texture = mTextureView.getSurfaceTexture();
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface surface = new Surface(texture);
try {
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
} catch (CameraAccessException e) {
e.printStackTrace();
}
mPreviewBuilder.addTarget(surface);
try {
mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
mPreviewSession = session;
updatePreview();
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
Toast.makeText(MainActivityOld.this, "onConfigureFailed", Toast.LENGTH_LONG).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
protected void updatePreview() {
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
Handler backgroundHandler = new Handler(thread.getLooper());
try {
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
As the Exception
says CalledFromWrongThreadException
, your readerListener
is working on another thread, from where you cannot change your views. 正如
Exception
所说的CalledFromWrongThreadException
,您的readerListener
正在另一个线程上工作,在该线程上您无法更改视图。
Change your code to: 将您的代码更改为:
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){
@Override
public void onImageAvailable(final ImageReader reader) {
MainActivityOld.this.runOnUIThread(new Runnable() {
@Override
public void run() {
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mImageView.setImageBitmap(bitmap);
}
});
}
};
I think you will be better of trying to stream to a surface view, not sure if this can even be done with a imageview. 我认为您最好尝试流式传输到表面视图,不确定是否可以使用imageview来完成。
try this tutorial it should get you going in the right direction 试试本教程,它应该使您朝正确的方向前进
or this for a more up to date example provided by google 或者这是由Google提供的最新示例
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.