Q&A
###前提・実現したいこと
私は今、androidstudioでJavaとopencvを使って
画像認識を利用したアプリを開発しています。
その中でImgproc.GaussianBlur()を使い平滑化したのですが、
平滑化した画像「avem2」に対して一定大きさ以上の画素値(輝度値?)を持つ画素を見つけ
座標(x、y)を保存したいと考えています。
平滑化を行う前は2値化した画像で行っています。
###発生している問題・エラーメッセージ
画像の全画素を探査し一定の値を持つ画素の座標を保存する方法を
教えて欲しいです。
調べても画素の探査のみなら
for (int i=0;i< m_temp.height();i=i++) {
for (int j = 0;j< m_temp.width();j= j++)
のようなforループを使えば出来るとは分かったものの
その後の処理が出来るかまでは判明しませんでした。
(追加2)
私なりにやってみましたが、一定の画素値以上のみを取り出すことができず、
エラーが発生してしまいました。
発生したエラー E/AndroidRuntime: FATAL EXCEPTION: Thread-3 Process: com.example.janome.color2, PID: 6055 java.lang.UnsupportedOperationException: Mat data type is not compatible: 5 at org.opencv.core.Mat.get(Mat.java:1015) at com.example.janome.color2.MainActivity.onCameraFrame(MainActivity.java:229) at org.opencv.android.CameraBridgeViewBase$CvCameraViewListenerAdapter.onCameraFrame(CameraBridgeViewBase.java:163) at org.opencv.android.CameraBridgeViewBase.deliverAndDrawFrame(CameraBridgeViewBase.java:399) at org.opencv.android.JavaCameraView$CameraWorker.run(JavaCameraView.java:352) at java.lang.Thread.run(Thread.java:776)
もしかして
mat.get(y,x)で画素値を取り出すことはできないのでしょうか。
以下コードです。
int r =0; int o=0; // double pix=0; double [] data =new double[avem2.width()*avem2.height()]; double[][] data2 =new double[2][avem2.width()*avem2.height()]; avem2.get(0,0,data); for(int y=0;y<avem2.height();y++) { for (int x = 0; x < avem2.width(); x++) { // avem2.get(y,x); //画素値にアクセス // System.out.println("値は"+data[o]); // pix=data[o]; if(data[o]>0.98){ data2[0][r]=x; data2[1][r]=y; // System.out.println(+(r+1)+"番目の座標が"+data2[0][r]+","+data2[1][r]); System.out.println("x座標は"+data2[0][r]+"y座標は"+data2[1][r]); o++; r++; } } }
###該当のソースコード
Java
1 private Mat m_temp; //抽出結果の画像 2 3 public Mat onCameraFrame(Mat inputFrame) { 4 Mat src = inputFrame; 5 Mat dst = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8U); 6 Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2HSV); 7 8 Mat src2 = dst; 9 Mat dst2 = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8U); 10 Scalar low = new Scalar(165, 20, 30);//下限 変更前(10,20,30) S,Vはあまり変えない方が良い? 11 Scalar high = new Scalar(179, 255, 255);//上限 変更前(179,255,255) 12 Core.inRange(src2, low, high, dst2); //色抽出 13 14 15 16 //画面をタッチすると表示画面が保持される 17 if (touId ==2) { 18 // return m_temp; // 保持した画像を代わりに表示する。画像は変化しないので、以降の処理は必要ない 19 touId++; 20 int size = (int) m_temp.total() * m_temp.channels(); //「size」はMatの大きさ的なモノ 21 byte[] temp = new byte[size]; //sizeの値を取るのに使うだけ 22 m_temp.get(0, 0, temp); //mat to array 23 // System.out.println(size); =2073600 24 int stride = 10; 25 int n=0; 26 double ave[] = new double[size/stride/stride]; 27 28 for (int i=0;i< m_temp.height();i=i+stride) { 29 for (int j = 0; j < m_temp.width(); j = j + stride) { 30 double sum = 0; 31 for (int k = i; k < i + stride; k++) { 32 for (int l = j; l < j + stride; l++) { 33 sum += temp[k * m_temp.width() + l]; 34 } 35 } 36 37 38 double relt = sum / stride / stride * -1.0; //平均を求める 符号を正に 39 40 41 if (relt >= 0.7) { //閾値の設定(relt3が小さいため0しか出ない) 42 relt = 1.0; 43 } else { 44 relt = 0.0; 45 } 46 ave[n] = relt; 47// System.out.println(+n +"番目は"+"ave="+ave[n]); 48 n++; //n=20736 49 } 50 } 51 // System.out.println("m_temp.width()="+m_temp.width()+"m_temp.height()="+m_temp.height()); width=1920 height=1080 →プーリングで192 , 108 に 52 Mat avem =new Mat(108,192,CV_32F); 53 avem.put(0,0,ave); // 求めた配列をMatに変換した 54 // System.out.println(avem.dump()); 55 56 Mat avem2 =new Mat(108,192,CvType.CV_32F); 57 Imgproc.GaussianBlur(avem,avem2,new Size(31,31),0,0); // 平滑化 58 59 int r =0; 60 int o=0; 61 double [] data =new double[avem2.width()*avem2.height()]; 62 double[][] data2 =new double[2][]; 63 64 for(int y=0;y<avem2.width();y++) { 65 for (int x = 0; x < avem2.height(); x++) { 66 avem2.get(x,y,data); 67 // avem2.get(x,y); //画素値にアクセス 68 System.out.println("値は"+data[o]); 69 o++; 70 if( data[o] >0.98){ 71 data2[0][r]=x; 72 data2[1][r]=y; 73 // System.out.println(+(r+1)+"番目の座標が"+data2[0][r]+","+data2[1][r]); 74 r++; 75 } 76 } 77 } 78 79 // 最大値を見つけられたが、白い部分を見つけるに至っていない。 80 81 82// Core.MinMaxLocResult max =Core.minMaxLoc(avem2); //最大値を求める部分 83// System.out.println("avem2の最大値="+max.maxVal); //avem2の最大値=1.000000238418579 0.9895517826080322 84// System.out.println("点数は"+point); 85 //固まりを見つけて点数を求めるのはここから↓ 86// for(n=0;n<=20628;n=n+108){ 87// for (n = 0; n < 108; n++) { 88// if(ave[n]==1){ 89// for(n=n+1;n%108==107;n++){ 90// if(ave[n]==1){ 91// 92// } 93 94// 107 > 215 > 323 > 431 n%108==107 95// } 96 97// } 98// } 99// } 100// } 101 return m_temp; 102 } 103 104 if(touId>2){ 105 return m_temp; 106 } 107 108 109 //ここに赤(-1)がいくつ連続するか「固まっているか」を探す内容を書く! 110 111 //(例) 10×10 ピクセルごとに走査(縦→横方向)して ピクセル内の総和(0と-1の総和)÷総ピクセル数で一つの値を求める。 112 // そして閾値を決め、さっきの値を含むか否か分ける。(白の割合がどの程度) 閾値以上であればフラグ(引数的な?)を立てる 113 // また、走査時に白と黒の境の座標などを記録?しておく。 114 //境界の中点の座標を今度は横→縦方向で走査しフラグが重なるか調べることで白い塊が見つかるはず・・(多分) 115 116 /*if (color.val[0] == 0) { 117 Scalar targetColor = inputFrame.get(i, j);*/ 118 119 120 121 if (touId == 1) { 122 touId++; 123 m_temp = dst2; //抽出結果を保持する 124 } 125 return dst2; 126 } 127 128 @Override 129 public boolean onTouchEvent (MotionEvent ev) { 130 switch (ev.getAction()) { 131 case ACTION_DOWN: 132 //画面がタッチされたときの動作 133 if (touId == 0) { 134 touId = 1; 135 } 136 break; 137 case MotionEvent.ACTION_CANCEL: 138 //他の要因によってタッチがキャンセルされたときの動作 139 break; 140 } 141 return super.onTouchEvent(ev); 142 }} 143
###補足情報(言語/FW/ツール等のバージョンなど)
androidstudio 2.3.1
java
OpenCV 3.0.0
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2017/12/10 13:33
2017/12/10 15:07 編集