[C#] Waveファイルを再生する

アプリでWaveファイルを再生するには、System.Media.SoundPlayerクラスを使うと簡単。

ハードディスク上のWaveファイルを再生する

アプリにリソースとして組み込んだWaveファイルを再生する

[C#] リストから別のリストの内容を取り除く

例えば会員名簿と退会会員名簿がテキストファイルに保存されていて、前者から後者を除外して有効会員名簿を作成するとしよう。それぞれの名簿を文字列リストに読み込んでどう処理するか考察してみたい。ここでは処理時間に関しては議論しない。

手っ取り早いのはRemoveメソッドを使って、リスト中で最初に見つかった要素を削除する方法だろうか。

この方法だと、もし会員名簿に重複して会員が登録されている場合(それが許される場合)、最初の登録しか削除されない。もし名簿が重複を許すことが明らかな場合(そういう仕様ならば)、ぞれぞれのリストから事前に重複要素を削除してから、2つのリストをぶつければ良いだろう。重複要素を削除するにはDistinctメソッドが使える。

参考サイト

Enumerable.Distinct(TSource) メソッド (IEnumerable(TSource)) (System.Linq)
http://msdn.microsoft.com/ja-jp/library/bb348436(v=vs.110).aspx

[C#] ビットマップにピクセル単位で高速にアクセスするには (GetPixel/SetPixel vs BitmapData 速度比較)

Bitmapクラスにはピクセル単位のアクセス関数 SetPixel/GetPixel が用意されているけど、ネットを見るとこれら関数はあまり速くないらしい。これら関数を使う代わりに、ビットマップデータをアンマネージ配列にコピーした 上で処理する方法が推奨されているみたい。画像処理ソフトを書く上で処理速度は重要だ。両者でどれぐらいの速度差があるのか調べてみた。

フルカラー画像を読み込んだ後、ピクセル単位にグレイスケールに変換するのに要した時間をミリ秒単位で計測。グレイスケールへの変換には、YCrCb変換のY値の計算式を使った。

方法1: SetPixel/GetPixelを使う

方法2: ビットマップデータをアンマネージ配列にコピーしてから処理する

方法3: ビットマップをシステムメモリにロックして直アクセスする (バイト単位)

方法2のMarshal.Copyのコストが掛かっているかも?という懸念から。

方法4: ビットマップをシステムメモリにロックして直アクセスする (ピクセル単位)

方法3では1ピクセルごとにMarshal.ReadByte/WriteByteが3回ずつ呼ばれるので、これら関数のオーバーヘッドが掛かっているかも?という懸念から。

テストに使ったデータ

画像1 lena.jpg (400×400ピクセル)
画像2 ff_x_e1_004.JPG (4896×3264ピクセル) – 富士フィルムサイトより拝借

フジノンレンズ XF18-55mmF2.8-4 R LM OIS : サンプル画像 | 富士フイルム
http://fujifilm.jp/personal/digitalcamera/x/fujinon_lens_xf18_55mmf28_4_r_lm_ois/sample_images/

テスト結果

処理時間は以下のようになった。方法3と4は、アンマネージ配列をアロケートしてデータをコピーするコストを考えた代替方法だったのだけど、画像が大きくなってもそのコストは大したことはなかったので気にする必要はなさそう。

# 処理内容 画像1(400×400ピクセル) 画像2(4896×3264ピクセル)
方法1 GetPixel/SetPixel関数を使用 597ms 28,187ms
方法2 アンマネージ配列にコピーした上で処理 10ms 268ms
方法3 システムメモリにロックして直アクセス (バイト単位) 19ms 523ms
方法4 システムメモリにロックして直アクセス (ピクセル単位) 15ms 400ms

環境: Windows 7 Ultimate SP1 (64bit), Intel Core i7 3.4GHz, RAM 16GB, Visual Studio 2012

[C#] 画像ファイルからExif情報を読み出す

C#でExif情報を読み出すプログラムを書けないか調べたところ、System.Drawing.Image.PropertyItems プロパティを使って画像に格納されたメタデータを取得できることがわかった。

Image.PropertyItems プロパティ (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/system.drawing.image.propertyitems(v=vs.90).aspx

Exif情報をテキストファイルにダンプするサンプルを書いてみた。

Exifデータの意味については仕様書を参照。

JEITA / JEITA規格・AV電子機器部門(デジタルカメラ<電子カメラ一般>関係)
http://www.jeita.or.jp/cgi-bin/standard/list.cgi?cateid=1&subcateid=4

Exchangeable image file format for digital still cameras: Exif Version 2.3
http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf

[C#] 画像を拡大/縮小する

画像を簡単に拡大/縮小するにはGraphicsオブジェクトを使う。

まず結果となるビットマップを作成し、そのビットマップからGraphicsオブジェクトを作成。そして、そのGraphicsオブジェクトにソースビットマップを描画する。Graphicsオブジェクトにはビットマップの補間機能が用意されているので、InterpolationModeを指定することで補間モードを設定できる。

参考サイト

@IT:.NET TIPS 画像を高品質に拡大/縮小するには? – C#
http://www.atmarkit.co.jp/fdotnet/dotnettips/023resize/resize.html

[C#] 画像ファイルを高速に読み込むには

ちょっと古い記事(2007/05/24)だけど反応。

画像ファイルを高速に読み込むには?[2.0のみ、C#、VB] - @IT
http://www.atmarkit.co.jp/fdotnet/dotnettips/597fastloadimg/fastloadimg.html

この記事では画像ファイルからImageオブジェクトを作成する手順を解説している。気になったのは、Imageクラスのインスタンスを作成する際に「画像データの検証」をするかしないかのオプションがあり、それによって処理速度が大きく左右されるということ。

自分で検証してみる。そのために、フォームにPictureBoxを配置し、画像ファイルを読み込んで生成したImageオブジェクトをPictureBoxにアサインする、という簡単なテストプログラムを作成した。画像ファイルからどのようにImageオブジェクトを生成するか、3つの方法を試してみたい。

方法1: Image.FromFile()を使う

もっとも簡単な方法。

方法2: Image.FromStream()を使う

ファイル名だけ指定してFromStream()を使う。

方法3: Image.FromStream()を使う – イメージデータ検証無し

2つのオプション付きのFromStream()を試してみる。2番目の引数はカラーマネージメント情報の適用の有無、3番目の引数はイメージデータの検証の有無を指定する。共に false と指定。

処理速度

前回のエントリ同様に、4896×3264ピクセルのサンプル画像を使って処理時間を計測した。結果は方法3が他の2つより2桁も速い。「イメージデータの検証」を無しにすると読み込み速度を向上できることがわかった。

# 使用関数 処理時間
方法1 Image.FromFile() 132ms
方法2 Image.FromStream() 155ms
方法3 Image.FromStream() イメージデータ検証なし 2ms

環境: Windows 7 Ultimate SP1 (64bit), Intel Core i7 3.4GHz, RAM 16GB, Visual Studio 2012

イメージデータの検証は何をしているのか?

イメージデータの検証は何をしているのかという疑問が残った。Image.FromStreamメソッドはMSDNでは以下の通り説明されている。

Image.FromStream メソッド (Stream, Boolean, Boolean) オプションで埋め込み色管理情報の使用とイメージ データの検証を行い、指定したデータ ストリームから Image を作成します。 public static Image FromStream( Stream stream, bool useEmbeddedColorManagement, bool validateImageData ) useEmbeddedColorManagement データ ストリームに埋め込まれている色管理情報を使用する場合は true。それ以外の場合は false。 validateImageData イメージ データを検証する場合は true。それ以外の場合は false。 useEmbeddedColorManagement パラメーターは、データ ストリームに埋め込まれた色管理情報に従って、新しい Image に色補正を適用させるかどうかを指定します。 埋め込み情報には、ICC (International Color Consortium) プロファイル、ガンマ値、および色度情報を含めることができます。

useEmbeddedColorManagementの意味はなんとなくわかる。だけどvalidateImageDataの意味がわからない。「イメージデータを検証する」って何をしてるの?そういえば.NETってオープンソースでPC以外のプラットフォームにも移植されてたよな、と思って調べたらソースらしきものが見つかった。

Image.cs source code in C# .NET
http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/ REDBITS/ndp/fx/src/CommonUI/System/Drawing/Image@cs/1/Image@cs

このソースを見ると、validateImageDataがtrue、すなわち「イメージ データを検証する」とした場合、GDI+のGdipImageForceValidationが呼ばれている。だけど、ネットでGdipImageForceValidationの情報を探すも見つからず。かろうじてMSDNの以下ページに「This function forces validation of the image.」とだけ記載されていた。

Image Functions (Windows)
http://msdn.microsoft.com/en-us/library/ms534041(v=vs.85).aspx

更に情報を求めてネットを検索していたら、Windowsアプリを別プラットフォームで動かすWINEというプロジェクトを見つけた。

WineHQ – Run Windows applications on Linux, BSD, Solaris and Mac OS X
http://www.winehq.org/

GDI+の互換ライブラリが含まれているらしいのでダウンロードしてソースを閲覧したのだが、関数は存在したけど処理は実装されてなかった。Image.FromStreamメソッドの「イメージデータの検証」は何をやっているのか、残念ながらわからずじまい。

[C#] 品質を指定してJPEG画像を保存する

品質の指定は、Bitmap.Save() にエンコードパラメータを与えるだけ。

参考サイト

方法 : JPEG 圧縮レベルの設定
http://msdn.microsoft.com/ja-jp/library/bb882583(v=vs.110).aspx

[C#] 画像ファイルを書き出す

Bitmap.Saveメソッドに画像ファイル名を渡すと画像をファイルに保存できる。以下の画像形式の指定無しのメソッドを使うと画像はPNG形式に保存される。試しにファイル名の拡張子を”.jpg”にしてみたが、やはり画像はPNG形式で保存された。

PNG以外の形式に保存したければ、以下のようにファイル形式を指定する。

参考サイト

Image.Save メソッド (String) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/ktx83wah(v=vs.110).aspx

Image.Save メソッド (String, ImageFormat) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/9t4syfhh(v=vs.110).aspx

[C#] 画像ファイルを読み込む

C#では標準でGDI+が使われているので、画像の扱いは非常に楽になった。

画像ファイルは、Bitmapのコンストラクタに画像ファイル名を渡すだけで読み込める。このコンストラクターは、BMP、GIF、EXIG、JPG、PNG、および TIFF の各ファイル形式の画像を開くときに使用できる。

参考サイト

Bitmap コンストラクター (Type, String) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/47591zc7(v=vs.110).aspx

[C#] 定数を定義する

C/C++で定数を定義するのに#defineマクロを使った。C#では?

C#で#defineマクロは使えるのか?

C#にも#defineは存在する。だけど定数の定義には使えない。

#define (C# リファレンス) – Visual Studio 2008
http://msdn.microsoft.com/ja-jp/library/yt3yck0x(v=vs.90).aspx

#define ディレクティブを使用して、通常 C および C++ で行うように定数値を宣言することはできません。C# の定数は、クラスまたは構造体の静的メンバとして定義することができます。そのような定数がいくつかある場合は、それを保持するための “Constants” クラスを個別に作成することを検討してください。

ちなみに、C#で使えるプリプロセッサディレクティブに関しては以下参照。

C# プリプロセッサ ディレクティブ
http://msdn.microsoft.com/ja-jp/library/ed8yd1ha(v=vs.90).aspx

C#で定数を定義する方法

以下のサイトに説明あり。

方法 : C# で定数を定義する
http://msdn.microsoft.com/ja-jp/library/vstudio/bb397677.aspx

C# では、C および C++ で一般的な #define プロセッサ ディレクティブを使用する方法で定数は定義できません。

整数型 (int、byte など) の定数値を定義するには、列挙型を使用します。 詳細については、「enum (C# リファレンス)」を参照してください。

整数型以外の定数を定義する 1 つの方法としては、Constants という名前の 1 つの静的クラスにそれらをグループ化します。 これを行うには、次の例に示すように、クラス名の前に定数へのすべての参照を付ける必要があります。

クラスの再利用性を高めるための工夫

アプリが多数のクラスで構成されている場合、それぞれのクラスがConstantsクラスを参照するようにしてしまうと、クラスの再利用性が低下する。言い換えるならば、あるクラスを別のプロジェクトにコピーしてビルドすると「Constantsクラスが未定義」と叱られるわけだ。できればConstantsクラスが無いプロジェクトにコピーしても、とりあえずビルドが通るようなクラスにしておきたい。 クラスの再利用性を高めるためには、クラス間の依存性を高くしないことが重要。そのためには、予めクラス内にデフォルトの動作定数を持たせておいて、プログラム起動時に必要に応じてそれを書き換えるといったような実装をするのも一案。コーディングの手間は若干増えるけど、クラスの再利用性は高まるはず。