我在我的应用程序中制作了自定义相机视图。基本上,只要我的应用程序中的相机在聚焦后打开,我就需要做一些事情。
在我的Camera.Parameters中,我使用了FOCUS_MODE_CONTINUOUS_PICTURE,它按预期完美运行。现在,我需要从这个连续的自动对焦练习回调,在那里我可以拍摄当前的焦点图片并用它做点什么。
另一种方法是勾选一个计时器'技术,每隔一段时间后会触发的功能。然后,我可以在其中使用mCamera.autofocus(),拍照并完成我的工作。不幸的是,这被证明是一种非常糟糕的技术,因为自动聚焦会给不同的设备带来复杂性。
所以,我想知道,这将是什么是完美的解决方案。
更新:使用主题进行尝试后
我想做的是,只要应用程序位于前台,就可以反复自动对焦并拍照。
经过多次不同的尝试,这是我能够到达的最远,但还不够远。
请参阅可运行的代码:
public class OCRRunnable implements Runnable {
static final String TAG = "DBG_" + "OCRRunnable";
private final Object mPauseLockDummyObject;
private boolean mPaused;
private boolean mFinished;
Camera mCamera;
public OCRRunnable(Camera cameraParam) {
mPauseLockDummyObject = new Object();
mPaused = false;
mFinished = false;
mCamera = cameraParam;
}
@Override
public void run()
{
if (mCamera != null) { // since the main activity may have been late opening the camera
try {
mCamera.autoFocus(new mAutoFocusCallback());
Log.d(TAG, "run: mCamera.autofocus()");
} catch (Exception e) {
Log.e(TAG, "run: " + e.getMessage());
}
//sleep necessary //TODO: needs refinement
//try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
//Runnable regulator
synchronized (mPauseLockDummyObject) {
while (mPaused) {
try {
mPauseLockDummyObject.wait();
} catch (InterruptedException e) {
Log.e(TAG, "run: " + e.getMessage());
}
}
}
}
}
/**
* Call this on pause of the activity.
*/
public void onPause() {
//Log.d(TAG, "onPause: called");
synchronized (mPauseLockDummyObject) {
mPaused = true;
}
}
/**
* Call this on resume of the activity
*/
public void onResume() {
//Log.d(TAG, "onResume: called");
synchronized (mPauseLockDummyObject) {
mPaused = false;
mPauseLockDummyObject.notifyAll();
}
}
//////////////////////////////////////
protected class mAutoFocusCallback implements Camera.AutoFocusCallback {
@Override
public void onAutoFocus(boolean success, final Camera camera) {
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken() called");
/* NEED TO RUN THIS CODE PART REPETITIVELY */
camera.cancelAutoFocus(); //be ready for next autofocus
camera.startPreview(); //re-start cameraPreview since taking a picture stops it
run(); //TODO
}
});
}
}
}
这是我的相关片段:
public class ODFragment extends Fragment {
View rootView;
static final String TAG = "DBG_" + MainActivity.class.getName();
private Camera mCamera;
private CameraPreview mCameraPreview;
int ROIHeight;
FrameLayout frameLayout_cameraLens;
TextView words_container;
Thread ocrThread;
OCRRunnable ocrRunnable; //TODO: this may cause problems because mCamera is null as of this moment
public ODFragment() {}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_od, container, false);
//one time tasks
words_container = (TextView) rootView.findViewById(R.id.words_container);
setCameraViewDimensions();
ocrThread = new Thread(ocrRunnable); //start it in onResume()
return rootView;
}
@Override
public void onResume() {
super.onResume();
hookCamera();
}
@Override
public void onPause() {
super.onPause();
unhookCamera();
}
private void hookCamera() {
try {
// 1. open camera
mCamera = Camera.open();
// 2. initialize cameraPreview
mCameraPreview = new CameraPreview(this.getActivity(), mCamera);
// 3. add view to frameLayout
frameLayout_cameraLens.addView(mCameraPreview);
mCamera.startPreview();
// 4. hook camera related listeners and threads
ocrRunnable = new OCRRunnable(mCamera);
ocrThread = new Thread(ocrRunnable);
ocrThread.start();
ocrRunnable.onResume();
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "Could not Camera.open(): " + e.getMessage());
}
}
private void unhookCamera() {
try {
// -4. unhook camera related listeners ans threads
ocrRunnable.onPause();
ocrThread = null;
ocrRunnable = null;
// -3. remove view from frameLayout
frameLayout_cameraLens.removeView(mCameraPreview);
// -2. destroy cameraPreview
mCameraPreview = null;
// -1. close camera
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void setCameraViewDimensions() {
//calculate and set dimensions of cameraLens
DisplayMetrics displaymetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
int height = (int) (width * 1.3333333333333);
//Log.d(TAG, "frameLayout_cameraLens dimensions: "+height+"x"+width);
frameLayout_cameraLens = (FrameLayout) rootView.findViewById(R.id.frameLayout_cameraLens);
frameLayout_cameraLens.getLayoutParams().width = width;
frameLayout_cameraLens.getLayoutParams().height = height;
frameLayout_cameraLens.requestLayout();
//set height of ROI
ROIHeight = height / 5;
LinearLayout linearLayout = (LinearLayout) rootView.findViewById(R.id.ROI);
linearLayout.getLayoutParams().height = ROIHeight;
linearLayout.requestLayout();
}
}
有些观点:
camera.autofocus()
发生在一个单独的线程本身。这就是为什么我没有在while(true)
中放置run()
循环,而是在mAutoFocusCallback
Log.d(TAG, "run: mCamera.autofocus()");
一次。此外,Log.d(TAG, "onPictureTaken() called");
甚至没有调过一次。这是我的相关日志:
05-29 12:51:58.460 W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
05-29 12:51:58.573 D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
05-29 12:51:58.655 W/FragmentManager: moveToState: Fragment state for VTFragment{fd65ec0 #0 id=0x7f0c006d android:switcher:2131492973:1} not updated inline; expected state 3 found 2
05-29 12:51:58.962 D/DBG_CameraPreview: CameraPreview() initialized
05-29 12:51:59.079 D/DBG_OCRRunnable: run: mCamera.autofocus()
05-29 12:51:59.097 I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: Nondeterministic_AU_msm8974_LA.BF.1.1.3_RB1__release_AU (I3f4bae6ca5)
OpenGL ES Shader Compiler Version: E031.29.00.00
Build Date: 02/14/16 Sun
Local Branch: mybranch18261495
Remote Branch: quic/LA.BF.1.1.3_rb1.10
Local Patches: NONE
Reconstruct Branch: NOTHING
05-29 12:51:59.101 I/OpenGLRenderer: Initialized EGL, version 1.4
05-29 12:51:59.366 I/Choreographer: Skipped 46 frames! The application may be doing too much work on its main thread.
05-29 12:51:59.556 I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@c66e1c1 time:44964952
答案 0 :(得分:1)
使用mCamera.autofocus(callback)
- 当焦点准备就绪时将触发回调。这是你拍照的机会。在onPictureTaken()
中,您可能会调用mCamera.cancelAutoFocus(); mCamera.autofocus(callback);
以允许相机重新对焦。
当然,每次相机聚焦时,您都可以选择不拍照。
要提高相机应用的性能,请务必致电Camera.open()
on a background HandlerThread - 否则焦点和图片回调将阻止UI线程。当这些回调偶尔发生时,这可能是可以接受的,但在你的场景中,它们会经常被激活。
更新让我更清楚地呈现建议的循环(伪代码):
cameraInit() {
Open camera, set FOCUS_MODE_CONTINUOUS_PICTURE
camera.autofocus(autofocusCallback)
}
autofocusCallback() {
if (it_is_time_to_take_picture) {
takePicture(pictureCallback)
}
else {
autofocusAgain()
}
}
pictureCallback.onPictureTaken(image) {
autofocusAgain()
save image
}
autofocusAgain() {
camera.cancelAutoFocus()
wait(100ms)
camera.autofocus(autofocusCallback)
}