簡單的Android Camera2與BoofCV
目錄
本文將演示BoofCV如何大大簡化在Android上使用相機的工作。
介紹
本文將演示BoofCV的Android庫如何極大地簡化了Camera2 API的使用,處理相機影象以及視覺化結果。Android開發和 Camera2
使用BoofCV,您只需要告訴它您想要的解析度,實現影象處理功能,以及(可選)編寫視覺化功能。BoofCV將選擇相機,開啟相機,建立執行緒池,同步資料結構,處理Android生命週期(正確開啟/關閉相機,停止執行緒),轉換YUV420影象,正確對齊輸入畫素到螢幕畫素,以及根據要求更改相機設定。
我們將在本文中討論的是編寫自己的自動聚焦例程。雖然不像使用最新的深度學習那樣性感(例如,對所有物體進行分類,老化你的臉),但這篇文章是關於實用和製作有用的東西。不管你的計算機視覺演算法有多麼令人驚訝,如果應用程式總是崩潰!一旦你理解了這段程式碼是如何工作的,你就可以將它與其他演算法結合起來,以便將相機專注於狗而不是人。
自動聚焦演算法
聚焦和失焦影象的示例。請注意焦點影象中邊緣強度如何變大?
內建自動對焦的行為因製造商和計算機視覺應用程式而異,我的經驗是他們傾向於專注於除了你想要的任何東西。為了解決這個問題,我們將通過手動控制相機的焦點並使用最大影象“最清晰”找到焦點值來進行自己的自動對焦。影象的清晰度由其梯度強度決定。影象的梯度是其x和y空間導數。梯度的強度可以以不同的方式定義。在這裡,我們使用歐幾里德範數,即sqrt(dx**2 + dy**2)。
自動聚焦演算法是有限狀態機,如上所述。它詳盡地遍歷所有焦點值以選擇具有最大邊緣強度的焦點值。一旦找到最大邊緣強度,它就會固定焦點。您可以通過輕擊螢幕重新開始該過程。
原始碼亮點
此時,您應該檢視Github上的原始碼並稍微探索一下程式碼。我們將逐步完成在原始碼本身中設定您自己的專案和重要行的關鍵步驟。假設您已經對Android開發有所瞭解,並且為了簡潔起見,跳過了一些步驟。
第一步:在Android Studio中建立一個新專案
這篇文章被標記為中介軟體,所以我假設你可以在沒有圖片和視訊的情況下做到這一點。最小的SDK必須是22.這是修復了Camera 2 API中一個令人討厭的bug的第一個版本。
第二步:依賴性
將以下內容新增到app / build.gradle中的依賴項欄位。
dependencies {
['boofcv-android', 'boofcv-core'].each {
String a ->
implementation group: 'org.boofcv', name: a, version: '0.32-SNAPSHOT'
}
}
您還需要排除一些傳遞依賴項,因為Android包含自己的版本,並且會發生衝突。
configurations {
all*.exclude group: "xmlpull", module: "xmlpull"
all*.exclude group: "org.apache.commons", module: "commons-compress"
all*.exclude group: "com.thoughtworks.xstream", module: "commons-compress"
}
然後讓Android Studio同步您的Gradle檔案。
第三步:Android許可權
在app / src / main / AndroidManifest.xml中,您需要授予自己對相機的訪問許可權:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera2.full" />
第四步:MainActivity:OnCreate()
您現在應該開啟 MainActivity.java 檔案。注意這個類如何擴充套件 VisualzieCamera2Activity。如果您希望在螢幕上呈現某些內容,那麼您應該擴充套件該活動。否則, 如果您只需要相機框架,則可以擴充套件 SimpleCamera2Activity。
看看 onCreate() 功能。這個功能正在發生很多事情; 獲取相機許可權,指定輸出影象的型別,所需的解析度以及關閉雙緩衝。讓我們一行一行進行。
TextureView顯示原始相機預覽。FrameLayout用於繪製視覺效果。我們還添加了一個觸控偵聽器,以便使用者可以重新啟動焦點演算法。稍後會詳細介紹。
TextureView view = findViewById(R.id.camera_view);
FrameLayout surface = findViewById(R.id.camera_frame);
surface.setOnClickListener(this);
在這裡,我們請求使用者訪問攝像機。這已經在整個web中廣泛地被覆蓋,因此請檢視原始碼,瞭解如何完成此操作。
requestCameraPermission();
BoofCV需要知道我們想要的影象格式。在這裡,我們告訴它給我們一個灰度8點陣圖像。
setImageType(ImageType.single(GrayU8.class));
相機通常支援多種解析度。BoofCV將為我們選擇一個解析度,但我們應該告訴它我們的要求。下面這行是告訴BoofCV找到一個大約有這麼多畫素的影象解析度。通過覆蓋selectResolution()函式可以實現更復雜的邏輯。
targetResolution = 640*480;
BoofCV還將自動渲染捕獲幀。在這種情況下,我們不想這樣做,只顯示原始相機Feed。所以讓我們關閉這種行為。
bitmapMode = BitmapMode.NONE;
最後,我們告訴它啟動相機並使用以下surface和view進行視覺化。
startCamera(surface,view);
第五步:攝像頭控制
預設情況下,攝像機配置為處於全自動模式。我們不希望這樣,所以我們用自己的邏輯覆蓋預設configureCamera()函式。BoofCV定義configureCamera()並且它不是內建的Camera2API函式。直接使用Camera2API完成這項工作需要做很多工作
下面的程式碼註釋描述了每個程式碼塊正在做什麼。實質上,它是上面實現有限狀態機的地方。
@Override
protected void configureCamera(CameraDevice device,
CameraCharacteristics characteristics, CaptureRequest.Builder captureRequestBuilder) {
// set focus control to manual
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
// get a list of acceptable values
Float minFocus = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
switch( state ) {
case INITIALIZE:{
if( minFocus == null ) {
Toast.makeText(this,"manual focus not supported", Toast.LENGTH_SHORT).show();
state = State.UNSUPPORTED;
} else {
focusBestIndex = 0;
focusBestValue = 0;
focusIndex = 0;
focusTime = System.currentTimeMillis()+FOCUS_PERIOD;
state = State.FOCUSING;
captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0f);
}
}break;
case PENDING:{
focusIndex++;
if( focusIndex < FOCUS_LEVELS ) {
focusTime = System.currentTimeMillis()+FOCUS_PERIOD;
captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE,
minFocus*focusIndex/(FOCUS_LEVELS-1));
state = State.FOCUSING;
} else {
captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE,
minFocus*focusBestIndex/(FOCUS_LEVELS-1));
state = State.FIXED;
}
}break;
}
}
第六步:影象處理
BoofCV提供了自己的影象處理功能,可以自動將流式 YUV420_888影象轉換為您理解的影象。它還為您啟動了一個處理影象的執行緒。這意味著您可以隨意使用而不會崩潰!如果您的影象處理無法跟上相機的進給速度,則會丟棄相框。
@Override
protected void processImage(ImageBase image) {
// We specified earlier to give us an 8-bit gray scale image
GrayU8 gray = (GrayU8)image;
// Ensure that work space images are the appropriate size
derivX.reshape(gray.width,gray.height);
derivY.reshape(gray.width,gray.height);
intensity.reshape(gray.width,gray.height);
// Compute the gradient and Euclidean edge intensity
GImageDerivativeOps.gradient(DerivativeType.SOBEL,gray,derivX,derivY, BorderType.EXTENDED);
GGradientToEdgeFeatures.intensityE(derivX, derivY, intensity);
// Find the average edge value
edgeValue = ImageStatistics.mean(intensity);
}
第七步:繪圖
通常,您需要為SurfaceView建立一個回撥,但這也是由您處理的。您仍然需要覆蓋下面的onDrawFrame函式。下面的程式碼是相當標準的Android繪圖,這就是它沒有突出顯示的原因。如果您想了解如何使用BoofCV渲染正在處理的實際影象(不是實時視訊輸入)並將視覺效果與精確畫素對齊,請參閱QR Code示例。
@Override
protected void onDrawFrame(SurfaceView view, Canvas canvas) {
super.onDrawFrame(view, canvas);
....
}
第八步:響應使用者觸控
在onCreate(),我們添加了一個觸控偵聽器。這允許使用者重新啟動自動對焦。下面的程式碼顯示瞭如何完成此操作。通過等待自動對焦處於FIXED狀態,我們無需擔心相機是否繁忙,從而簡化了程式碼。
@Override
public void onClick(View v) {
// If the user touches the screen and it has already finished focusing, start again
if( state == State.FIXED ) {
state = State.INITIALIZE;
changeCameraConfiguration();
}
}
使用其他計算機視覺庫
在這個例子中,我們使用BoofCV進行影象處理。沒有理由不能使用OpenCV等其他庫或您最喜歡的深度學習庫(例如Torch)。您需要做的是將BoofCV影象轉換為其他庫能夠理解的影象。這比首先獲得影象要容易得多!你可以完全在BoofCV影象中訪問原始位元組陣列和影象特性(例如,width,height,stride)。
其他例子
BoofCV的儲存庫包括一些額外的極簡主義Android示例。
結論
我們能夠在Android上建立一個功能齊全的計算機視覺應用程式,它可以處理庫中的相機設定,同時處理影象並向用戶顯示資訊。在沒有廣泛瞭解Android生命週期、Camera2 API如何工作、或者瞭解YUV420使您能夠進入商業領域並且以最少的繁瑣工作建立酷的計算機視覺應用程式的情況下,就完成了此任務!
原文地址:https://www.codeproject.com/Articles/1266363/Easy-Android-Camera2-with-BoofCV