Skip to content

Commit 1169c8c

Browse files
Google ML KitYun Liu
Google ML Kit
authored and
Yun Liu
committed
List of included changes:
- Support auto zoom in the barcode scanning demo. PiperOrigin-RevId: 535307448 Change-Id: I1e2e52d343357a1eae57a0fc492cf505549ddfc3
1 parent c1411e9 commit 1169c8c

13 files changed

+320
-342
lines changed

android/vision-quickstart/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ dependencies {
5656
implementation 'androidx.multidex:multidex:2.0.1'
5757

5858
// Barcode model
59-
implementation 'com.google.mlkit:barcode-scanning:17.1.0'
59+
implementation 'com.google.mlkit:barcode-scanning:17.2.0'
6060
// Or comment the dependency above and uncomment the dependency below to
6161
// use unbundled model that depends on Google Play Services
62-
// implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.2.0'
62+
// implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.0'
6363

6464
// Object detection feature with bundled default classifier
6565
implementation 'com.google.mlkit:object-detection:17.0.0'

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/CameraSource.java

+42
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import android.graphics.SurfaceTexture;
2525
import android.hardware.Camera;
2626
import android.hardware.Camera.CameraInfo;
27+
import android.hardware.Camera.Parameters;
2728
import android.util.Log;
2829
import android.view.Surface;
2930
import android.view.SurfaceHolder;
@@ -243,6 +244,47 @@ public int getCameraFacing() {
243244
return facing;
244245
}
245246

247+
public boolean setZoom(float zoomRatio) {
248+
Log.d(TAG, "setZoom: " + zoomRatio);
249+
if (camera == null) {
250+
return false;
251+
}
252+
253+
Parameters parameters = camera.getParameters();
254+
parameters.setZoom(getZoomValue(parameters, zoomRatio));
255+
camera.setParameters(parameters);
256+
return true;
257+
}
258+
259+
/**
260+
* Calculate the zoom value of the target zoom ratio.
261+
*
262+
* <p>According to the camera API, {@link Parameters#getZoomRatios()} will return a list of zoom
263+
* ratios with length {@link Parameters#getMaxZoom()}+1. Each of this value indicates a actual
264+
* zoom ratio of the camera.
265+
*
266+
* <p>E.g. Assume {@link Parameters#getZoomRatios()} return {@code [100, 114, 131, 151, 174, 200,
267+
* 234, 268, 300]}, where {@link Parameters#getMaxZoom()}=8. It means, {@code setZoom(0)} will
268+
* actual perform 1.00x to the camera, {@code setZoom(1)} will actual perform 1.14x to the camera,
269+
* {@code setZoom(2)} will actual perform 1.31x to the camera, ..., {@code setZoom(8)} will actual
270+
* perform 3.00x to the camera.
271+
*
272+
* @param params The parameters of the camera.
273+
* @param zoomRatio The target zoom ratio.
274+
* @return The maximum zoom value that will not exceed the target {@code zoomRatio}.
275+
*/
276+
private static int getZoomValue(Camera.Parameters params, float zoomRatio) {
277+
int zoom = (int) (Math.max(zoomRatio, 1) * 100);
278+
List<Integer> zoomRatios = params.getZoomRatios();
279+
int maxZoom = params.getMaxZoom();
280+
for (int i = 0; i < maxZoom; ++i) {
281+
if (zoomRatios.get(i + 1) > zoom) {
282+
return i;
283+
}
284+
}
285+
return maxZoom;
286+
}
287+
246288
/**
247289
* Opens the camera and applies the user settings.
248290
*

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/CameraXLivePreviewActivity.java

+19-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import androidx.annotation.NonNull;
3535
import androidx.annotation.Nullable;
3636
import androidx.annotation.RequiresApi;
37+
import androidx.camera.core.Camera;
3738
import androidx.camera.core.CameraInfoUnavailableException;
3839
import androidx.camera.core.CameraSelector;
3940
import androidx.camera.core.ImageAnalysis;
@@ -44,19 +45,21 @@
4445
import androidx.lifecycle.ViewModelProvider;
4546
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;
4647
import com.google.android.gms.common.annotation.KeepName;
48+
import com.google.common.util.concurrent.ListenableFuture;
4749
import com.google.mlkit.common.MlKitException;
4850
import com.google.mlkit.common.model.LocalModel;
51+
import com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback;
4952
import com.google.mlkit.vision.demo.CameraXViewModel;
5053
import com.google.mlkit.vision.demo.GraphicOverlay;
5154
import com.google.mlkit.vision.demo.R;
5255
import com.google.mlkit.vision.demo.VisionImageProcessor;
5356
import com.google.mlkit.vision.demo.java.barcodescanner.BarcodeScannerProcessor;
5457
import com.google.mlkit.vision.demo.java.facedetector.FaceDetectorProcessor;
58+
import com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;
5559
import com.google.mlkit.vision.demo.java.labeldetector.LabelDetectorProcessor;
5660
import com.google.mlkit.vision.demo.java.objectdetector.ObjectDetectorProcessor;
5761
import com.google.mlkit.vision.demo.java.posedetector.PoseDetectorProcessor;
5862
import com.google.mlkit.vision.demo.java.segmenter.SegmenterProcessor;
59-
import com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;
6063
import com.google.mlkit.vision.demo.java.textdetector.TextRecognitionProcessor;
6164
import com.google.mlkit.vision.demo.preference.PreferenceUtils;
6265
import com.google.mlkit.vision.demo.preference.SettingsActivity;
@@ -104,6 +107,7 @@ public final class CameraXLivePreviewActivity extends AppCompatActivity
104107
private GraphicOverlay graphicOverlay;
105108

106109
@Nullable private ProcessCameraProvider cameraProvider;
110+
@Nullable private Camera camera;
107111
@Nullable private Preview previewUseCase;
108112
@Nullable private ImageAnalysis analysisUseCase;
109113
@Nullable private VisionImageProcessor imageProcessor;
@@ -282,7 +286,8 @@ private void bindPreviewUseCase() {
282286
}
283287
previewUseCase = builder.build();
284288
previewUseCase.setSurfaceProvider(previewView.getSurfaceProvider());
285-
cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, previewUseCase);
289+
camera =
290+
cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, previewUseCase);
286291
}
287292

288293
private void bindAnalysisUseCase() {
@@ -357,7 +362,18 @@ private void bindAnalysisUseCase() {
357362
break;
358363
case BARCODE_SCANNING:
359364
Log.i(TAG, "Using Barcode Detector Processor");
360-
imageProcessor = new BarcodeScannerProcessor(this);
365+
ZoomCallback zoomCallback = null;
366+
if (PreferenceUtils.shouldEnableAutoZoom(this)) {
367+
zoomCallback =
368+
zoomLevel -> {
369+
Log.i(TAG, "Set zoom ratio " + zoomLevel);
370+
@SuppressWarnings("FutureReturnValueIgnored")
371+
ListenableFuture<Void> ignored =
372+
camera.getCameraControl().setZoomRatio(zoomLevel);
373+
return true;
374+
};
375+
}
376+
imageProcessor = new BarcodeScannerProcessor(this, zoomCallback);
361377
break;
362378
case IMAGE_LABELING:
363379
Log.i(TAG, "Using Image Label Detector Processor");

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/LivePreviewActivity.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,18 @@
3131
import android.widget.ToggleButton;
3232
import com.google.android.gms.common.annotation.KeepName;
3333
import com.google.mlkit.common.model.LocalModel;
34+
import com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback;
3435
import com.google.mlkit.vision.demo.CameraSource;
3536
import com.google.mlkit.vision.demo.CameraSourcePreview;
3637
import com.google.mlkit.vision.demo.GraphicOverlay;
3738
import com.google.mlkit.vision.demo.R;
3839
import com.google.mlkit.vision.demo.java.barcodescanner.BarcodeScannerProcessor;
3940
import com.google.mlkit.vision.demo.java.facedetector.FaceDetectorProcessor;
41+
import com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;
4042
import com.google.mlkit.vision.demo.java.labeldetector.LabelDetectorProcessor;
4143
import com.google.mlkit.vision.demo.java.objectdetector.ObjectDetectorProcessor;
4244
import com.google.mlkit.vision.demo.java.posedetector.PoseDetectorProcessor;
4345
import com.google.mlkit.vision.demo.java.segmenter.SegmenterProcessor;
44-
import com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;
4546
import com.google.mlkit.vision.demo.java.textdetector.TextRecognitionProcessor;
4647
import com.google.mlkit.vision.demo.preference.PreferenceUtils;
4748
import com.google.mlkit.vision.demo.preference.SettingsActivity;
@@ -247,7 +248,12 @@ private void createCameraSource(String model) {
247248
break;
248249
case BARCODE_SCANNING:
249250
Log.i(TAG, "Using Barcode Detector Processor");
250-
cameraSource.setMachineLearningFrameProcessor(new BarcodeScannerProcessor(this));
251+
ZoomCallback zoomCallback = null;
252+
if (PreferenceUtils.shouldEnableAutoZoom(this)) {
253+
zoomCallback = zoomLevel -> cameraSource.setZoom(zoomLevel);
254+
}
255+
cameraSource.setMachineLearningFrameProcessor(
256+
new BarcodeScannerProcessor(this, zoomCallback));
251257
break;
252258
case IMAGE_LABELING:
253259
Log.i(TAG, "Using Image Label Detector Processor");

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/StillImageActivity.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@
4646
import com.google.mlkit.vision.demo.VisionImageProcessor;
4747
import com.google.mlkit.vision.demo.java.barcodescanner.BarcodeScannerProcessor;
4848
import com.google.mlkit.vision.demo.java.facedetector.FaceDetectorProcessor;
49+
import com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;
4950
import com.google.mlkit.vision.demo.java.labeldetector.LabelDetectorProcessor;
5051
import com.google.mlkit.vision.demo.java.objectdetector.ObjectDetectorProcessor;
5152
import com.google.mlkit.vision.demo.java.posedetector.PoseDetectorProcessor;
5253
import com.google.mlkit.vision.demo.java.segmenter.SegmenterProcessor;
53-
import com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;
5454
import com.google.mlkit.vision.demo.java.textdetector.TextRecognitionProcessor;
5555
import com.google.mlkit.vision.demo.preference.PreferenceUtils;
5656
import com.google.mlkit.vision.demo.preference.SettingsActivity;
@@ -436,7 +436,7 @@ private void createImageProcessor() {
436436
imageProcessor = new FaceDetectorProcessor(this);
437437
break;
438438
case BARCODE_SCANNING:
439-
imageProcessor = new BarcodeScannerProcessor(this);
439+
imageProcessor = new BarcodeScannerProcessor(this, /* zoomCallback= */ null);
440440
break;
441441
case TEXT_RECOGNITION_LATIN:
442442
if (imageProcessor != null) {

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/barcodescanner/BarcodeScannerProcessor.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@
2020
import android.graphics.Point;
2121
import android.util.Log;
2222
import androidx.annotation.NonNull;
23+
import androidx.annotation.Nullable;
2324
import com.google.android.gms.tasks.Task;
2425
import com.google.android.odml.image.MlImage;
2526
import com.google.mlkit.vision.barcode.BarcodeScanner;
27+
import com.google.mlkit.vision.barcode.BarcodeScannerOptions;
2628
import com.google.mlkit.vision.barcode.BarcodeScanning;
29+
import com.google.mlkit.vision.barcode.ZoomSuggestionOptions;
30+
import com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback;
2731
import com.google.mlkit.vision.barcode.common.Barcode;
2832
import com.google.mlkit.vision.common.InputImage;
2933
import com.google.mlkit.vision.demo.GraphicOverlay;
@@ -37,14 +41,22 @@ public class BarcodeScannerProcessor extends VisionProcessorBase<List<Barcode>>
3741

3842
private final BarcodeScanner barcodeScanner;
3943

40-
public BarcodeScannerProcessor(Context context) {
44+
public BarcodeScannerProcessor(Context context, @Nullable ZoomCallback zoomCallback) {
4145
super(context);
4246
// Note that if you know which format of barcode your app is dealing with, detection will be
4347
// faster to specify the supported barcode formats one by one, e.g.
4448
// new BarcodeScannerOptions.Builder()
4549
// .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
4650
// .build();
47-
barcodeScanner = BarcodeScanning.getClient();
51+
if (zoomCallback != null) {
52+
BarcodeScannerOptions options =
53+
new BarcodeScannerOptions.Builder()
54+
.setZoomSuggestionOptions(new ZoomSuggestionOptions.Builder(zoomCallback).build())
55+
.build();
56+
barcodeScanner = BarcodeScanning.getClient(options);
57+
} else {
58+
barcodeScanner = BarcodeScanning.getClient();
59+
}
4860
}
4961

5062
@Override

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/CameraXLivePreviewActivity.kt

+15-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import android.widget.Spinner
3131
import android.widget.Toast
3232
import android.widget.ToggleButton
3333
import androidx.annotation.RequiresApi
34+
import androidx.camera.core.Camera
3435
import androidx.camera.core.CameraInfoUnavailableException
3536
import androidx.camera.core.CameraSelector
3637
import androidx.camera.core.ImageAnalysis
@@ -44,6 +45,7 @@ import androidx.lifecycle.ViewModelProvider
4445
import com.google.android.gms.common.annotation.KeepName
4546
import com.google.mlkit.common.MlKitException
4647
import com.google.mlkit.common.model.LocalModel
48+
import com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback
4749
import com.google.mlkit.vision.demo.CameraXViewModel
4850
import com.google.mlkit.vision.demo.GraphicOverlay
4951
import com.google.mlkit.vision.demo.R
@@ -66,7 +68,6 @@ import com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions
6668
import com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions
6769
import com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions
6870
import com.google.mlkit.vision.text.latin.TextRecognizerOptions
69-
import java.util.ArrayList
7071

7172
/** Live preview demo app for ML Kit APIs using CameraX. */
7273
@KeepName
@@ -77,6 +78,7 @@ class CameraXLivePreviewActivity :
7778
private var previewView: PreviewView? = null
7879
private var graphicOverlay: GraphicOverlay? = null
7980
private var cameraProvider: ProcessCameraProvider? = null
81+
private var camera: Camera? = null
8082
private var previewUseCase: Preview? = null
8183
private var analysisUseCase: ImageAnalysis? = null
8284
private var imageProcessor: VisionImageProcessor? = null
@@ -239,7 +241,8 @@ class CameraXLivePreviewActivity :
239241
}
240242
previewUseCase = builder.build()
241243
previewUseCase!!.setSurfaceProvider(previewView!!.getSurfaceProvider())
242-
cameraProvider!!.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector!!, previewUseCase)
244+
camera =
245+
cameraProvider!!.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector!!, previewUseCase)
243246
}
244247

