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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

OpenCV

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

Q&A

解決済

1回答

10384閲覧

C#とOpenCvSharp3で対象の画像のヒストグラムを求める方法

Shito_Mutsuki

総合スコア13

C#

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

OpenCV

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

0グッド

0クリップ

投稿2018/09/30 08:49

前提・実現したいこと

C#とOpenCvSharp3で対象の画像のヒストグラムを求め、それをテキストファイルに保存したいです。

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

OpenCvSharp3以前のOpenCvSharpではint型の二次元配列にヒストグラムの値を入れることが出来たようですが、
OpenCvSharp3では、Mat型にヒストグラムの値が入っているみたいなのですが、その値がどこに入っているのか分かりません。

試したこと

Mat型の変数の中のどこかに入っているのだと思い、Dataプロパティの中を見たのですが、二次元配列ではないみたいです。

【言語:C#】
using (Mat histogram2 = new Mat())
{
Cv2.CalcHist(new Mat[] { source2 }, channelsToUse, new Mat(), histogram2, dimention, binCounts, histRange);
var hist = histogram2.Data;

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

開発環境:VisualStuido2017
言語:C#
使用ライブラリ:OpenCvSharp3-AnyCPU(3.4.1.20180319)

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

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

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

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

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

guest

回答1

0

ベストアンサー

Matがどういったものかわかった上で、公開されているメソッド一覧を見ると解決します。
また、Matを理解するためには、チャンネルというものが何かを理解する必要があります。

チャンネルというのは、例えばRGBのことです。
Rチャンネル、Gチャンネル、Bチャンネルです。
このチャンネルがあるため、画像から得られるMatは縦、横、色の3次元配列みたくなります。

ヒストグラムの場合、Matは行1, 列複数, チャンネル1の三次元配列みたくなります。
このときのチャンネルは色ではなく頻度です。

求める値を得るには次の関数を使います。

C#

1hist.GetArray(x,y)[c]

まずチャンネルの配列を取得し、さらに指定したチャンネルの値を取得します。

  • x: 行番号
  • y: 列番号
  • c: チャンネル番号

cv::Matの基本処理の、"マルチチャンネルと多次元配列"という項目を読んでみてください。図があるので非常にわかりやすいです。C++のドキュメントですが、基本は変わりません。

ヒストグラムの値は次のように取得できます。
CalcHistの仕様が理解しきれなかったのですが、もしかすると使い方によってはチャンネルが複数になることがあるかもしれません。

C#

1for(var i = 0; i < hist.Rows; i++) 2 Debug.WriteLine(hist.GetArray(i, 0)[0]);

追記

サンプルコードとしてはこんな感じです。

C#

1 2 public void OutputHists() 3 { 4 var histB = new Mat(); 5 var histG = new Mat(); 6 var histR = new Mat(); 7 8 using (var imgBGR = Cv2.ImRead(@"C:\Users\ppn\Desktop\Lenna.png")) 9 { 10 // 青に関するヒストグラムを作成します 11 Cv2.CalcHist( 12 images: new Mat[] { imgBGR }, 13 channels: new int[] { 0 }, // 0: B 14 mask: new Mat(), // マスクは利用しません 15 hist: histB, 16 dims: 1, 17 histSize: new int[] { 256 }, 18 ranges: new float[][] { new float[] { 0, 256 } }, 19 uniform: true, // ヒストグラムは一様です 20 accumulate: false 21 ); 22 // 緑に関するヒストグラムを作成します 23 Cv2.CalcHist( 24 images: new Mat[] { imgBGR }, 25 channels: new int[] { 1 }, // 1: G 26 mask: new Mat(), // マスクは利用しません 27 hist: histG, 28 dims: 1, 29 histSize: new int[] { 256 }, 30 ranges: new float[][] { new float[] { 0, 256 } }, 31 uniform: true, // ヒストグラムは一様です 32 accumulate: false 33 ); 34 // 赤に関するヒストグラムを作成します 35 Cv2.CalcHist( 36 images: new Mat[] { imgBGR }, 37 channels: new int[] { 2 }, // 2: R 38 mask: new Mat(), // マスクは利用しません 39 hist: histR, 40 dims: 1, 41 histSize: new int[] { 256 }, 42 ranges: new float[][] { new float[] { 0, 256 } }, 43 uniform: true, // ヒストグラムは一様です 44 accumulate: false 45 ); 46 47 // 青に関するヒストグラム 48 for (var i = 0; i < histB.Rows; i++) 49 { 50 var v = histB.GetArray(i, 0)[0]; 51 Debug.Write(v + ", "); 52 } 53 Debug.WriteLine(""); 54 // 緑に関するヒストグラム 55 for (var i = 0; i < histG.Rows; i++) 56 { 57 var v = histG.GetArray(i, 0)[0]; 58 Debug.Write(v + ", "); 59 } 60 Debug.WriteLine(""); 61 // 赤に関するヒストグラム 62 for (var i = 0; i < histR.Rows; i++) 63 { 64 var v = histR.GetArray(i, 0)[0]; 65 Debug.Write(v + ", "); 66 } 67 Debug.WriteLine(""); 68 } 69 }

投稿2018/09/30 11:44

編集2018/09/30 14:43
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Shito_Mutsuki

2018/09/30 13:56 編集

追記: すみません、今気づいたのですが そもそもCv2.CalcHist()を実行すること無く Matから直接値を取ってくるということですね。 ありがとうございます。 ご回答有り難うございます。 ```C# using (Mat histogram2 = new Mat()) { Cv2.CalcHist(new Mat[] { source2 }, channelsToUse, new Mat(), histogram2, dimention, binCounts, histRange); double[,] hist = new double[source2.Size().Height, source2.Size().Width]; for (int i = 0; source2.Size().Height > i; i++) { for (int j = 0; source2.Size().Width > j; j++) { hist[i, j] = histogram2.GetArray(i, j)[0]; } } ``` 上記の方法で、値を取る方法が出来ました。 ただ、もう一つ問題がありまして source2の時点では[333,500]の配列があるのですが Cv2.CalcHist()を実行したあとの histogram2の配列には[256,1]になってしまっています。 まだ調べている途中ですが、現状このような状態です。
退会済みユーザー

退会済みユーザー

2018/09/30 14:33

CalcHistは必要です。これを実行することで、histにヒストグラムの結果が入るので。 また、ヒストグラムですが、[256, 1]の二次元配列で、チャンネルが1のMatで正しいと思います。画像のサイズは関係ないです。 全体的なサンプルコードを追記しました。 もしかすると、Shito_Mutsukiさんが欲しているのはヒストグラムではないかも?と思ったりするのですが、なんのために、どういった結果が欲しいのか説明いただけるとアドバイスできるかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問