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

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

ただいまの
回答率

91.35%

  • Java

    10476questions

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

  • Android

    5174questions

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

  • Android Studio

    2719questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

  • OpenCV

    622questions

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

openCVを使った画素値取得とその座標の保存方法

受付中

回答 1

投稿 2017/12/06 15:45 ・編集 2017/12/07 15:58

flag 質問者が4日前に「まだ回答を求めています」と言っています。

  • 評価
  • クリップ 0
  • VIEW 99

shutein

score 7

前提・実現したいこと

私は今、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++;
                   }
                }
            }

該当のソースコード

 private Mat m_temp; //抽出結果の画像

    public Mat onCameraFrame(Mat inputFrame) {
        Mat src = inputFrame;
        Mat dst = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8U);
        Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2HSV);

        Mat src2 = dst;
        Mat dst2 = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8U);
        Scalar low = new Scalar(165, 20, 30);//下限  変更前(10,20,30)  S,Vはあまり変えない方が良い?
        Scalar high = new Scalar(179, 255, 255);//上限 変更前(179,255,255)
        Core.inRange(src2, low, high, dst2); //色抽出



        //画面をタッチすると表示画面が保持される
        if (touId ==2) {
            // return m_temp;   // 保持した画像を代わりに表示する。画像は変化しないので、以降の処理は必要ない
           touId++;
            int size = (int) m_temp.total() * m_temp.channels(); //「size」はMatの大きさ的なモノ
            byte[] temp = new byte[size]; //sizeの値を取るのに使うだけ
            m_temp.get(0, 0, temp);  //mat to array
           // System.out.println(size); =2073600
            int stride = 10;
            int n=0;
            double ave[] = new double[size/stride/stride];

            for (int i=0;i< m_temp.height();i=i+stride) {
                for (int j = 0; j < m_temp.width(); j = j + stride) {
                    double sum = 0;
                    for (int k = i; k < i + stride; k++) {
                        for (int l = j; l < j + stride; l++) {
                            sum += temp[k * m_temp.width() + l];                  
                        }
                    }


                    double relt = sum / stride / stride * -1.0;             //平均を求める 符号を正に


                    if (relt >= 0.7) {                               //閾値の設定(relt3が小さいため0しか出ない)
                        relt = 1.0;
                    } else {
                        relt = 0.0;
                    }
                    ave[n] = relt;                                              
//                                System.out.println(+n +"番目は"+"ave="+ave[n]);
                    n++;      //n=20736
                }
            }
            // System.out.println("m_temp.width()="+m_temp.width()+"m_temp.height()="+m_temp.height());      width=1920  height=1080 →プーリングで192 , 108 に
            Mat avem =new Mat(108,192,CV_32F);
            avem.put(0,0,ave);    // 求めた配列をMatに変換した
         //  System.out.println(avem.dump());

            Mat avem2 =new Mat(108,192,CvType.CV_32F);
            Imgproc.GaussianBlur(avem,avem2,new Size(31,31),0,0);   //  平滑化

            int r =0;
            int o=0;
            double [] data =new double[avem2.width()*avem2.height()];
            double[][] data2 =new double[2][];

            for(int y=0;y<avem2.width();y++) {
                for (int x = 0; x < avem2.height(); x++) {
                   avem2.get(x,y,data);
                  //  avem2.get(x,y);   //画素値にアクセス
                   System.out.println("値は"+data[o]);
                      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]);
                       r++;
                   }
                }
            }

          // 最大値を見つけられたが、白い部分を見つけるに至っていない。


//            Core.MinMaxLocResult max =Core.minMaxLoc(avem2);   //最大値を求める部分
//            System.out.println("avem2の最大値="+max.maxVal);   //avem2の最大値=1.000000238418579  0.9895517826080322
//            System.out.println("点数は"+point);
            //固まりを見つけて点数を求めるのはここから↓
