2016-05-24 17 views
0

自分のアプリケーションでカスタムカメラビューを作成しました。基本的には、アプリケーションのカメラがフォーカスされている限り、何かをする必要があります。アンドロイドでオートフォーカスで連続して画像を撮る

私のCamera.Parametersでは、私はFOCUS_MODE_CONTINUOUS_PICTUREを使用しており、意図どおりに動作します。今、私は、この連続的なオートフォーカスの練習からコールバックが必要です。ここでは、現在のフォーカスされた写真を撮り、何かをすることができます。

もう1つの方法は、一定時間ごとに起動する「タイマー」テクニックをフックすることでした。そして、mCamera.autofocus()を使って写真を撮り、自分の仕事をします。残念なことに、これは非常に悪い技術であることが判明しました。なぜなら、オートフォーカスはさまざまなデバイスに応じて複雑になるからです。

だから私は、これに対する完璧な解決策は何だろうと思っていました。

UPDATE:私は何をしたいかのスレッド

との試みを行った後、オートフォーカスで、限り、アプリがフォアグラウンドにあるよう何度も何度も写真を撮ります。

さまざまな試行の後で、これは私が今までには遠くても遠くないほど遠いです。

実行可能なコードを参照してください:

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()は別のスレッド自体に起こると思います。ここ

    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 
    
    
          } 
    
         }); 
        } 
    
    
    } 
    } 
    

    は私の関連するフラグメントです。それでwhile(true)ループをrun()に入れるのではなく、mAutoFocusCallbackの末尾にrun()を呼び出したのです。

  • この時点では、実行は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: [email protected] time:44964952 

答えて

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) 
} 
+0

こんにちは、あなたの答えをありがとうございました。私の要件は、mCamera.autofocus(コールバック)をスケジュールされた関数で自分で呼び出す必要はないということです。 FOCUS_MODE_CONTINUOUS_PICTUREパラメータの良い点は、カメラが開いている間、繰り返しオートフォーカスが行われることです。このパラメータが自動的に同様のコールバックを呼び出すことはできませんか? –

+0

いいえ、 'autofocus()'の呼び出しにはどのような複雑さがありますか? –

+0

たとえば、3秒ごとに機能を実行するようにスケジュールを設定すると、前回のオートフォーカスの試みが途中で終了していないカメラデバイスが故障している可能性があります。これにより例外が発生します。 例外を処理すると、次のオートフォーカスに6秒間待機します。 リスクを回避して間隔を7秒または8秒に増やすと、この時間はあまりにも有用になりすぎます。 camera.paramterのオートフォーカスの方法はとても良いと高速です –

関連する問題