質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.02%

Kotlin Android camera2のプレビュー表示でopenCVを噛ませたい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 2,377

redp

score 46

 実現したいこと

Kotlinでcamera2APIを使って、最終的にはリアルタイムトラッキングをしたいと考えているのですが、それ以前にプレビュー表示においてグレイスケールに変換して表示したりだとか、Canny法によるエッジ検出した映像を出力したいのです。
つまり、SurfaceViewあるいはTextureViewに非同期で加工したカメラのプレビュー映像を表示したいのですが、どのようにプレビュー映像からフレーム単位で画像を取得して、加工して、SurfaceViewあるいはTextureViewに表示すればいいのかわからないです。
Android開発に関して全くの初心者なので当たり前のことがわかってないことが多いですが、ご教示願います。

 Cameraクラスのソースコード

現在のappはフルスクリーンでプレビュー表示をするのみのものとなっています。
ここではCameraのクラスを示します。

package com.example.user.cvcamera

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.hardware.camera2.params.StreamConfigurationMap
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.util.Size
import android.view.Surface
import android.view.TextureView
import java.util.*

class Camera(activity: Activity, textureView: TextureView) {
    private var mCamera : CameraDevice? = null
    var mTextureView : TextureView? = textureView
    private var mCameraSize : Size? = null
    private var mPreviewBuilder : CaptureRequest.Builder? = null
    var mPreviewSession : CameraCaptureSession? = null
    private val mActivity = activity

    private val mCameraDeviceCallback = object : CameraDevice.StateCallback() {
        override fun onOpened(camera: CameraDevice?) {
            mCamera = camera
            createCaptureSession()
        }

        override fun onDisconnected(camera: CameraDevice?) {
            Log.d("debug", "Disconnected")
            camera?.close()
            mCamera = null
        }

        override fun onError(camera: CameraDevice?, error: Int) {
            Log.d("debug", "Error")
            camera?.close()
            mCamera = null
        }
    }

    private val mCameraCaptureSessionCallback = object : CameraCaptureSession.StateCallback() {
        override fun onConfigured(session: CameraCaptureSession?) {
            mPreviewSession = session
            updatePreview()
        }

        override fun onConfigureFailed(session: CameraCaptureSession?) {
            Log.d("Debug", "onConfiguredFailed ")
        }
    }

    @SuppressLint("MissingPermission")
    fun open() {
        try {
            val manager = mActivity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
            for(cameraId in manager.cameraIdList) {
                Log.d("ID", cameraId.toString())
                val characteristics : CameraCharacteristics = manager.getCameraCharacteristics(cameraId)
                if(characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {
                    val map : StreamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                    mCameraSize = map.getOutputSizes(SurfaceTexture::class.java)[0]
                    manager.openCamera(cameraId, mCameraDeviceCallback, null)
                    return
                }
            }
        } catch (e : CameraAccessException) {
            e.printStackTrace()
        }
    }

    @SuppressLint("Recycle")
    private fun createCaptureSession() {
        if(!mTextureView!!.isAvailable) {
            return
        }

        val texture = mTextureView!!.surfaceTexture
        texture.setDefaultBufferSize(mCameraSize!!.width, mCameraSize!!.height)
        val surface = Surface(texture)
        try{
            mPreviewBuilder = mCamera?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        }catch (e : CameraAccessException) {
            e.printStackTrace()
        }

        mPreviewBuilder?.addTarget(surface)
        try {
            mCamera?.createCaptureSession(Collections.singletonList(surface), mCameraCaptureSessionCallback, null)
        }catch (e : CameraAccessException) {
            e.printStackTrace()
        }
    }

    fun updatePreview() {
        mPreviewBuilder?.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
        mPreviewBuilder?.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
        val thread = HandlerThread("Preview")
        thread.start()
        val backgroundHandler = Handler(thread.looper)

        try {
            mPreviewSession?.setRepeatingRequest(mPreviewBuilder?.build(), null, backgroundHandler)
        }catch (e : CameraAccessException) {
            e.printStackTrace()
        }
    }
}

 試したこと

OpenCVモジュールに用意されているCameraBridgeViewBaseを使い、onCameraFrameメソッドでinputFrameを加工してJavaCameraViewへの表示を試みましたが、思っていた以上に解像度が低かっためこちらの方法にシフトしました。

 補足情報(FW/ツールのバージョンなど)

Android Studio 3.0
OpenCV 3.4.0
Kotlin 1.2.21

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

あまりやりたくなかった方法ですし、このアプローチは間違っているかもしれませんが TextureViewからbitmapを取得し、OpenCVでbitmapを加工してから、別のViewに表示することにしました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる