Android CameraX使用説明の翻訳1.0.0-beta 03バージョンAndroid 10.0本体実行可能

68352 ワード

Android CameraXを学ぶついでに公式の説明を翻訳します
翻訳元CameraX入門このリンクを使用するには、科学的なインターネットが必要かもしれません.
ええ、前の章の権限管理は简単です.レイアウトファイルをひっくり返さないでください.简単です.ボタンとプレビューのViewです.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/camera_capture_button"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="fitCenter"
        android:elevation="2dp"
        android:text="Take Photo"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.camera.view.PreviewView
        android:id="@+id/viewFinder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

androidx.constraintlayout.widget.ConstraintLayout>

もちろんAndroidManifestxmlには登録権限が必要です
	<!--       app                                --!>
    <uses-feature android:name="android.hardware.Camera.any"/>
    <uses-permission android:name="android.permission.CAMERA"/>

以下は翻訳本文です.
前の3章では、プロジェクトの構築方法と権限管理の概要
4.プレビュー実施例
カメラアプリケーションでは、ビューファインダーを使用して、撮影する写真をユーザーにプレビューさせます.Camerax Previewクラスを使用してファインダーを実現できます.
Previewを使用するには、まず構成を定義し、使用例のインスタンスを作成する必要があります.CameraXライフサイクルの結果インスタンスにバインドする必要があります.1.startCamera()関数へ
次の分析では、さっきコピーしたコードを分析します.
private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener(Runnable {
            //Used to bind the lifecycle of cameras to the lifecycle owner
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
            preview = Preview.Builder().build()

            //select back camera
            val cameraSelector =
                CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK)

                    .build()

            try {
                //unbide use cases before rebinding
                cameraProvider.unbindAll()

                //bind use cases to camera
                camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
                preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))

            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        },ContextCompat.getMainExecutor(this))
    }
  • ProcessCameraProviderを作成します.これは、カメラのライフサイクルをライフサイクル所有者にバインドするために使用します.カメラの開閉を心配する必要はありません.カメラXはライフサイクル感知の
  • です.
    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    
  • cameraProviderFutureにリスナーを追加します.パラメータとしてRunnableを追加し、後で記入します.ContextCompat.を追加getMainExecutor()は2番目のパラメータとして、メインスレッド上で実行される実行プログラムを返します.
  • cameraProviderFuture.addListener(Runnable {},ContextCompat.getMainExecutor(this))
    
  • このRunalbeには、カメラのライフサイクルをアプリケーションプロセスのLifecycleOwnerにバインドするためのProcessCameraProviderが追加されています.
  • val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
    
  • Preview
  • を初期化
    preview = Preview.Builder().build()
    
  • CameraSelectorオブジェクトを作成し、CameraSelectorを使用します.Builder.requireLensFacing()関数を使用して、希望するレンズ
  • を開きます.
    CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK)
    
  • tryブロックを作成します.そのブロックで、cameraProviderにバインドされているものがないことを確認し、cameraSelectorとpreviewオブジェクトをcameraProviderにバインドします.ファインダーのsurfaceプロバイダをpreviewに添付します.
  •             try {
                   //unbide use cases before rebinding
                   cameraProvider.unbindAll()
                   //bind use cases to camera
                   camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
                   preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))
               }
    
  • このコードには、アプリケーションが焦点ではなくなったなど、いくつかの失敗する可能性があります.障害が発生した場合は、このコードをcatchブロックにパッケージしてログを記録します.
  • 			catch (exc: Exception) {
                   Log.e(TAG, "Use case binding failed", exc)
               }
    

    2.アプリを実行すると、カメラのプレビュー画面が表示されます
    5.ImageCaptureの実装例
    プレビューと比較して、他の例の動作は非常に似ています.まず、実際のインスタンスオブジェクトをインスタンス化するための構成オブジェクトを定義する必要があります.写真をキャプチャするには、キャプチャボタンを押したときに呼び出されるtakePhoto()メソッドを実装する必要があります.
    このコードをtakePhoto()メソッドにコピーします.
    次のポイントでは、さっきコピーしたコードを分解します.
    private fun takePhoto() {
            //Get a stable reference of the modifiable image capture use case
            //                
            val imageCapture = imageCapture ?: return
    
            //Create timestamped output file to hold the image
            val photoFile = File(
                outputDirectory,
                SimpleDateFormat(FILENAME_FORMAT, Locale.CHINA)
                    .format(System.currentTimeMillis()) + ".JPG"
            )
    
            //Create output pptions object which constins file + metadata
            val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
    
            //Setup image capture listener which is triggered after photo has been taken
            //         ,      
            imageCapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                object  : ImageCapture.OnImageSavedCallback{
                    override fun onError(exception: ImageCaptureException) {
                        Log.e(TAG, "Photo capture failed: ${exception.message}", exception)
                    }
    
                    override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                        val savedUri = Uri.fromFile(photoFile)
                        val msg = "Photo caputre succeeded: $savedUri"
                        Toast.makeText(baseContext,msg,Toast.LENGTH_SHORT).show()
                        Log.d(TAG,msg)
                    }
                }
            )
        }
    
  • まず、ImageCaptureの使用例への参照を取得する.使用例が空の場合は、関数から戻ります.画像キャプチャを設定する前にphotoボタンをクリックするとnullになります.return文がない場合、アプリケーションはnullでクラッシュします.△どうして崩れたの?写真を撮っても反応しないんだろう...
  • val imageCapture = imageCapture ?: return
    
  • は次に、画像を保存するためのファイルを作成する.ファイル名が一意になるようにタイムスタンプを追加します.
  • 	//Create timestamped output file to hold the image
           val photoFile = File(
               outputDirectory,
               SimpleDateFormat(FILENAME_FORMAT, Locale.CHINA)
                   .format(System.currentTimeMillis()) + ".JPG"
           )
    
  • outputFileoptionsオブジェクトを作成します.このオブジェクトでは、出力する内容を指定できます.作成したばかりのファイルに出力を保存するため、photoFileを追加します.
  • val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
    
  • imageCaptureオブジェクトでtakePicture()を呼び出します.入出力、実行プログラム、イメージ保存時のコールバック.次にコールバックを記入します.
  • imageCapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                object  : ImageCapture.OnImageSavedCallback{}
                )
    
  • 画像取得に失敗した場合、または保存に失敗した場合、エラーを追加して失敗を記録する.
  •                 override fun onError(exception: ImageCaptureException) {
                        Log.e(TAG, "Photo capture failed: ${exception.message}", exception)
                    }
    
    
  • キャプチャに失敗しなければ、写真撮影に成功!前に作成したファイルに写真を保存し、ユーザーにお祝いを表示し、ログ文を印刷します.
  • override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                        val savedUri = Uri.fromFile(photoFile)
                        val msg = "Photo caputre succeeded: $savedUri"
                        Toast.makeText(baseContext,msg,Toast.LENGTH_SHORT).show()
                        Log.d(TAG,msg)
                    }
    
  • startCamera()メソッドに移動し、「プレビューコード」の下でこのコード
  • をコピーします.
    imageCapture=ImageCapture.Builder().build()
    

    コードの貼り付け方法を示します.
    private fun startCamera() {
    	...
    	preview = Preview.Builder().build()
    	//Paste image capture code here!
    	val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
    	...
    
  • 最後に、bindToLifecycle()の呼び出しがtryブロックで更新され、新しい例が含まれる:
  • camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
    
  • アプリケーションを再実行し、写真を押す.画面にToastが表示され、ログにメッセージが表示されます.

  • 6.ImageAnalysisの実装例
    Q以下を実行すると、プレビュー、撮像、画像解析を同時に実現することは、Android Studioのデバイスシミュレータには適用されません.このコードをテストするには、実際のデバイスを使用することをお勧めします.
    あなたのカメラアプリをもっと面白くする良い方法はImageAnalysis機能を使うことです.ImageAnalysisを実装するカスタムクラスを定義できます.入力されたカメラフレームと呼び出されるアナライザインタフェース.カメラセッションの状態を管理したり、画像を処理したりする心配はありません.他のライフサイクル感知コンポーネントのように、私たちが望むライフサイクルにバインドすれば十分です.
  • このアナライザをmainとする.ktの内部クラスが追加されました.このアナライザは画像の平均輝度を記録する.アナライザを作成するには、ImageAnalysisを実装するクラスでanalyze関数を書き換える必要があります.アナライザのインタフェース.
  • private class LuminosityAnalyzer(private val listener: LumaListener) : ImageAnalysis.Analyzer {
    
       private fun ByteBuffer.toByteArray(): ByteArray {
           rewind()    // Rewind the buffer to zero
           val data = ByteArray(remaining())
           get(data)   // Copy the buffer into a byte array
           return data // Return the byte array
       }
    
       override fun analyze(image: ImageProxy) {
    
           val buffer = image.planes[0].buffer
           val data = buffer.toByteArray()
           val pixels = data.map { it.toInt() and 0xFF }
           val luma = pixels.average()
    
           listener(luma)
    
           image.close()
       }
    }
    

    私たちのクラスでImageAnalysisを実現します.Analyzerインタフェースは、ImageAnalysisでLuminosityAnalyzerのインスタンスをインスタンス化し、他のすべての例のようにCameraXを呼び出します.bindToLifecycle()の前に、「startCamera()」関数を再更新します.
  • startCamera()メソッドでは、imageCapture()コードの下にこのコードを追加します.
  • imageAnalyzer = ImageAnalysis.Builder()
      .build()
      .also {
          it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
              Log.d(TAG, "Average luminosity: $luma")
          })
      }
    

    コードを貼り付ける方法を示します.
    private fun startCamera() {
           ... 
    
           imageCapture = ImageCapture.Builder()
       .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
       .build()
    
           // Paste image analyzer code here!
    
    
           val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
    
           ... 
    }
    
  • bindToLifecycle()を更新し、imageAnalyzerを含むようにcameraProviderを呼び出します.
  • camera = cameraProvider.bindToLifecycle(
       this, cameraSelector, preview, imageCapture, imageAnalyzer)
    
  • アプリケーションを実行します!logcatでは、ほぼ毎秒類似のメッセージが生成されます.
  • D/CameraXApp: Average luminosity: ...
    

    翻訳終了
    最後に全体をktを上げる
    package city.carcate.u.myapplication
    
    import android.Manifest
    import android.content.pm.PackageManager
    import android.net.Uri
    import android.os.Bundle
    import android.provider.ContactsContract
    import android.util.Log
    import android.widget.Toast
    import androidx.appcompat.app.AppCompatActivity
    import androidx.camera.core.*
    import androidx.camera.lifecycle.ProcessCameraProvider
    import androidx.camera.view.PreviewView
    import androidx.core.app.ActivityCompat
    import androidx.core.content.ContextCompat
    import com.google.common.util.concurrent.ListenableFuture
    import kotlinx.android.synthetic.main.activity_main.*
    import java.io.File
    import java.lang.Exception
    import java.text.SimpleDateFormat
    import java.util.*
    import java.util.concurrent.Executor
    import java.util.concurrent.ExecutorService
    import java.util.concurrent.Executors
    
    /**
     *
     */
    class MainActivity : AppCompatActivity() {
        private var preview: Preview? = null
        private var imageCapture: ImageCapture? = null
        private var camera: Camera? = null
    
        private lateinit var outputDirectory: File
        private lateinit var cameraExecutor: ExecutorService
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            if (allPermissionsGranted()) {
                startCamera()
            } else {
                ActivityCompat.requestPermissions(
                    this, REQUIRED_PERMISSIONS, REQUEST_CODE_PREMISSIONS
                )
            }
            //setup the listener for take photo button
            camera_capture_button.setOnClickListener { takePhoto() }
            outputDirectory = getOutputDirectory()
            cameraExecutor = Executors.newSingleThreadExecutor()
        }
    
        private fun startCamera() {
            val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    
            cameraProviderFuture.addListener(Runnable {
                //Used to bind the lifecycle of cameras to the lifecycle owner
                val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
                preview = Preview.Builder().build()
                imageCapture = ImageCapture.Builder().build()
    
                //select back camera         
                val cameraSelector =
                    CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
    
                try {
                    //unbide use cases before rebinding      
                    cameraProvider.unbindAll()
                    //bind use cases to camera
                    camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
                    preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))
                } catch (exc: Exception) {
                    Log.e(TAG, "Use case binding failed", exc)
                }
    
            }, ContextCompat.getMainExecutor(this))
    
        }
    
        private fun takePhoto() {
            //Get a stable reference of the modifiable image capture use case
            //                
            val imageCapture = imageCapture ?: return
    
            //Create timestamped output file to hold the image
            val photoFile = File(
                outputDirectory,
                SimpleDateFormat(FILENAME_FORMAT, Locale.CHINA)
                    .format(System.currentTimeMillis()) + ".JPG"
            )
    
            //Create output pptions object which constins file + metadata
            val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
    
            //Setup image capture listener which is triggered after photo has been taken
            //         ,      
            imageCapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                object : ImageCapture.OnImageSavedCallback {
                    override fun onError(exception: ImageCaptureException) {
                        Log.e(TAG, "Photo capture failed: ${exception.message}", exception)
                    }
    
                    override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                        val savedUri = Uri.fromFile(photoFile)
                        val msg = "Photo caputre succeeded: $savedUri"
                        Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
                        Log.d(TAG, msg)
                    }
                }
            )
        }
    
        private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
            ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
        }
    
       private fun getOutputDirectory(): File {
            val mediaDir = externalMediaDirs.firstOrNull()?.let {
                File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
            }
            return if (mediaDir != null && mediaDir.exists()) mediaDir
            else filesDir
        }
    
        override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<out String>,
            grantResults: IntArray
        ) {
            if (requestCode == REQUEST_CODE_PREMISSIONS) {
                if (allPermissionsGranted()) {
                    startCamera()
                } else {
                    Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_LONG)
                        .show()
                    finish()
                }
            }
        }
    
        companion object {
            private const val TAG = "CameraXBasic"
            private const val FILENAME_FORMAT = "yyyy-MM-mm-ss-SSS"	//                 yyyy-MM-dd HH:mm:ss
            private const val REQUEST_CODE_PREMISSIONS = 10
            private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
        }
    }
    
    

    またappプロファイルの下に導入されたライブラリもあります
    // CameraX core library
        def camerax_version = '1.0.0-beta03'
        implementation "androidx.camera:camera-core:$camerax_version"
    
        // CameraX Camera2 extensions
        implementation "androidx.camera:camera-camera2:$camerax_version"
    
        // CameraX Lifecycle library
        implementation "androidx.camera:camera-lifecycle:$camerax_version"
    
        // CameraX View class
        implementation 'androidx.camera:camera-view:1.0.0-alpha10'
    
        // CameraX Extensions library
         implementation "androidx.camera:camera-extensions:1.0.0-alpha10"
    

    最後にOKを実行して基本的に写真を撮る機能を実現しました