//          for(n=0;n<=20628;n=n+108){
//              for (n = 0; n < 108; n++) {
//                  if(ave[n]==1){
//                    for(n=n+1;n%108==107;n++){
//                      if(ave[n]==1){
//
//                      }

//                          107 > 215 > 323 > 431 n%108==107
//                    }

//                    }
//                  }
//                  }
//              }
          return m_temp;
        }

         if(touId>2){
             return m_temp;
         }


                  //ここに赤(-1)がいくつ連続するか「固まっているか」を探す内容を書く!

                  //(例) 10×10 ピクセルごとに走査(縦→横方向)して ピクセル内の総和(0と-1の総和)÷総ピクセル数で一つの値を求める。
                  // そして閾値を決め、さっきの値を含むか否か分ける。(白の割合がどの程度) 閾値以上であればフラグ(引数的な?)を立てる
                  // また、走査時に白と黒の境の座標などを記録?しておく。
                  //境界の中点の座標を今度は横→縦方向で走査しフラグが重なるか調べることで白い塊が見つかるはず・・(多分)

                    /*if (color.val[0] == 0) {
                        Scalar targetColor = inputFrame.get(i, j);*/



                 if (touId == 1) {
                    touId++;
                    m_temp = dst2; //抽出結果を保持する
                }
                return dst2;
            }

            @Override
            public boolean onTouchEvent (MotionEvent ev) {
                switch (ev.getAction()) {
                    case ACTION_DOWN:
                        //画面がタッチされたときの動作
                        if (touId == 0) {
                            touId = 1;
                        }
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        //他の要因によってタッチがキャンセルされたときの動作
                        break;
                }
                return super.onTouchEvent(ev);
            }}

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

androidstudio 2.3.1
java
OpenCV 3.0.0

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

+1

Q103546.java

package tsukka.teratail.questions.q103546;

import java.util.HashSet;
import java.util.Set;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import tsukka.utility.function.BytePredicate;

/**
 *
 * @author tsukka
 */
public class Q103546 {
    public static void main (String... args){
        System.out.println(System.getProperty("java.library.path"));
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        //画像読み込み
        Mat im = Imgcodecs.imread("test.png"); // 入力画像の取得

        //二値化
        Imgproc.cvtColor(im, im, Imgproc.COLOR_BGR2GRAY); //グレースケールに変換
        Imgproc.threshold(im, im, 0, 255, Imgproc.THRESH_OTSU); //閾値を自動で設定
        //二値化ここまで

        Mat avem2=new Mat(im.size(),CvType.CV_8U);
        //平滑化
        Imgproc.GaussianBlur(im, avem2, new Size(17,13), 0, 0);

        //書き込み
        //Imgcodecs.imwrite("out.png", avem2);

        //画素値250以上のpointを取得してsetに代入
        Set<IntPoint> s=getMatchPoints(avem2,c->c>(byte)250);//255*0.98
        //出力
        s.forEach(System.out::println);
    }
    /**
     * org.opencv.core.Pointはdoubleしか扱えない罠
     * @param avem2 グレースケールあるいは二値画像
     * @param tester 条件 ちなみに画素値が渡されてくる
     * @return 条件を満たした座標のデータ
     */
    public static Set<IntPoint> getMatchPoints(Mat avem2,BytePredicate tester){
        int width=avem2.width();
        int height=avem2.height();
        byte [] data =new byte[width*height];
        avem2.get(0,0,data);
        HashSet<IntPoint> ret=new HashSet<>();
        for(int y=0;y<height;y++) {
            for (int x = 0; x < width; x++) {
                if(tester.test(data[y*width+x])){
                    ret.add(new IntPoint(x,y));
                }
            }
        }
        return ret;
    }

}

IntPoint.java

package tsukka.teratail.questions.q103546;

import org.opencv.core.Point;

/**
 *
 * @author tsukka
 */
public class IntPoint {

    public int x, y;

    public IntPoint(int x, int y) {
        this.x = x;
        this.y = y;
    }