245248
private fun bindAnalysisUseCase() {
@@ -306,7 +309,15 @@ class CameraXLivePreviewActivity :
306309
}
307310
BARCODE_SCANNING -> {
308311
Log.i(TAG, "Using Barcode Detector Processor")
309-
BarcodeScannerProcessor(this)
312+
var zoomCallback: ZoomCallback? = null
313+
if (PreferenceUtils.shouldEnableAutoZoom(this)) {
314+
zoomCallback = ZoomCallback { zoomLevel: Float ->
315+
Log.i(TAG, "Set zoom ratio $zoomLevel")
316+
val ignored = camera!!.cameraControl.setZoomRatio(zoomLevel)
317+
true
318+
}
319+
}
320+
BarcodeScannerProcessor(this, zoomCallback)
310321
}
311322
IMAGE_LABELING -> {
312323
Log.i(TAG, "Using Image Label Detector Processor")
@@ -414,7 +425,7 @@ class CameraXLivePreviewActivity :
414425
private const val CUSTOM_AUTOML_LABELING = "Custom AutoML Image Labeling (Flower)"
415426
private const val POSE_DETECTION = "Pose Detection"
416427
private const val SELFIE_SEGMENTATION = "Selfie Segmentation"
417-
private const val FACE_MESH_DETECTION = "Face Mesh Detection (Beta)";
428+
private const val FACE_MESH_DETECTION = "Face Mesh Detection (Beta)"
418429

419430
private const val STATE_SELECTED_MODEL = "selected_model"
420431
}

