USBカメラを使ってみよう

この記事は[C# Advent Calendar 2023アドベントカレンダー](https://qiita.com/advent-calendar/2023/csharplang)の18日目です。

C#でWindowsアプリを作成する際に、USBカメラやWebカメラを利用する方法を紹介します。ネットで検索する限り、OpenCVSharpを利用している例が多いのですが、今回は、私が作成したライブラリ「UsbCamera」を紹介します。

「UsbCamera」は、DirectShowを利用して、WinFormsやWPFで、USBカメラ（Webカメラ）を利用するためのライブラリです。プログラムはGitHubで公開されています。リポジトリはこちらです。

https://github.com/secile/UsbCamera

# ライブラリの特徴
UsbCameraの特徴は以下の通りです。
* 導入するには、ソースコードを１つあなたのプロジェクトに追加するだけです。（DLL等は必要ありません）
* WinFormsとWPFの両方に対応しています。
* チルト・ズーム・ホワイトバランス・露出などの設定を行うことができます。(カメラが対応している必要があります)
* カメラの撮影ボタンで静止画を撮影することができます。(カメラが対応している必要があります)

# 導入方法
上記リポジトリからクローンするか、zipファイルをダウンロードしてください。ここでは、zipファイルをダウンロードした場合で解説します。

ダウンロードしたzipを解凍すると、ライブラリ本体である「UsbCamera.cs」と、使い方のサンプルである「SampleProject」フォルダが作成されますので、「UsbCamera.cs」を、あなたのプロジェクトに追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/ec9bf445-b3d6-942e-9a6e-90d1772c7b77.png)

今回は、サンプルプロジェクトでその使用例を説明しますので、「SampleProject」フォルダ内にある「UsbCameraSample.sln」を起動してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/a83f23fd-176c-a09b-8a92-4a5ca0ecd25c.png)

ソリューションには、2つのプロジェクトが含まれています。「UsbCameraForms」がWinForms用で、「UsbCameraWpf」がWPF用です。

プロジェクトを実行して、動作を確認してみてください。画面に、Webカメラの画像が表示されたはずです。

以後、プログラムの中身を解説します。

# 基本的な使い方

### 利用可能なカメラを探す。

```c#
// 利用可能なカメラを探す。
string[] devices = UsbCamera.FindDevices();
if (devices.Length == 0) return; // カメラが見つからなかった。
```

UsbCamera#FindDevices()を呼び出して、PCに接続されているカメラの一覧を取得します。
戻り値はstring[]で、カメラ名の配列が返りますので、この中から、利用したいカメラのインデックス番号を確認します。カメラのインデックス番号は、次の「ビデオフォーマットの作成」や、あとで「UsbCameraクラスのインスタンスを作成する際」に使用します。

### ビデオフォーマットの選択。

```c#
// ビデオフォーマットの取得。
var cameraIndex = 0; // カメラインデックス番号0番のビデオフォーマットを取得。
var formats = UsbCamera.GetVideoFormat(cameraIndex);
```

カメラは320x240, 640x480など、複数の画面サイズに対応しているのが普通です。UsbCamera#GetVideoFormat()を呼び出して、カメラが対応しているビデオフォーマットのリストを取得します。
たとえば私が使用しているPCのWebカメラでは、以下のようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/41ef9302-e53e-987f-5df8-1e9cb547cf2f.png)

この中から、利用したい画像のサイズであるビデオフォーマットを探します。例えば、1920x1080サイズのビデオフォーマットを利用する場合は、formats[0]を、UsbCameraクラスのインスタンス作成時に指定します。

### UsbCameraクラスのインスタンスを作成。

利用したいカメラのインデックス番号と、ビデオフォーマットを指定して、UsbCameraクラスのインスタンスを作成します。インスタンスを作成したら、camera.Start()で動作を開始します。

```c#
// カメラインデックスとビデオフォーマットを指定して、USBカメラクラスのインスタンスを作成
var camera = new UsbCamera(cameraIndex, formats[0]);
camera.Start(); // 動作開始！
```