    @Override
    public String toString() {
        return '(' + Integer.toString(x) + ',' + Integer.toString(y) + ')';
    }

    public Point toPoint() {
        return new Point(x, y);
    }
}


BytePredicate.java

package tsukka.utility.function;

/**
 *
 * @author tsukka
 */
@FunctionalInterface
public interface BytePredicate {
    default BytePredicate and​(BytePredicate other){
        return b->this.test(b)&&other.test(b);
    }
    default BytePredicate negate​(){
        return b->!this.test(b);
    }     
    default BytePredicate or​(BytePredicate other) {
        return b->this.test(b)||other.test(b);
    }    
    boolean test(byte value);
}


byteでならとれると思われる
ちなみに白なら-1(255)黒なら0
1ピクセル当たり1インデックス

ラムダとか使えないなら適宜書き換えてください

投稿 2017/12/07 16:02

編集 2017/12/11 00:06

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/10 22:33

    回答ありがとうございます。
    目を通したのですが、
    Q103546.javaのmainの部分で何をしているか教えて頂きたいです。

    キャンセル

  • 2017/12/11 00:07 編集

    そこは質問者様の質問にあったように画像を読み込みそれに対して二値化した後平滑化を行ない状況を合わせています
    その後平滑化画像を書き出し(これいらないやつですね)
    さらにgetMatchPointsメソッドを呼び出して条件に合う点を抽出(今回は画素値250以上を対象にしました)
    最後にそれを表示しています
    全体の説明はこんなところです
    更にわからないところがあればどこがわからないのか詳しくお願いします
    ちなみにgetMatchPointsメソッドの使い方がこんな感じ程度の意味しかありません

    直接の回答はgetMatchPointsメソッドになります

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

  • 解決済

    OpenCV for UnityでwebCamTextureToMatできない

    OpenCV for Unityを使ってウェブカメラの画像をいじろうとしているのですが、WebCamTextureをMatに変換しようとするときに出るエラーが解決できずにいます。

  • 受付中

    テンプレートマッチング時のエラーについて教えてくださいm(__)m

    以前質問をし、エラーが解決しましたがうまくテンプレートマッチングが行えません。 デバックでみたところ49行目の"Point matchLoc;"で✖がついてしまいます・・・ 原

  • 解決済

    OpenCVを用いた物体検出

    現在OpenCV2.1を用いた上で顔検出にチャレンジしています。 学習等については問題なく行うことができ、顔の検出を行おうと思っているのですが、検出の段階で設定するパラメータの"m

  • 解決済

    配列のプログラムについて

    配列を使って最大値・最小値・平均値を求めるプログラムを作りたいのですが、うまく出力結果が出ません。(コンパイルは成功) import java.util.Scanner; pu

  • 解決済

    androidstudio 色検出

    androidstudioで色検出をしようとしています。このサイトのコードをほぼほぼコピペしたのですが FdActivity.javaでonCreateOptionsMenuの中の

  • 解決済

    OpenCVを使ってカメラ撮影画面から1フレームを保存(撮影)したい

    前提・実現したいこと androidstudioとopenCVを使って、 カメラで撮影している物から赤色のみを抽出するアプリを開発しています。 現在、撮影している画面の1フレームを

  • 解決済

    ラベリング処理を行いたい

    前提・実現したいこと こんにちは。 https://youtu.be/CBXrsAJOKhQ こちらのテニスシーンの映像においてラベリング処理をBackgroundSubtract

  • 解決済

    EclipseでJava用のOpenCVのプログラムを動かしたい

    EclipseでJava用のOpenCVのプログラムを動かしたい Eclipseで2つの画像を比較した時のヒストグラム値を算出するというプログラムを動かしたいのですが、エラーが出て

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

  • Java

    10476questions

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

  • Android

    5174questions

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

  • Android Studio

    2719questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

  • OpenCV

    622questions

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