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

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

ただいまの
回答率

87.51%

OpenCVを使って画素情報を調べる方法

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,712

score 14

前提・実現したいこと

androidstudioとopenCVを使って、
カメラで撮影している物から赤色のみを抽出するアプリを開発しています。
現在、色を抽出した白と黒の画像から画面全体の画素を調べて
連続する白色の領域のみを数えようと考えています。

発生している問題・エラーメッセージ

画素を調べる際に
HSV形式から画素の情報を調べる方法はあるのでしょうか。

私が調べた限りだと、RGBから調べているものが多く
もしかしたらHSVからRGBに変換しなくては出来ないのでしょうか。

参考までにこちらが色抽出する部分のコードです。

    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);//下限  
        Scalar high = new Scalar(179, 255, 255);//上限 
        Core.inRange(src2, low, high, dst2);//色抽出
         return dst2; }}  

試したこと

保存した結果画像「m_temp」を
Imgproc.cvtColor(m_temp,m_temp,Imgproc.COLOR_HSV2RGB)
でRGBに変換しようと試してみるとこのようなエラーが出てしまいました。

エラーメッセージ

1-08 18:42:30.868 15086-15154/com.example.janome.color2 E/cv::error(): OpenCV Error: Assertion failed (scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F)) in void cv::cvtColor(cv::InputArray, cv::OutputArray, int, int), file /build/master_pack-android/opencv/modules/imgproc/src/color.cpp, line 9825
11-08 18:42:30.869 15086-15154/com.example.janome.color2 E/org.opencv.imgproc: imgproc::cvtColor_11() caught cv::Exception: /build/master_pack-android/opencv/modules/imgproc/src/color.cpp:9825: error: (-215) scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) in function void cv::cvtColor(cv::InputArray, cv::OutputArray, int, int)
11-08 18:42:30.870 15086-15154/com.example.janome.color2 E/AndroidRuntime: FATAL EXCEPTION: Thread-3
                                                                           Process: com.example.janome.color2, PID: 15086
                                                                           CvException [org.opencv.core.CvException: cv::Exception: /build/master_pack-android/opencv/modules/imgproc/src/color.cpp:9825: error: (-215) scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) in function void cv::cvtColor(cv::InputArray, cv::OutputArray, int, int)
                                                                           ]
                                                                               at org.opencv.imgproc.Imgproc.cvtColor_1(Native Method)
                                                                               at org.opencv.imgproc.Imgproc.cvtColor(Imgproc.java:1778)
                                                                               at com.example.janome.color2.MainActivity.onCameraFrame(MainActivity.java:155)
                                                                               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)

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

androidstudio 2.3.1
java
OpenCV 3.0.0

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • umyu

    2017/11/09 00:59

    m_temp.empty()の結果をログに出力して空のMatでないかを確認してください。

    キャンセル

  • shutein

    2017/11/09 23:36

    System.out.println( m_temp.empty()); を記述したらlogcatにfalseが出力されました。

    キャンセル

  • yohhoy

    2017/11/15 15:55 編集

    日本語の質問文と提示ソースコードが合致していないようにも思えますが、質問の趣旨はなんでしょうか?「画素を調べる」というのは、具体的に何を行いたいのでしょう?「保存した結果画像m_temp」はどこから出てきたのでしょう?

    キャンセル

  • shutein

    2017/11/15 16:02

    提示のコードは前段階の赤色の抽出までで、質問はその結果画像(白黒)の中で白い領域を見つけたいと考えています。その後、その領域の数も数えたいです。と

    キャンセル

回答 2

checkベストアンサー

0

質問内容に2つ以上の質問が同居しているようですが、エラーの対処部分の回答です。

エラーの原因:
各画素に24 bit必要なHSVを格納するためのdst の型として、CV_8U (CV_8UC1)を指定したため。

対処法: 型をCV_8UC3に変更する。
Mat dst = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8UC3);


この部分は必要なければ読み飛ばして下さい。

「白と黒」について、少し混乱されているように思います。
RGBでは(255, 255, 255)、HSVでは(0, 0, 255)、8bitのグレースケールでは(255)などが「白」、  
RGBでは(0, 0, 0)、HSVでは(0, 0, 0)、8bitのグレースケールでは(0)などが「黒」  
として扱われると思いますが、これらは(1)を「白」、(0)を「黒」として扱う事と実質的に変わりありません。

また、inRange() の出力に含まれるのは、0xff (255) あるいは 0 のみです。

なので、inRange()で得られたdst2 を、「白黒」画像として扱えばよいかと思います。

参考:
InRange
http://opencv.jp/opencv-2svn/py/core_operations_on_arrays.html#inrange

src(I) が範囲内にあれば dst(I) に 0xff(すべてのビットが 1 )がセットされ,そうでなければ 0 がセットされます


これ以降、旧内容です。消してしまうとコメントの流れが分からなくなるかと思いますので、参考に残しておきます。

OpenCV を触っていないので、的外れかもしれませんが・・

・HSVで赤色のみを抽出

理論上は、(どのような赤かを気にしない場合は) H値のレンジで判定可能かと思います。
ただし、赤は両サイドにある(0度側、360度側)ので、inRange等での判定に工夫が必要かもしれません。
(例えば赤以外を抽出して反転など)

