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

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

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

ARCoreは、グーグル社が提供しているAndroid向けのAR(拡張現実)フレームワークです。スマホ内蔵のカメラとIMUセンサー(慣性計測装置)を使って、モーショントラッキングや水平面の検出、光源の推測を行い、ARを実現します。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenCV

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

Android

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

1回答

3600閲覧

端末のカメラが撮影している動画を画像処理して画面上に映し出したい

Suchmos23

総合スコア6

ARCore

ARCoreは、グーグル社が提供しているAndroid向けのAR(拡張現実)フレームワークです。スマホ内蔵のカメラとIMUセンサー(慣性計測装置)を使って、モーショントラッキングや水平面の検出、光源の推測を行い、ARを実現します。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenCV

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

Android

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2020/11/01 11:42

編集2022/01/12 10:55

やろうとしていること

Google ARcoreとOpenCVを利用してandroid端末でカメラを起動させ,リアルタイムでカメラが撮影している動画データをOpenCVに渡してOpenCV側で画像処理を行った画像データを画面上に映し出したいです.

できていること

android端末のカメラが取得した画像データを画面上に映し出す.

android端末のカメラが撮影している動画をリアルタイムで画面上に投影している様子

できていないこと

android端末のカメラが取得した画像データをOpenCVに流して画像処理(例えば,2値化)を行う.

わからないこと

以下のソースコードで試してみたが,アプリを実行した際にアプリがすぐ落ちてしまいます.
原因はおそらく,update関数内でMatの生成をしていることが処理を重くしてアプリが落ちる原因だと考えています.
しかし,update関数の中以外で,どの箇所でMatの生成を行えばリアルタイムで動画を処理できるのでしょうか...

画像処理が分からないわけではなく,現状のコードではなぜアプリが落ちてしまうのか,その改善方法が分からないです.

ソースコード

C#

