Ich habe CameraX ausprobiert, das bei Google I / O 2019 auf Fragment in Java eingeführt wurde, daher werde ich es kurz vorstellen.
Es ist einfach, mit dem offiziellen [Tutorial] fortzufahren (https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0), also werde ich mit dem Betrachten fortfahren.
Das Erstellen eines Projekts und das Hinzufügen von Abhängigkeiten entsprechen den Anweisungen im Lernprogramm. Daher werde ich sie in diesem Artikel weglassen.
Fügen Sie textureView zu layout.xml hinzu, um es von Fragment anzuzeigen.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF">
<TextureView
android:id="@+id/view_finder"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout
android:id="@+id/camera_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#456700"
android:padding="15dp">
<ImageButton
android:id="@+id/camera_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/common_backbtn"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/camera_bottom_control"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#456700"
android:padding="20dp">
<Button
android:id="@+id/capture_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Schießen"
/>
</RelativeLayout>
</RelativeLayout>
Es sieht so aus ↓
TextureView wird auf der gesamten Oberfläche platziert und mit Bildschirmelementen überlagert.
Sie müssen lediglich die Vorschau einstellen und an den Fragmentlebenszyklus binden.
Es ist einfach, weil Sie nur die von CameraX.bindToLifecycle erstellte PreviewConfig binden.
public void startCamera() {
PreviewConfig.Builder builder = new PreviewConfig.Builder();
builder.setTargetResolution(new Size(App.width, App.height));
PreviewConfig previewConfig = builder.build();
preview = new Preview(previewConfig);
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
@Override
public void onUpdated(@NonNull Preview.PreviewOutput output) {
ViewGroup viewGroup = (ViewGroup) viewFinder.getParent();
viewGroup.removeView(viewFinder);
viewGroup.addView(viewFinder, 0);
viewFinder.setSurfaceTexture(output.getSurfaceTexture());
updateTransform();
}
});
CameraX.bindToLifecycle(this, preview);
}
public void updateTransform() {
Matrix matrix = new Matrix();
float centerX = viewFinder.getWidth() / 2f;
float centerY = viewFinder.getHeight() / 2f;
float rotationDegrees;
switch (viewFinder.getDisplay().getRotation()) {
case Surface.ROTATION_0:
rotationDegrees = 0f;
break;
case Surface.ROTATION_90:
rotationDegrees = 90f;
break;
case Surface.ROTATION_180:
rotationDegrees = 180f;
break;
case Surface.ROTATION_270:
rotationDegrees = 270f;
break;
default:
return;
}
matrix.postRotate(-rotationDegrees, centerX, centerY);
viewFinder.setTransform(matrix);
}
Schreiben Sie dies einfach und wenn Sie startCamera aufrufen, nachdem Sie die Erlaubnis der Kamera erhalten haben, wird die Vorschau angezeigt.
Sie können nichts tun, indem Sie eine Vorschau der Kamera anzeigen. Lassen Sie uns das Bild also in dem Moment aufnehmen, in dem die Taste capture_button gedrückt wird.
Fügen Sie den folgenden Code hinzu, bevor Sie die obige startCamera-Methode binden.
ImageCaptureConfig.Builder imageBuilder = new ImageCaptureConfig.Builder();
imageBuilder.setTargetResolution(new Size(App.width, App.height));
imageBuilder.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY);
imageBuilder.setFlashMode(FlashMode.ON);
ImageCaptureConfig imageCaptureConfig = imageBuilder.build();
imageCapture = new ImageCapture(imageCaptureConfig);
Ich richte die Bilderfassung ein. Hier wird Flash aktiviert, um die Qualität zu maximieren. Fügen Sie nach dem Erstellen der ImageCaptureConfig auch die ImageCaptureConfig zur Bindemethode hinzu.
CameraX.bindToLifecycle(this, preview, imageCapture);
Jetzt können Sie loslegen.
Sie können erfassen, indem Sie imageCapture.takePicture () aufrufen. Legen Sie also ein Ereignis für die Schaltfläche fest.
btnCamera.setOnClickListener((View v) -> {
imageCapture.takePicture(CameraFragment.this, new ImageCapture.OnImageCapturedListener() {
@Override
public void onCaptureSuccess(ImageProxy imageProxy, int rotationDegrees) {
}
@Override
public void onError(
@NonNull ImageCapture.ImageCaptureError imageCaptureError, @NonNull String message,
@Nullable Throwable cause) {
}
});
}
});
Für das Argument von takePicture wird Executor benötigt. Daher implementieren wir hier Executor in Fragment, damit UiThread die Verarbeitung nach dem Aufnehmen eines Bildes ausführen kann.
public class CameraFragment implements Executor {
@Override
public void execute(Runnable command) {
if(getActivity() != null){
getActivity().runOnUiThread(command);
}
}
}
Wenn Sie die Aufnahmetaste drücken und die Aufnahme erfolgreich ist, wird onCaptureSuccess (ImageProxy imageProxy, int rotationDegrees) aufgerufen und das Bild kann von imageProxy aufgenommen werden!
Es ist einfach ...
Was wurde auf Camera2 geschrieben?
Es ist ein schwieriges Wort, die Kamera zu montieren, also habe ich darauf gewartet.
Nun, ich habe es sehr leicht beschrieben, aber ich werde es vorstellen, weil es einige süchtig machende Punkte gab.
Es ist kein Verschlussgeräusch zu hören. Ja.
Ich habe nach etwas gesucht, das in den Aufnahmeeinstellungen eingestellt werden kann, aber es ist nirgendwo zu finden ...
Wenn Sie es klingen lassen möchten, versuchen Sie es zu erzwingen.
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
Ja, das ist es.
public Bitmap imageProxyToBitmap(ImageProxy image, int rotationDegrees) {
ImageProxy.PlaneProxy planeProxy = image.getPlanes()[0];
ByteBuffer buffer = planeProxy.getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
Matrix mat = new Matrix();
mat.postRotate(rotationDegrees);
if (rotationDegrees != 0) {
return rotate(BitmapFactory.decodeByteArray(bytes, 0, bytes.length), rotationDegrees);
} else {
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
}
public Bitmap rotate(Bitmap in, int angle) {
Matrix mat = new Matrix();
mat.postRotate(angle);
return Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), mat, true);
}
F. Warum befindet sich TextureView in der gesamten Layoutdatei? Sollte es nicht in den Vorschaubereich passen?
A. Ich wage es, alles noch einmal zu machen.
Wenn die Größe der Vorschau und das Seitenverhältnis der TextureView-Größe nicht übereinstimmen, wird die Vorschau verzerrt und angezeigt. Wenn Sie einen Bildschirm mit einem Vorschaubereich erstellen, der im Vergleich zur Bildschirmgröße klein ist, haben Sie festgestellt, dass die TextureView an den Vorschaubereich angepasst ist. Die Vorschau ist sehr schwer zu sehen, da die Dinge in der TextureView in verkleinerter Größe angezeigt werden.
Wenn Sie TextureView auf der gesamten Oberfläche platzieren, werden alle oben genannten Probleme gelöst, und Sie können mit dem gleichen Gefühl wie die Kamera auf der gesamten Oberfläche fotografieren, die Sie normalerweise verwenden, sodass Sie ohne Beschwerden fotografieren können.
Wenn Sie nur ein Bild des für den Benutzer sichtbaren Bereichs wünschen, können Sie es nach der Aufnahme ausschneiden.
Bitte beachten Sie, dass CameraX immer noch eine Alpha-Version ist, sodass sich die Benutzeroberfläche in der Release-Version ändern kann.
Obwohl hier nicht vorgestellt, scheint es eine API zu geben, die die Verwendung gerätespezifischer Herstellereffekte (unscharf, HDR, Nachtansicht) vereinfacht. Daher möchte ich dies auch in Zukunft versuchen.
Recommended Posts