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

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

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

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

Java

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

Android

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

Android Studio

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

Q&A

解決済

2回答

6272閲覧

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

shutein

総合スコア14

OpenCV

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

Java

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

Android

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

Android Studio

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

0グッド

0クリップ

投稿2017/11/08 09:49

編集2017/11/08 09:58

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

###発生している問題・エラーメッセージ
画素を調べる際に
HSV形式から画素の情報を調べる方法はあるのでしょうか。

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

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

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

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

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

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

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

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

umyu

2017/11/08 15:59

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

2017/11/09 14:36

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

2017/11/15 06:56 編集

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

2017/11/15 07:02

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

回答2

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/12 04:35

編集2017/11/15 09:32
toris-birds

総合スコア122

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

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

shutein

2017/11/12 06:53

赤説明が分かりにくかったかもしれないですが 色の抽出はすでに出来ており、おっしゃるように判定に工夫が必要でした。 現在出来ていないのは 抽出結果の画像(赤は白く、他は黒)から白い画素を調べたいです。
shutein

2017/11/12 06:54

floatがあるかよくわからないですが、 「CV_8U」という部分がもしかしたらfloatを使っているかもしれないです。
toris-birds

2017/11/12 06:56

白黒の場合も、配列の要素の値の範囲チェックかと思いますので、範囲指定が変わるだけかと思います。
shutein

2017/11/12 07:07

何度もすいません。 もう少し詳しく教えて欲しいのですが、 赤色と同じ方法で画素の情報(座標やHSVの値など)を取得することができるのでしょうか。 赤色は画像にフィルタをしているだけではないのでしょうか。
toris-birds

2017/11/12 07:24

とりあえずエラーの方は、コードを見直してみると、Mat.zeros(width(), height(), CV_8U); となっているので、HSVやRGBだと要素数が足りていない(3倍必要なはず)というエラーなのかなと推測します。 赤色と同じ方法で座標、HSV・・の部分は、元データ(RGB画像)から直接取得できるかという事でしょうか? HSVでも白黒でも、(元がRGB値なら) 計算値になるかと思います。
shutein

2017/11/12 07:39

説明不足でした。 同じ方法で・・の部分は 赤色を抽出した白と黒の結果画像(HSV)から白色の画素情報を取得することが出来るのか という意味です。
toris-birds

2017/11/12 07:59 編集

白黒はモノクロ8bitの事かと思っていました。 HSVは、色相(H)、彩度(S)、明度(V)で色を表す方法ですので、白黒に変換した結果として使用するのは、あまり適切ではないかと思います。(一応、明度が白黒の要素にあたります) Wikiの「HSV色空間」などに一旦目を通すことをお勧めします。
shutein

2017/11/12 08:15

モノクロ8bitとはグレイスケールのことで合ってますか。 不適切であるならば 結果画像をHSV→RGBに変換して画素を取得する方法のほうが実現できるのでしょうか。
toris-birds

2017/11/12 08:50

一旦、やりたいことを整理しましょう。 inputFrameが、RGB画像として渡される所がスタートですよね?赤色=R値と考える場合は、変換は一切いりません。srcに対して、inRangeなどで、R値の範囲チェックをするだけです。  これに対して、RGB値の「赤色成分」を何らかの形で「白と黒(グレイスケール)」に変換した結果を、8bitの配列に入れたのであれば、この8bitの配列に対して範囲チェックをする必要がある、というだけです。 また、RGB値をHSV(何色なのか、色の濃さ、明るさ)に変換したのであれば、HSV値を格納した配列に対して、範囲チェックが必要になります。 ここまでは理解されているでしょうか?
shutein

2017/11/14 06:44

返信が遅くなりすいません。 はい、inputFrameがスタートです。 わたしはRGB値をHSVに変換して、 Scalorで範囲を指定し、赤い部分を白色に、それ以外を黒色で 出力しています。 ここまでは説明のおかげでそこそこ理解できたと思います。
Yukihiro2119

2017/11/14 09:50 編集

for(int i = 0; i < dst2.width(); i++){  for(int j = 0; j < dst2.height(); j++){   Scalar color = dst2.get(i,j);   if(color.val[0] == 0){    Scalar targetColor = inputFrame.get(i,j);   }  } } のようなことをしたいのでしょうか
Yukihiro2119

2017/11/14 09:58

@toris-birds さん shuteinさんは既にHSV空間でのinRangeで赤色部分のマスク画像(CV_8U:1チャンネルの白黒画像)に変換することに成功しています。 おそらくHSVとマスク画像が同一チャンネルと勘違いしているため、マスク画像に対してImgproc.cvtColor(m_temp,m_temp,Imgproc.COLOR_HSV2RGB) を実行し、エラーがでたのかと思います。 白黒のマスク画像:CV_8U(1チャンネル) HSV画像:CV_8UC3(3チャンネル) で、今回得られたdst2は白黒のマスク画像になります。 src or inputFrame がRGB:CV_8UC3(3チャンネル) dst がHSV:CV_8UC3(3チャンネル) dst2 がBW:CV_8U(1チャンネル) となっています、今回取得したい値がRGB値ということであれば例えば Mat target = Mat.zeros(inputFrame.width(), inputFrame.height(), CV_8UC3); inputFrame.copyTo(target , dst2); のような形にしてあげると赤色部分の領域だけ抽出できます。 (赤色部分の領域以外は黒になる。) もし実現したいことが違うのであれば、訂正お願い致します。
shutein

2017/11/15 06:22

@Yukihiro2119さん まさにそんな感じです。 その処理を白黒画像に対してやりたいと考えてます。 最終的には白と黒なら値が「0と1」の2通りで表されるはずなので、 連続する白の塊がいくつ画像内にあるか数えたいと思っています。
shutein

2017/11/15 06:41

連続というのは 白を「1」とするならば「1111100011111」 のような感じで1が続いた部分がいくつあるか(上の例ならば2つ)を数えられないかと考えています。
yohhoy

2017/11/15 07:05 編集

(質問にコメントしてからこちらに気づいたのですが)一度質問内容と思考を整理し、""質問本文""を更新されたほうが良いように思えます。 ちなみに画像は2次元データですから、"連続"を考えるときに 1111000111 のような1次元方向だけでよいか?という点を改めて考慮してみてください。一般的にはYukihiro2119さんが指摘するように、輪郭抽出=連続画素の塊と、その面積計算=画素個数のカウントとして考えます。(が、質問者さんの目的次第です)
toris-birds

2017/11/15 08: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次元の処理かで実装が変わると思います。
shutein

2017/11/17 05:30

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

0

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

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

投稿2017/11/08 10:06

LouiS0616

総合スコア35658

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

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

shutein

2017/11/08 14:05

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問