1using System; 2using UnityEngine; 3 4//GoogleARcore 5using GoogleARCore; 6using GoogleARCore.Examples.ComputerVision; 7 8//OpenCVForUnity 9using OpenCVForUnity; 10using OpenCVForUnity.UnityUtils; 11using OpenCVForUnity.ImgprocModule; 12using OpenCVForUnity.CoreModule; 13 14 15 16public class TextureRenderWrapper : MonoBehaviour 17{ 18 19 //Textureの生成 20 Texture2D new_tex; 21 Texture2D out_tex; 22 23 24 //Matの作成 25 Mat imgMat; 26 Mat imgMat2; 27 Mat hsvMat; 28 Mat blurMat; 29 30 //-------------------------------------- 31 32 /// <summary> 33 /// 取得するTextureのサイズの、カメラ画像に対する割合 34 /// </summary> 35 public float TextureSizeRatio = 1.0f; 36 37 /// <summary> 38 /// カメラ画像のデータ群 39 /// </summary> 40 private TextureReaderApi.ImageFormatType format; 41 private int width; 42 private int height; 43 private IntPtr pixelBuffer; 44 private int bufferSize = 0; 45 46 /// <summary> 47 /// カメラ画像取得用API 48 /// </summary> 49 private TextureReader TextureReader = null; 50 51 52 /// <summary> 53 /// カメラ画像のサイズに合わせてTextureReaderをセットしたかどうかのフラグ 54 /// </summary> 55 private bool setFrameSizeToTextureReader = false; 56 public void Awake() 57 { 58 // // カメラ画像取得時に呼ばれるコールバック関数を定義 59 // TextureReader = GetComponent<TextureReader>(); 60 // TextureReader.OnImageAvailableCallback += OnImageAvailableCallbackFunc; 61 } 62 63 private void OnImageAvailableCallbackFunc(TextureReaderApi.ImageFormatType format, int width, int height, IntPtr pixelBuffer, int bufferSize) 64 { 65 this.format = format; 66 this.width = width; 67 this.height = height; 68 this.pixelBuffer = pixelBuffer; 69 this.bufferSize = bufferSize; 70 } 71 72 73 void Start() 74 { 75 // AwakeからStartへ初期化を移動(TextureRender.csの初期化がStartのため) 76 TextureReader = GetComponent<TextureReader>(); 77 TextureReader.OnImageAvailableCallback += OnImageAvailableCallbackFunc; 78 79 } 80 81 82 void Update() 83 { 84 85 86//----------------------------------------------------------------このあたりの処理をupdateに書いているため処理が重くなっていると考える.しかし,それ以外の方法が分からない. 87     88 new_tex = new Texture2D(height, width, TextureFormat.RGBA32, false); 89 new_tex = FrameTexture;//FrameTexture関数内で取得している_texをnew_texに代入する._texにandroid端末がリアルタイム撮影している画像データが入っている. 90 91 92 //Matを生成する 93 imgMat = new Mat(new_tex.height, new_tex.width, CvType.CV_8UC3); 94 Utils.texture2DToMat(new_tex, imgMat); 95 96 //ガウシアンフィルターによる平滑化 97 imgMat2 = new Mat(new_tex.height, new_tex.width, CvType.CV_8UC3); 98 Imgproc.GaussianBlur(imgMat, imgMat2, new Size(5, 5), 0); 99 100 // BGRからHSVに変換 101 hsvMat = new Mat(new_tex.height, new_tex.width, CvType.CV_8UC3);//CV_8UC3?? 102 Imgproc.cvtColor(imgMat2, hsvMat, Imgproc.COLOR_RGB2HSV); 103 104 //medianBlur化 105 blurMat = new Mat(new_tex.height, new_tex.width, CvType.CV_8UC3);//CV_8CU3?? 106 Imgproc.medianBlur(hsvMat, blurMat, 3); 107 108 //画像の平坦化 109 Imgproc.equalizeHist(blurMat, blurMat); 110 111 out_tex = new Texture2D(imgMat.cols(), imgMat.rows(), TextureFormat.RGBA32, false); 112 Utils.matToTexture2D(blurMat, out_tex); 113 114 gameObject.GetComponent<Renderer>().material.mainTexture = out_tex;//画面上のcubeに貼り付ける 115 116//-------------------------------------------------------------------------------------------- 117 118 119 120 121 // TextureReaderにカメラ画像のサイズをセットする。実行は一回だけ 122 if (!setFrameSizeToTextureReader) 123 { 124 using (var image = Frame.CameraImage.AcquireCameraImageBytes()) 125 { 126 if (!image.IsAvailable) 127 { 128 return; 129 } 130 131 TextureReader.ImageWidth = (int)(image.Width * TextureSizeRatio); 132 TextureReader.ImageHeight = (int)(image.Height * TextureSizeRatio); 133 TextureReader.Apply(); 134 135 setFrameSizeToTextureReader = true; 136 } 137 } 138 } 139 140 public bool isRed(float x, float y) 141 { 142 // グレイスケールが選択されているとき 143 if (format == TextureReaderApi.ImageFormatType.ImageFormatGrayscale) 144 { 145 return false; 146 } 147 148 // TextureReaderが取得した画像データのポインタからデータを取得 149 byte[] data = new byte[bufferSize]; 150 System.Runtime.InteropServices.Marshal.Copy(pixelBuffer, data, 0, bufferSize); 151 // 向きが270回転と反転しているので補正する 152 byte[] correctedData = Rotate90AndFlip(data, width, height, format == TextureReaderApi.ImageFormatType.ImageFormatGrayscale); 153 154 // サイズを合わせる 155 int x_arg = (int)(x / 2.25); 156 int y_arg = (int)(y / 3); 157 int w_arg = height; 158 int h_arg = width; 159 int ch = 4; 160 int th = 50; 161 int idx = (y_arg * w_arg * ch) + (x_arg * ch); 162 163 // 画素値を取得 164 int r = correctedData[idx + 0]; 165 int g = correctedData[idx + 1]; 166 int b = correctedData[idx + 2]; 167 168 // 簡易的に red 検出 169 int diff_rg = r - g; 170 int diff_rb = r - b; 171 if ((diff_rg > th) & (diff_rb > th)) 172 { 173 return true; 174 } 175 return false; 176 } 177 178 public Texture2D FrameTexture 179 { 180 get 181 { 182 if (bufferSize != 0) 183 { 184 // TextureReaderが取得した画像データのポインタからデータを取得 185 byte[] data = new byte[bufferSize]; 186 System.Runtime.InteropServices.Marshal.Copy(pixelBuffer, data, 0, bufferSize); 187 // 向きが270回転と反転しているので補正する 188 byte[] correctedData = Rotate90AndFlip(data, width, height, format == TextureReaderApi.ImageFormatType.ImageFormatGrayscale); 189 // Texture2Dを作成 90度回転させているのでwidth/heightを入れ替える 190 Texture2D _tex = new Texture2D(height, width, TextureFormat.RGBA32, false, false); 191 _tex.LoadRawTextureData(correctedData); 192 _tex.Apply(); 193 194 return _tex; 195 } 196 else 197 { 198 return null; 199 } 200 } 201 } 202 203 private byte[] Rotate90AndFlip(byte[] img, int width, int height, bool isGrayscale) 204 { 205 int srcChannels = isGrayscale ? 1 : 4; 206 int dstChannels = 4; //出力は常にRGBA32にする 207 byte[] newImg = new byte[width * height * dstChannels]; 208 209 for (int i = 0; i < height; i++) 210 { 211 for (int j = 0; j < width; j++) 212 { 213 //imgのindex 214 int p = (i * width + j) * srcChannels; 215 216 //newImgに対するindex. 90度回転と反転を入れている 217 int np = ((width - j - 1) * height + (height - i - 1)) * dstChannels; 218 219 // グレースケールでもRGBで扱えるようにしておく 220 if (isGrayscale) 221 { 222 newImg[np] = img[p]; // R 223 newImg[np + 1] = img[p]; // G 224 newImg[np + 2] = img[p]; // B 225 newImg[np + 3] = 255; // A 226 } 227 else 228 { 229 for (int c = 0; c < dstChannels; c++) 230 { 231 newImg[np + c] = img[p + c]; 232 } 233 } 234 } 235 } 236 237 return newImg; 238 } 239}

