J'ai essayé d'utiliser la bibliothèque CameraX avec Android Java Fragment

J'ai essayé CameraX présenté à Google I / O 2019 sur Fragment en Java, je vais donc le présenter brièvement.

Préparation

Il est facile de procéder en regardant le [Tutoriel] officiel (https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0), donc je vais continuer en regardant ceci.

La création d'un projet et l'ajout de dépendances sont conformes au didacticiel, je les omettrai donc dans cet article.

Vue ajoutée pour l'aperçu

Ajoutez TextureView à layout.xml pour l'afficher dans Fragment.

<?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="Tirer"
            />
        
    </RelativeLayout>

</RelativeLayout>

Ça ressemble à ça ↓ スクリーンショット 2019-12-12 15.20.00.png

TextureView est placé sur toute la surface et des éléments d'écran y sont superposés.

Lancer la caméra

Tout ce que vous avez à faire est de définir l'aperçu et de le lier au cycle de vie du fragment.

C'est facile car vous liez simplement le PreviewConfig créé par CameraX.bindToLifecycle.

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

Fondamentalement, écrivez simplement ceci, et si vous appelez startCamera après avoir obtenu l'autorisation de la caméra, l'aperçu sera affiché.

Capture de la caméra

Vous ne pouvez pas l'utiliser pour quoi que ce soit juste en prévisualisant la caméra, alors capturons l'image à ce moment-là lorsque capture_button est enfoncé.

Ajoutez le code suivant avant de lier la méthode startCamera ci-dessus.

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

Je configure la capture d'image. Ici, Flash est activé pour maximiser la qualité. Après avoir créé ImageCaptureConfig, ajoutons également ImageCaptureConfig à la méthode de liaison.

CameraX.bindToLifecycle(this, preview, imageCapture);

Maintenant, vous êtes prêt à partir.

Vous pouvez capturer en appelant imageCapture.takePicture (), définissons donc un événement pour le bouton.

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) {

			}
		});
	}
});
	

Executor est requis pour l'argument de takePicture, nous allons donc implémenter ici Executor dans Fragment afin qu'UiThread puisse exécuter le traitement après avoir pris une photo.


public class CameraFragment implements Executor {

    @Override
    public void execute(Runnable command) {
		if(getActivity() != null){
			getActivity().runOnUiThread(command);
		}
	}
}

Lorsque vous appuyez sur le bouton de prise de vue et que la prise de vue est réussie, onCaptureSuccess (ImageProxy imageProxy, int rotationDegrees) est appelé et l'image peut être acquise depuis imageProxy!

Impressions

C'est facile ...

Qu'est-ce qui a été écrit sur Camera2?

C'est un mot difficile à monter sur la caméra, donc j'attendais ça.

Point addictif

Eh bien, je l'ai décrit très facilement, mais je vais le présenter car il y avait des points addictifs.

① L'obturateur activé ne sonne pas!

Il n'y a pas de son d'obturateur. Oui.

Je cherchais quelque chose qui pourrait être défini dans les paramètres de capture, mais on ne le trouve nulle part ...

Si vous voulez le faire sonner, essayez de le forcer.

MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);

② ImageProxy Comment convertissez-vous en Bitmap?

Oui, c'est ça.

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

③ Comment organiser TextureView

Q. Pourquoi TextureView se trouve-t-il sur toute la surface du fichier de mise en page? Ne devrait-il pas rentrer dans la zone de prévisualisation?

R. J'ose tout recommencer.

Si la taille de l'aperçu et le rapport hauteur / largeur de la taille de TextureView ne correspondent pas, l'aperçu sera déformé et affiché, ou si vous créez un écran avec une zone d'aperçu qui est petite par rapport à la taille de l'écran, vous avez vu que TextureView est conçue pour s'adapter à la zone d'aperçu. L'aperçu sera très difficile à voir car les choses seront affichées dans une taille réduite dans TextureView.

Si vous placez TextureView sur toute la surface, tous les problèmes ci-dessus seront résolus et vous pourrez prendre des photos avec la même sensation que l'appareil photo sur toute la surface que vous utilisez habituellement, afin de pouvoir prendre des photos sans aucun inconfort.

Si vous voulez une image de la seule zone visible par l'utilisateur, vous pouvez la découper après la prise de vue.

À la fin

