代碼出處:http://opencv.org/ 的 OpenCV for Android version 2.4.5
.../OpenCV-2.4.5-android-sdk/samples/face-detection/
# 1 如何讓opencv使用前后相機?
玩opencv4Android的sample時發現,sample僅做了后置的相機的識別。
那么如何使用讓他可以對frontCamera進行處理呢?
於是google發現了這個:http://answers.opencv.org/question/4226/how-i-use-front-camera-with-new-opencv-243-for/
答案提出了通過修改openCVlibrary的庫參數來達到使用frontCamera的目的。
再那個2.43的環境下只能寫死,或者自己再這塊重寫opencv的Library。
於是准備改時意外發現了2.45與2.43不同,多了個參數
--> 2.43
private boolean initializeCamera(int width, int height) { synchronized (this) { // +1 表示使用frontCamera +0 表示使用backCamera mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID +1); if (mCamera == null) return false; if (mCamera.isOpened() == false) return false; ....
--> 2.45
private boolean initializeCamera(int width, int height) { synchronized (this) { // 多了mCameraIndex參數 看來此參數是用來改變 [front,back]{1} if (mCameraIndex == -1) mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID); else mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID + mCameraIndex); if (mCamera == null) return false; if (mCamera.isOpened() == false) return false;
有沒有發現2.45的版本多了個mCameraIndex參數。然后發現mCameraIndex是寫在CameraBridgeViewBase的類里的,而CameraBridgeViewBase類是 JavaCameraView 和 NativeCameraView 的父類。
我們知道如果要讓屏幕出現照相機的話必定是在屏幕里放置一個layout,然后再layout里布局各種參數和放置的位置。
實例化layout:
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.fd_activity_surface_view);
由上面我們知道獲取的實例是CameraBridgeViewBase,所以推測一定是把上面的mCameraIndex的參數寫在layout里。
搜了下官方文檔,確實有寫:http://docs.opencv.org/trunk/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.html?highlight=javacameraview
opencv:show_fps="true" andopencv:camera_id="any" options enable FPS message and allow to use any camera on device. Application tries to use back camera first.
看到這句話 心里小小的激動了下。。。
接下來要實現切換前后鏡頭的思路就是需要按按鈕時觸發切換整個layout(因為前后參數是寫在layout里的),切換layout方法,http://www.pocketdigi.com/20110509/269.html
--------2013-5-18--add-----------------------
上面的思路是通過切換整個layout來達到切屏的目的,還可以通過更換layout上的view,來達到同樣的目的。啟發自: OpenCV Tutorial 1 - Camera Preview
寫一個layout,里面包含2個view:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:opencv="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <org.opencv.android.JavaCameraView android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone" android:id="@+id/tutorial1_activity_java_surface_view" opencv:show_fps="true" opencv:camera_id="any" /> <org.opencv.android.NativeCameraView android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone" android:id="@+id/tutorial1_activity_native_surface_view" opencv:show_fps="true" opencv:camera_id="any" /> </LinearLayout>
然后再Activity里直接修改 CameraBridgeViewBase 就行:
if (mIsJavaCamera) mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view); else mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view);
意外發現
按照sample提供的切換javaCamera 和 NativeCamera 的方法依樣畫葫蘆的加了切換前后鏡頭的方法。卻發現點擊Menuitem卻且不了前置鏡頭。 后來發現是代碼的bug。。。
1 private int mDetectorType; 2 ... 3 else if (item == mItemType) { 4 mDetectorType = (mDetectorType + 1) % mDetectorName.length; 5 item.setTitle(mDetectorName[mDetectorType]); 6 // 此處。。 7 setDetectorType(mDetectorType); 8 ... 9 10 private void setDetectorType(int type) { 11 if (mDetectorType != type) { 12 mDetectorType = type; 13 14 if (type == NATIVE_DETECTOR) { 15 Log.i(TAG, "Detection Based Tracker enabled"); 16 mNativeDetector.start(); 17 } else { 18 Log.i(TAG, "Cascade detector enabled"); 19 mNativeDetector.stop(); 20 } 21 } 22 }
mDetectorType是個全局變量調用函數時給他的參數也是mDetectorType,再setDetector函數里進行了
if (mDetectorType != type (即 mDetectorType) ) {...}
哎,永遠進步了if了。。。
我的解決方法: 改成臨時變量就行。。
int tmpDetectorType = (mDetectorType + 1) % mDetectorName.length; item.setTitle(mDetectorName[tmpDetectorType]); setDetectorType(tmpDetectorType);
狠狠插入 - 關於openCV Library是什么?JavaCameraView和NativeCameraView的區別是什么?
openCV Library 其實就是個 c++實現的openCV庫的 java接口,通過jni調用。
從package org.opencv.android;可以看到,initOpenCV的時候先獲取library list,大概是各個cpp文件。
Log.d(TAG, "Trying to get library list"); try { System.loadLibrary("opencv_info"); libs = getLibraryList(); }
然后 全部無腦載入內存
private static boolean initOpenCVLibs(String Libs) { Log.d(TAG, "Trying to init OpenCV libs"); boolean result = true; if ((null != Libs) && (Libs.length() != 0)) { Log.d(TAG, "Trying to load libs by dependency list"); StringTokenizer splitter = new StringTokenizer(Libs, ";"); while(splitter.hasMoreTokens()) { result &= loadLibrary(splitter.nextToken()); } } ...
如果自己寫的opencv c++程序編譯后,通過此方法載入:
private static boolean loadLibrary(String Name) { boolean result = true; Log.d(TAG, "Trying to load library " + Name); try { System.loadLibrary(Name); Log.d(TAG, "OpenCV libs init was ok!"); } catch(UnsatisfiedLinkError e) { Log.d(TAG, "Cannot load library \"" + Name + "\""); e.printStackTrace(); result &= false; } return result; }
JavaCameraView和NativeCameraView的區別
之前有過各種猜測直到看到了這個。。。 http://docs.opencv.org/trunk/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.html?highlight=javacameraview
First of all we create our application view using xml layout. Our layout consists of the only one full screen component of class org.opencv.android.JavaCameraView. This class is implemented inside OpenCV library. It is inherited from CameraBridgeViewBase, that extends SurfaceView and uses standard Android camera API. Alternatively you can use org.opencv.android.NativeCameraView class, that implements the same interface, but uses VideoCapture class as camera access back-end.
而在facedetect的sample里的
private CascadeClassifier mJavaDetector; private DetectionBasedTracker mNativeDetector;
讓我混亂了很久,我開始以為他們分別代表了javaCameraView和NativeCameraView,其實他們都是基於javaCameraView,(是否是基於javaCameraView主要看他的layout里給他配的是Java還是Native,上面有提到),
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.fd_activity_surface_view);
而這里的javaDetector表示使用android的sdk提供的借口來調用opencv,而NativeDector表示調用自己寫得本地cpp文件,本地cpp import相應的頭文件,並調用opencv借口,在這個sample里其實他們都是調用同一個opencv接口。
待續。。