・HSV → RGBの変換でエラー

-- 削除 ここから --

error: (-215) ・・・

RGB値が0~255に収まっていない等の現象が発生したのではないかと推測します。
どこかでfloatが紛れ込んでいませんか?
-- 削除 ここまで --

追記1:

Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8U);

これで確保されるのは、width * height * (8bit) かと思いますので、HSVやRGB用に使用した場合、要素数が不足すると思います。

LouiS0616さんが

空のMatをcvtColorに放り込むと同様のエラーが出ます。

と書かれていますので、同様の現象かと思います。


イメージをつかむために、一応、コードを置いておきます。
OpenCV を触っていないので、参考程度に(コンパイルが通らないかもしれません)

[RGB をそのまま使う版]

public Mat onCameraFrame(Mat inputFrame) {
    Mat src = inputFrame;

    Mat src2 = src; // ここに入っているのはRGB値(の配列)
    Mat dst2 = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8UC3); // changed

    Scalar low = new Scalar(165, 20, 30); // 下限 (これはRGB値としての範囲のように思います)
    Scalar high = new Scalar(179, 255, 255); // 上限 (これはRGB値としての範囲のように思います)

    Core.inRange(src2, low, high, dst2); // 色抽出
    return dst2; 
}

[RGB to HSV 版]

public Mat onCameraFrame(Mat inputFrame) {
    Mat src = inputFrame;
    Mat dst = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8UC3); // changed
    Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2HSV); // RGB to HSV (24 bit)

    Mat src2 = dst; // ここに入っているのはHSV値(の配列)
    Mat dst2 = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8UC3); // changed

    // Scalar low = new Scalar(165, 20, 30); // 下限 (これはRGB値としての範囲のように思います)
    // Scalar high = new Scalar(179, 255, 255); // 上限 (これはRGB値としての範囲のように思います)

    // 範囲はサンプルです。H成分のみ制限。(実際は、赤は360度の方にもつながっているので、範囲等を考慮する必要があります)
    Scalar low = new Scalar(0, 0, 0); // 下限
    Scalar high = new Scalar(10, 255, 255); // 上限

    Core.inRange(src2, low, high, dst2); // 色抽出
    return dst2; 
}

[RGB から 赤色成分を抽出して、「白と黒」として表現して、判定に使う版]

public Mat onCameraFrame(Mat inputFrame) {
    Mat src = inputFrame; // (24bitの配列)
    Mat dst = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8UC1); // CV_8U と同じ(8bitの配列)

    // ここで、srcから 赤色成分を抽出する (長くなるので省略)
    //
    // 「cv::Matの行列要素を,イテレータを介して扱う」
    // http://opencv.jp/cookbook/opencv_mat.html#id40 などを参照
    // 
    // 必要なのは、 srcの各画素 [R, G, B] から 赤色を表す何らかの値(8bitで表現) を計算する処理 と、
    // 計算した値を dst に格納する処理
    //
    // 計算するついでに、色抽出 (一定の値を超えたら1、それ以外は0など)まで処理した方が楽です。

    return dst; 
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/15 16:03 編集

    (質問にコメントしてからこちらに気づいたのですが)一度質問内容と思考を整理し、""質問本文""を更新されたほうが良いように思えます。

    ちなみに画像は2次元データですから、"連続"を考えるときに 1111000111 のような1次元方向だけでよいか?という点を改めて考慮してみてください。一般的にはYukihiro2119さんが指摘するように、輪郭抽出=連続画素の塊と、その面積計算=画素個数のカウントとして考えます。(が、質問者さんの目的次第です)

    キャンセル

  • 2017/11/15 17:53

    @Yukihiro2119 さん
    OpenCVのHのレンジは、[0..179]でしたね。少し勘違いしました。
    inRange()の出力は8Uで固定なので、Mat dst = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8U); を、CV_8UC3にするだけで大丈夫そうな感じがします。

    @shutein さん
    inRange()を通した段階で、黒(0)と白(0xff)に振り分けられています。
    http://opencv.jp/opencv-2svn/py/core_operations_on_arrays.html#inrange
    > src(I) が範囲内にあれば dst(I) に 0xff(すべてのビットが 1 )がセットされ,そうでなければ 0 がセットされます

    あとは、連続している部分のカウントだけかと思います。
    Yukihiro2119 さん、yohhoy さんのおっしゃる通り、1次元(RowやCol)の処理か、2次元の処理かで実装が変わると思います。

    キャンセル

  • 2017/11/17 14:30

    @yohhoyさん、@toris-birdsさん
    もう一度自分で調べて整理したらできました。
    inRange()の時点で2値化していたことが分かっておらず、色々な処理をしてしまったためエラーが出てしまったようです。 

    連続部分のカウントは2次元の処理で考えています。

    キャンセル

0

Java + OpenCV の経験はないので、的外れなことを言っていたらすみません。

結果画像がm_tempに代入されていないのでは?
空のMatをcvtColorに放り込むと同様のエラーが出ます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/08 23:05

    結果画像は別の部分で代入してあります。
    対応箇所のコードを記載してなかったです。

    キャンセル

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

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

関連した質問

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