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

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

新規登録して質問してみよう
ただいま回答率
87.20%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

解決済

カメラの画像(Mat)をトリミングしてからOpenCVで処理を実行したい

m-mega
m-mega

総合スコア52

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

1回答

0評価

0クリップ

550閲覧

投稿2022/03/18 10:24

実現したいこと

Androidスマホのカメラから取得した画像をトリミングして、デフォルトでは画像全体になっているOpenCVの検出範囲を、トリミングした限定的な範囲に変更したいと考えています。

言語は「kotlin」を使用しています。

理想とする処理としては下記のようなものになります。
Python+OpenCVで範囲指定して画像処理を行う方法
画像の一部を切り抜いて保存する
OpenCV with Java 処理事例

できていること

現在、下記のコードでカメラの画像からオレンジ色を検出して輪郭を表示し、認識されたオレンジ色の面積に応じてアクティビティの背景色を変更する処理を実現しています。

kotlin

package jp.gr.java_conf.coskx.targetinggame import android.Manifest import android.annotation.TargetApi import android.content.ContentValues.TAG import android.content.Intent import android.content.pm.PackageManager import android.graphics.Color import android.os.Build import android.os.Bundle import android.util.Log import android.view.View import android.widget.Button import androidx.appcompat.app.AppCompatActivity import org.opencv.android.CameraBridgeViewBase import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2 import org.opencv.core.* import org.opencv.imgproc.Imgproc class MainActivity : AppCompatActivity(), CvCameraViewListener2 { private var mOpenCvCameraView: CameraBridgeViewBase? = null override fun onStart() { super.onStart() var havePermission = true if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions( arrayOf(Manifest.permission.CAMERA), GamePlayActivity.CAMERA_PERMISSION_REQUEST_CODE ) havePermission = false } } if (havePermission) { mOpenCvCameraView!!.setCameraPermissionGranted() } } @TargetApi(Build.VERSION_CODES.M) override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { if (requestCode == GamePlayActivity.CAMERA_PERMISSION_REQUEST_CODE && grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { mOpenCvCameraView!!.setCameraPermissionGranted() } super.onRequestPermissionsResult(requestCode, permissions, grantResults) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // ボタンを押したらゲーム画面へ val btnStart :Button = findViewById(R.id.btnStart) // Viewの取得 btnStart.setOnClickListener { val intent = Intent(this,GamePlayActivity::class.java) // 遷移元と遷移先の設定 startActivity(intent) // 遷移の実行 overridePendingTransition(0, 0) // 遷移時のアニメーションを消す } // OpenCVの設定 System.loadLibrary("opencv_java4") mOpenCvCameraView = findViewById<View>(R.id.camera_view) as CameraBridgeViewBase mOpenCvCameraView!!.setCvCameraViewListener(this) // 画像回転作業負荷を低減するためpreviewの解像度を設定 mOpenCvCameraView!!.setMaxFrameSize(960, 720) } public override fun onResume() { super.onResume() mOpenCvCameraView!!.enableView() } public override fun onDestroy() { super.onDestroy() if (mOpenCvCameraView != null) mOpenCvCameraView!!.disableView() } override fun onCameraViewStarted(width: Int, height: Int) { mMatRed = Mat(height, width, CvType.CV_8UC4) } override fun onCameraViewStopped() { mMatRed?.release() } private var mMatRed: Mat? = null private fun detectRed(img:Mat):Boolean { // 赤色を抽出 <Core.inRange(元Mat, 取得HSVの下限, 取得HSVの上限, 変換後Mat)> Core.inRange(img, Scalar(5.0, 100.0, 100.0), Scalar(15.0, 255.0, 255.0), img) // 赤色の輪郭の面積に応じた処理を実行 return compareContourRed(detectContour(img)) } private fun detectContour(img:Mat): Int { // 輪郭の情報を取得 // ガウシアンフィルタで画像をぼかす Imgproc.GaussianBlur(img, img, Size(5.0, 5.0), 5.0) // 輪郭を取得 Imgproc.Canny(img, img, 10.0, 360.0) // 輪郭の情報を取得 val contours: List<MatOfPoint> = ArrayList() val hierarchy = Mat.zeros(Size(5.0, 5.0), CvType.CV_8UC1) Imgproc.findContours(img, contours, // 輪郭情報を格納 hierarchy, // 階層構造を格納 Imgproc.RETR_EXTERNAL, // 輪郭抽出モードを指定 Imgproc.CHAIN_APPROX_SIMPLE // 輪郭の表示方法を指定 ) return contours.size } private fun compareContourRed(size:Int):Boolean { // 取得した赤色の輪郭サイズを比較 Log.i(TAG, "=================赤色比較:${size} ====================") var maxarea = 20.0 val viewStart : View = findViewById(R.id.viewStart) // スタート画面の背景の取得 if(size > maxarea){ // スタート画面の背景色を赤色に変更 viewStart?.setBackgroundColor(Color.RED) return true } else { viewStart?.setBackgroundColor(Color.WHITE) return false } } override fun onCameraFrame(inputFrame: CameraBridgeViewBase.CvCameraViewFrame): Mat? { // カメラプレビューのフレームをフルカラーで取得 mMatRed = inputFrame.rgba() // 画像をHSVに変換 Imgproc.cvtColor(mMatRed, mMatRed, Imgproc.COLOR_RGBA2BGR) // MatをRGBAからBGRに変換 Imgproc.cvtColor(mMatRed, mMatRed, Imgproc.COLOR_BGR2HSV) // MatをBGRからHSVに変換 // Matを指定範囲でトリミングしてOpenCVの検出範囲を限定的にする // val roi = Rect(0,0, mMatRed!!.width(), mMatRed!!.height()) // mMatRed = Mat(mMatRed, roi) // 赤色の輪郭面積に応じた処理を実行 detectRed(mMatRed!!) return mMatRed } }

やったこと

前述したサイトを参考に、画像(Mat)をトリミングしようと下記のようにコードを作成しました。
(該当箇所はコメントアウトしている部分になります。)

kotlin

override fun onCameraFrame(inputFrame: CameraBridgeViewBase.CvCameraViewFrame): Mat? { // カメラプレビューのフレームをフルカラーで取得 mMatRed = inputFrame.rgba() // 画像をHSVに変換 Imgproc.cvtColor(mMatRed, mMatRed, Imgproc.COLOR_RGBA2BGR) // MatをRGBAからBGRに変換 Imgproc.cvtColor(mMatRed, mMatRed, Imgproc.COLOR_BGR2HSV) // MatをBGRからHSVに変換 // Matを指定範囲でトリミングしてOpenCVの検出範囲を限定的にする // val roi = Rect(0,0, mMatRed!!.width(), mMatRed!!.height()) // mMatRed = Mat(mMatRed, roi) // 赤色の輪郭面積に応じた処理を実行 detectRed(mMatRed!!) return mMatRed }

Rectの範囲を元となる画像(Mat)と同じサイズに設定しています。
そのため、結果としては何もトリミングされないままカメラのプレビューが全画面表示され、検出した色に応じて処理が実行されます。

わからないこと

前述したサイトのように範囲を小さくしてトリミングを行おうとするとエラーが発生してしまい、アプリが強制終了してしまうのですが、何が原因なのでしょうか。

エラー内容

Rectのサイズを小さくすると下記のエラーが発生します。

E/cv::error(): OpenCV(4.5.5) Error: Assertion failed (src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols) in Java_org_opencv_android_Utils_nMatToBitmap2, file /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp, line 101 E/org.opencv.android.Utils: nMatToBitmap caught cv::Exception: OpenCV(4.5.5) /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp:101: error: (-215:Assertion failed) src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols in function 'Java_org_opencv_android_Utils_nMatToBitmap2' E/CameraBridge: Mat type: Mat [ 100*100*CV_8UC3, isCont=false, isSubmat=true, nativeObj=0x739f63fa80, dataAddr=0x7384e0d000 ] E/CameraBridge: Bitmap type: 480*864   E/CameraBridge: Utils.matToBitmap() throws an exception: OpenCV(4.5.5) /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp:101: error: (-215:Assertion failed) src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols in function 'Java_org_opencv_android_Utils_nMatToBitmap2' E/cv::error(): OpenCV(4.5.5) Error: Assertion failed (src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols) in Java_org_opencv_android_Utils_nMatToBitmap2, file /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp, line 101 A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4000 in tid 3074 (OpenCVCameraBac), pid 2978 (x.targetinggame)

要約すると、下記のように記載されているように見受けられます。

nMatToBitmapが例外をキャッチした。  「Java_org_opencv_android_Utils_nMatToBitmap2」関数内では  「 src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols」という条件を満たす必要がある。 BitMapのサイズは480*864にする。

実際、Rectのサイズを元の画像のサイズ(480*864)に戻すとエラーが解消されるので、サイズが原因であることは確かかと考えています。

良い質問の評価を上げる

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

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

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

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

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

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

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

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

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

hoshi-takanori

2022/03/20 18:32

最終的に Utils.matToBitmap を使って OpenCV の Mat を Android の Bitmap に変換して表示か何かしてるんだと思いますが、その際に Bitmap を変換元の Mat と同じサイズ (width, height) で作成する必要があると思います。
m-mega

2022/03/21 06:48

ご回答いただきありがとうございます。 なるほど、つまり処理自体はトリミングした状態で行うとして、最終的に表示する際には元のサイズに戻しておく必要があるということですね。 おっしゃる通り、現在のコードではカメラの映像を画面上にプレビューしておりますので、その際にエラーが出ているのかもしれません。 修正して検証してみます。
hoshi-takanori

2022/03/21 06:59

> 最終的に表示する際には元のサイズに戻しておく必要がある それでもいいですが、サイズ変更した Mat を表示したいなら、Mat と同じサイズの Bitmap を作れば良いってことです。具体的には、 val newBitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888) Utils.matToBitmap(mat, newBitmap) みたいな。
m-mega

2022/03/21 12:02

なるほど。ご丁寧にありがとうございます! 明日早速試してみたいと思います。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。