Veuillez noter que CameraX est toujours une version alpha, donc l'interface peut changer dans la version finale.

De plus, bien que cela ne soit pas présenté ici, il semble qu'il existe une API qui facilite l'utilisation des effets de fournisseur spécifiques à l'appareil (flou, HDR, vue nocturne), je voudrais donc essayer cela également à l'avenir.

Recommended Posts

J'ai essayé d'utiliser la bibliothèque CameraX avec Android Java Fragment
J'ai essayé d'utiliser OpenCV avec Java + Tomcat
J'ai essayé d'utiliser Java REPL
J'ai essayé d'utiliser le référentiel GitHub comme serveur de bibliothèque
J'ai essayé d'interagir avec Java
J'ai essayé la communication UDP avec Java
J'ai essayé le framework Java "Quarkus"
J'ai créé un schéma de verrouillage à l'aide de la touche de volume avec l'application Android. Édition fragmentée
J'ai essayé d'utiliser JWT en Java
[Android] J'ai essayé d'utiliser la disposition du coordinateur.
[Android] [Bibliothèque] J'ai essayé d'utiliser une bibliothèque d'animations appelée "Before After animation".
J'ai essayé d'utiliser le mémo Java LocalDate
J'ai essayé d'utiliser Google HttpClient de Java
J'ai essayé de créer une application Android avec MVC maintenant (Java)
J'ai essayé d'utiliser l'API Elasticsearch en Java
J'ai essayé d'utiliser Realm avec Swift UI
J'ai essayé d'utiliser Scalar DL avec Docker
J'ai essayé le nouveau yuan à Java
J'ai essayé d'utiliser OnlineConverter avec SpringBoot + JODConverter
J'ai essayé la bibliothèque AutoValue avec Intellij
Essayez d'utiliser la télécommande Wii en Java
J'ai essayé de faire une authentification de base avec Java
[Android] J'ai quitté SQLite et essayé d'utiliser Realm
J'ai fait un blackjack avec Ruby (j'ai essayé d'utiliser minitest)
[API] J'ai essayé d'utiliser l'API de recherche par code postal
J'ai essayé d'utiliser le profileur d'IntelliJ IDEA
J'ai essayé de casser le bloc avec java (1)
[Java] J'ai essayé de me connecter en utilisant le pool de connexion avec Servlet (tomcat) & MySQL & Java
J'ai essayé d'utiliser Gson
J'ai essayé d'utiliser TestNG
J'ai essayé d'utiliser Galasa
J'ai essayé d'utiliser une connexion à une base de données dans le développement Android
J'ai essayé d'utiliser la fonction Server Push de Servlet 4.0
J'ai essayé d'implémenter TCP / IP + BIO avec JAVA
[Java 11] J'ai essayé d'exécuter Java sans compiler avec javac
Essayez d'implémenter le tamis Eratostenes en utilisant la bibliothèque standard de Java
J'ai essayé de faire fonctionner SQS en utilisant AWS Java SDK
J'ai essayé d'utiliser la boîte à outils de migration pour les fichiers binaires d'application
J'ai essayé d'utiliser Log4j2 sur un serveur Java EE
J'ai essayé OCR de traiter un fichier PDF avec Java
J'ai essayé d'implémenter Sterling Sort avec Java Collector
Essayez le hooking global en Java à l'aide de la bibliothèque JNativeHook
J'ai essayé d'étudier le mécanisme d'Emscripten en l'utilisant avec un solveur allemand
J'ai essayé de créer un environnement de développement java8 avec Chocolatey
J'ai essayé de moderniser une application Java EE avec OpenShift.
J'ai essayé DI avec Ruby
[Rails] J'ai essayé d'utiliser la méthode button_to pour la première fois
J'ai essayé d'augmenter la vitesse de traitement avec l'ingénierie spirituelle
[JDBC] J'ai essayé d'accéder à la base de données SQLite3 depuis Java.
J'ai essayé de résumer les bases de kotlin et java
J'ai essayé Drools (Java, InputStream)
[Java] Essayez de modifier les éléments de la chaîne Json à l'aide de la bibliothèque
J'ai essayé d'utiliser Apache Wicket
Utilisation de Mapper avec Java (Spring)
J'ai essayé de construire l'environnement petit à petit en utilisant docker
J'ai essayé le problème FizzBuzz
J'ai essayé UPSERT avec PostgreSQL.