android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/LivePreviewActivity.kt

+11-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import android.widget.Toast
3131
import android.widget.ToggleButton
3232
import com.google.android.gms.common.annotation.KeepName
3333
import com.google.mlkit.common.model.LocalModel
34+
import com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback
3435
import com.google.mlkit.vision.demo.CameraSource
3536
import com.google.mlkit.vision.demo.CameraSourcePreview
3637
import com.google.mlkit.vision.demo.GraphicOverlay
@@ -54,7 +55,6 @@ import com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions
5455
import com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions
5556
import com.google.mlkit.vision.text.latin.TextRecognizerOptions
5657
import java.io.IOException
57-
import java.util.ArrayList
5858

5959
/** Live preview demo for ML Kit APIs. */
6060
@KeepName
@@ -98,7 +98,7 @@ class LivePreviewActivity :
9898
options.add(TEXT_RECOGNITION_DEVANAGARI)
9999
options.add(TEXT_RECOGNITION_JAPANESE)
100100
options.add(TEXT_RECOGNITION_KOREAN)
101-
options.add(FACE_MESH_DETECTION);
101+
options.add(FACE_MESH_DETECTION)
102102

103103
// Creating adapter for spinner
104104
val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options)
@@ -226,7 +226,13 @@ class LivePreviewActivity :
226226
}
227227
BARCODE_SCANNING -> {
228228
Log.i(TAG, "Using Barcode Detector Processor")
229-
cameraSource!!.setMachineLearningFrameProcessor(BarcodeScannerProcessor(this))
229+
var zoomCallback: ZoomCallback? = null
230+
if (PreferenceUtils.shouldEnableAutoZoom(this)) {
231+
zoomCallback = ZoomCallback { zoomLevel: Float -> cameraSource!!.setZoom(zoomLevel) }
232+
}
233+
cameraSource!!.setMachineLearningFrameProcessor(
234+
BarcodeScannerProcessor(this, zoomCallback)
235+
)
230236
}
231237
IMAGE_LABELING -> {
232238
Log.i(TAG, "Using Image Label Detector Processor")
@@ -279,7 +285,7 @@ class LivePreviewActivity :
279285
cameraSource!!.setMachineLearningFrameProcessor(SegmenterProcessor(this))
280286
}
281287
FACE_MESH_DETECTION -> {
282-
cameraSource!!.setMachineLearningFrameProcessor(FaceMeshDetectorProcessor (this));
288+
cameraSource!!.setMachineLearningFrameProcessor(FaceMeshDetectorProcessor(this))
283289
}
284290
else -> Log.e(TAG, "Unknown model: $model")
285291
}
@@ -353,7 +359,7 @@ class LivePreviewActivity :
353359
private const val CUSTOM_AUTOML_LABELING = "Custom AutoML Image Labeling (Flower)"
354360
private const val POSE_DETECTION = "Pose Detection"
355361
private const val SELFIE_SEGMENTATION = "Selfie Segmentation"
356-
private const val FACE_MESH_DETECTION = "Face Mesh Detection (Beta)";
362+
private const val FACE_MESH_DETECTION = "Face Mesh Detection (Beta)"
357363

358364
private const val TAG = "LivePreviewActivity"
359365
}

0 commit comments

Comments
 (0)