### 画像の取得。
カメラから画像を取得するには、camera.GetBitmap()を呼び出します。

```c#
button1.Click += (s, ev) => pictureBox1.Image = camera.GetBitmap();
```

### あとしまつ。
フォームクローズ時など、不要になった時点でcamera.Release()を呼び出してください。

```c#
this.FormClosing += (s, ev) => camera.Release(); // release when close.
```

# 高度な使い方
### WPFで利用する。
ライブラリはデフォルトではWinFormsで利用されることを想定されており、GetBitmap()はSystem.Drawing.Bitmap型の画像を返します。
WPFで利用する場合は、「USBCAMERA_WPF」シンボルを定義すると、GetBitmap()はBitmapSource()型で画像を返すようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/91bc5da6-8378-e35a-73b9-cb34cddb1a0e.png)

# プレビューを表示する。
カメラ画像のプレビューを画面に表示したい場合は、WinFormsとWPFで方法が異なります。

WinFormsの場合は、画面にPictureBoxを配置し、camera.SetPreviewControlでプレビューを表示するPictureBoxを指定してください。

```c#
camera.SetPreviewControl(pictureBox1.Handle, pictureBox1.ClientSize);
pictureBox1.Resize += (s, ev) => camera.SetPreviewSize(pictureBox1.ClientSize);
```

WPFの場合は、プレビュー画像が更新されるたびに呼び出されるcamera.PreviewCapturedでデータバインディングを利用して画像を更新してください。詳しくは、サンプルプロジェクトを参照してください。

```c#
camera.PreviewCaptured += (bmp) =>
{
    Preview = bmp;
    OnPropertyChanged("Preview");
};
```

### カメラの撮影ボタンへの対応。
カメラには、通常の動画撮影とは別に、静止画撮影機能をもったものがあります。静止画撮影機能で取得した画像は、一般的に、動画撮影で取得した画像より高解像度なことが多いです。

あなたのカメラに、撮影ボタンが付いていたら、そのカメラは静止画撮影機能に対応している可能性が高いです。静止画撮影機能に対応しているかどうかは、camera.StillImageAvailableで判別できます。ボタンが押されたら、camera.StillImageCapturedがコールバックされます。ボタンの代わりに、camera.StillImageTrigger()を呼び出すことで撮影することもできます。

```c#
if (camera.StillImageAvailable)
{
    button.Click += (s, ev) => camera.StillImageTrigger();
    camera.StillImageCaptured += bmp => pictureBox.Image = bmp;
}
```

### カメラプロパティ(チルト・ズーム・ホワイトバランス・露出など)の変更。
カメラが対応していれば、チルト・ズーム・ホワイトバランス・露出などを変更することができます。

カメラプロパティには大きく、CameraControlProperty系(Pan, Tilt, Roll, oom, Exposure, Iris, Focus)と、VideoProcAmpProperty系(Brightness, Contrast, hue, Saturation, Sharpness, Gamma, ColorEnable, WhiteBalance...)があります。

例えば露出(Exposure)を変更する場合は以下のようになります。プロパティはカメラが対応していない場合もありますので、必ずAvailableプロパティを確認してください。

```c#
// adjust properties.
var prop = camera.Properties[DirectShow.CameraControlProperty.Exposure];
if (prop.Available)
{
    // get current value
    var val = prop.GetValue();
    // set new value
    var min = prop.Min;
    var max = prop.Max;
    var def = prop.Default;
    var step = prop.Step;
    // set new value
    prop.SetValue(DirectShow.CameraControlFlags.Manual, def);
}
```

# おわりに。
以上、駆け足ですが、UsbCameraライブラリの使い方を説明しました。

近年では多くのノートPCにWebカメラが備わっています。もしあなたのPCにカメラがついていたら、試してみてはいかがでしょうか？

それでは、メリークリスマス！