吐かれているエラー

  • Adreno-GSL: <gsl_memory_alloc_pure:2270>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.  
  • Unity : OPENGL NATIVE PLUG-IN ERROR: GL_OUT_OF_MEMORY: Not enough memory left to execute command
  • Unity : (Filename: ./Runtime/GfxDevice/opengles/GfxDeviceGLES.cpp Line: 354)  
  • Unity : Could not allocate memory: System out of memory!  
  • Unity : Trying to allocate: 1228804B with 16 alignment. MemoryLabel: Texture  
  • Unity : Allocation happened at: Line:78 in  Unity : Memory overview

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/11/01 12:30

OpenCVとは言ってもいろいろな言語から使えますので、C#タグを明記した方が答えをもらえやすいです。
Suchmos23

2020/11/01 13:45

分かりました。ありがとうございます!
退会済みユーザー

退会済みユーザー

2020/11/02 01:12 編集

落ちるという曖昧な表現では、見た人は何も分かりません。 最低限どの行で強制終了しているか、例外が発生しているなら、例外内容をスタックトレース含めて載せてください。 どこで強制終了しているかがまだ分かっていないのであれば、ログ出力などを組み込んでどこまで正常に動いているか追跡してください。
Suchmos23

2020/11/02 04:25

出力されているエラーは以下のとおりです.  Adreno-GSL: <gsl_memory_alloc_pure:2270>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.  Unity : OPENGL NATIVE PLUG-IN ERROR: GL_OUT_OF_MEMORY: Not enough memory left to execute command Unity : (Filename: ./Runtime/GfxDevice/opengles/GfxDeviceGLES.cpp Line: 354)  Unity : Could not allocate memory: System out of memory!  Unity : Trying to allocate: 1228804B with 16 alignment. MemoryLabel: Texture  Unity : Allocation happened at: Line:78 in  Unity : Memory overview
退会済みユーザー

退会済みユーザー

2020/11/02 04:41 編集

この欄だと読みづらいので、質問文を編集してそちらに追記してください。 out of memoryと出てますが、メモリリークを起こしてメモリ食いつぶしてたりはしてないですか?
Suchmos23

2020/11/02 08:25

エラーを質問文に追加しました. メモリリークを起こしている可能性はあると思います.というのもソースコードのupdate関数内で本来はimgMatの作成を行わないためです.ですが,自分はそれ以外の方法がわからなくて困っています. さらに,自分はメモリの解放を行っていません.具体的なメモリの解放方法もわからないです.
guest

回答1

0

実際に試せないので推測での回答になりますが、out of memoryが出ているということは、大量にMatを生成することでメインメモリを食いつぶしているのではないかと推定します。

毎回Matを生成するのはコスト高そうなので、Startの辺りで生成してメンバ変数に保持しておくと良いかもしれません。カメラ停止のタイミングが拾えるのであれば、その時点でメンバ変数に保持しているMatをDisposeすれば良さそうな気がします。

投稿2020/11/02 23:45

編集2020/11/02 23:47
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

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

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問