2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

撮影画像に露光・ゲイン・ROIなどの設定情報を記録する【Baslerカメラ / C#】

Posted at

撮影画像に露光・ゲイン・ROIなどの設定情報を記録する【Baslerカメラ / C#】

画像ファイルに「撮影時の設定」を記録できれば、
後からその画像が どんな条件で撮られたのか を再現・比較できます。

今回は、EXIFの代替として
ファイル名・CSV・JSON・XML で設定値を記録する方法を紹介します。

EXIFとは?

EXIF(エグジフ)とは、Exchangeable Image File Format の略で、
JPEGやTIFFなどの画像ファイルに撮影時の情報(メタデータ)を埋め込むための規格です。

✅ EXIFで記録される主な情報

種類
撮影日時 2025:08:06 21:30:00
カメラ機種 Canon EOS 5D Mark IV
レンズ情報 50mm F1.8
シャッター速度 1/125
ISO感度 ISO 400
絞り(F値) f/2.8
サムネイル画像 簡易表示用

産業用カメラで取得した画像を保存する際は.bmpで保存することも多いですが、
EXIFには非対応です。そのため、どんな条件で撮影をしたかのログをメタデータとして別途残しておく必要があります。


✅ 使用環境

項目 内容
カメラ Basler acA2500-14gm
SDK pylon Camera Software Suite
言語 C# / .NET 8
保存形式 BMP + メタデータ

今回も前回記事(Baslerカメラの設定を保存・読み込みする方法)で紹介したBaslerCameraSampleクラスに機能を追加し、実行例を紹介していきます。


📝 方法①:PFS形式で保存する(Pylon限定)

Basler製カメラpylon SDKを使用している場合は、PFS形式で保存するのが手軽です。PFSファイルとは、pylon Feature Stream file の略で、Basler製カメラの設定を保存・読み込みに使えます。

本来PFSは撮影条件を外部ログに残すというより、カメラ本体の設定スナップショットを保存するものですが、これを撮影ログとして代替してしまおうという考え方です。

実際のコード例については前回記事(Baslerカメラの設定を保存・読み込みする方法)で紹介しています。

PFS形式はTSV形式で、テキストエディタにより内容を確認することができます。また、撮影条件再現の観点からも都合がいいです。


📝 方法②:ファイル名に設定情報を埋め込む

ファイル名にメタ情報を埋め込みます。手軽でファイル移動に強く、よく見かける手法ですが、管理が大変になることも多いです。

一方、ファイルエクスプローラの検索が活用できる点は地味に嬉しかったりします。実務では実験担当や画像処理担当の要望に応じて情報を付加し、別の方法で撮影条件も残しておくのがいいと思います。

[TestMethod()]
public void SaveCameraDeviceSettingsTest_AsFileName()
{
    if (!_baslerCameraSample.IsConnected)
        _baslerCameraSample.Connect();

    double exposure = _baslerCameraSample.GetExposureTime();
    int gain = _baslerCameraSample.GetGainRaw();
    int width = _baslerCameraSample.GetWidth();
    int height = _baslerCameraSample.GetHeight();

    var bitmap = _baslerCameraSample.SnapToBitmapSource(1000);

    string filename = $"SaveCameraDeviceSettingsTest_Exp{exposure:F0}_Gain{gain}_{width}x{height}.bmp";
    BaslerCameraSample.SaveBitmap(bitmap, filename);

    Assert.IsTrue(File.Exists(filename), $"File {filename} should be created.");
}

出力例:

SaveCameraDeviceSettingsTest_Exp35000_Gain0_2592x1944.bmp
  • メリット:画像だけでも条件がわかる
  • デメリット:長くなりすぎると管理しづらい

📋 方法③:CSVにログを保存する(一覧・集計用)

撮影するたび、CSVに条件を追記する方法です。

[TestMethod()]
public void SaveCameraDeviceSettingsTest_AsCsv()
{
    if (!_baslerCameraSample.IsConnected)
        _baslerCameraSample.Connect();

    double exposure = _baslerCameraSample.GetExposureTime();
    int gain = _baslerCameraSample.GetGainRaw();
    int width = _baslerCameraSample.GetWidth();
    int height = _baslerCameraSample.GetHeight();

    // まず撮影して画像を保存する。
    var bitmap = _baslerCameraSample.SnapToBitmapSource(1000);
    var filename = $"SaveCameraDeviceSettingsTest_{DateTime.Now:yyyyMMdd_HHmmss}.bmp";
    BaslerCameraSample.SaveBitmap(bitmap, filename);

    // 撮影条件をCSVに追加
    string logPath = "capture_log.csv";
    bool fileExists = File.Exists(logPath);
    using var writer = new StreamWriter(logPath, append: true);
    if (!fileExists)
    {
        // 最初の1行目にヘッダが来るようにする。
        writer.WriteLine("Timestamp,Exposure,Gain,Width,Height,FileName");
    }

    writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss},{exposure},{gain},{width},{height},{filename}");

    Assert.IsTrue(File.Exists(filename), $"File {filename} should be created.");
}

CSV出力例:

Timestamp,Exposure,Gain,Width,Height,FileName
2025-08-19 01:17:39,35000,0,2592,1944,SaveCameraDeviceSettingsTest_20250819_011739.bmp
2025-08-19 01:21:08,35000,0,2592,1944,SaveCameraDeviceSettingsTest_20250819_012108.bmp
  • メリット:ExcelやPythonで集計可能
  • デメリット:画像とセットで移動しないと情報が欠落する

📦 方法④:JSON形式で保存する(構造化データ)

設定用の型を作り、JsonSerializerでJSON形式にシリアライズして保存します。

using System.Text.Json;

[TestMethod()]
public void SaveCameraDeviceSettingsTest_AsAnonymousTypeJson()
{
    if (!_baslerCameraSample.IsConnected)
        _baslerCameraSample.Connect();

    double exposure = _baslerCameraSample.GetExposureTime();
    int gain = _baslerCameraSample.GetGainRaw();
    int width = _baslerCameraSample.GetWidth();
    int height = _baslerCameraSample.GetHeight();

    // まず撮影して画像を保存する。
    var bitmap = _baslerCameraSample.SnapToBitmapSource(1000);
    var filename = $"SaveCameraDeviceSettingsTest_{DateTime.Now:yyyyMMdd_HHmmss}.bmp";
    BaslerCameraSample.SaveBitmap(bitmap, filename);

    // 匿名型でメタデータを作成
    var metadata = new
    {
        Timestamp = DateTime.Now,
        Exposure = exposure,
        Gain = gain,
        Width = width,
        Height = height,
        FileName = filename
    };

    // JSON形式でメタデータを保存
    // WriteIndentedをtrueに設定して、整形されたJSONを生成。
    string json = JsonSerializer.Serialize(metadata, new JsonSerializerOptions
    {
        WriteIndented = true
    });
    var jsonFilePath = Path.ChangeExtension(filename, ".json");
    File.WriteAllText(jsonFilePath, json);
    Assert.IsTrue(File.Exists(jsonFilePath), $"File {jsonFilePath} should be created.");
}

JSON出力例:

{
  "Timestamp": "2025-08-19T01:39:34.8826328+09:00",
  "Exposure": 35000,
  "Gain": 0,
  "Width": 2592,
  "Height": 1944,
  "FileName": "SaveCameraDeviceSettingsTest_20250819_013934.bmp"
}

実際は匿名型ではなく設定用のクラスを別途用意することがほとんどだと思います。カメラ設定以外にアプリケーション固有の情報も追加します。例えば、カメラが動く場合には撮影した座標や角度を加えます。他にもPFSを保存し、対応するPFSファイルのパスを残すこともあります。

  • メリット:プログラムで扱いやすい/API連携に向いている
  • デメリット:CSVと比較し、一覧性に欠ける

📄 方法⑤:XML形式で保存する(構造化データ)

Basler以外のメーカでは、XMLでカメラ設定を保存することもあります。

using System.Xml.Linq;

[TestMethod()]
public void SaveCameraDeviceSettingsTest_AsXML()
{
    if (!_baslerCameraSample.IsConnected)
        _baslerCameraSample.Connect();

    double exposure = _baslerCameraSample.GetExposureTime();
    int gain = _baslerCameraSample.GetGainRaw();
    int width = _baslerCameraSample.GetWidth();
    int height = _baslerCameraSample.GetHeight();

    // まず撮影して画像を保存する。
    var bitmap = _baslerCameraSample.SnapToBitmapSource(1000);
    var filename = $"SaveCameraDeviceSettingsTest_{DateTime.Now:yyyyMMdd_HHmmss}.bmp";
    BaslerCameraSample.SaveBitmap(bitmap, filename);

    // XML形式でメタデータを作成
    var xml = new XElement("CaptureMetadata",
        new XElement("Timestamp", DateTime.Now),
        new XElement("Exposure", exposure),
        new XElement("Gain", gain),
        new XElement("Width", width),
        new XElement("Height", height),
        new XElement("FileName", filename)
    );

    // XML形式でメタデータを保存
    var xmlFileName = Path.ChangeExtension(filename, ".xml");
    xml.Save(xmlFileName);
    Assert.IsTrue(File.Exists(xmlFileName), $"File {xmlFileName} should be created.");
}

XML出力例:

<CaptureMetadata>
  <Timestamp>2025-08-19T02:28:10.2621161+09:00</Timestamp>
  <Exposure>35000</Exposure>
  <Gain>0</Gain>
  <Width>2592</Width>
  <Height>1944</Height>
  <FileName>SaveCameraDeviceSettingsTest_20250819_022810.bmp</FileName>
</CaptureMetadata>

個人的にはXMLファイルはタグ構造が冗長になりやすく、可読性の観点からあまり採用しません。

なお、GenICam規格ではカメラ設定をXMLで記述するように定められています。このXMLはCamera Description Fileといい、直接扱う必要がある場合にはXMLを操作する必要があります。

  • メリット:Basler以外のメーカで採用例あり
  • デメリット:ファイルサイズが増える傾向

⚠️ 注意点

項目 内容
EXIFには直接書けない BMPやPNGはEXIF非対応(JPEGなら可能)
同名ファイル対策 ファイル名に日時を含めて重複防止
PFS/JSON/XMLの保存先 画像と同じフォルダに置くと管理が楽

✅ まとめ

  • ファイル名:単独で条件がわかる
  • CSV:大量データの集計に向く
  • JSON/XML:プログラム連携やUI表示に便利
  • BaslerカメラはEXIF非対応なので、このような外部メタデータが有効

迷ったときはJSONかCSVで保存すると、実装しやすく管理しやすいことが多いです。


次回は、これらのログを使って撮影プロファイルの管理UIを構築する方法を解説します。


筆者:@MilleVision


🛠 サンプルコード完全版のご案内

Qiita記事で紹介しているサンプルコードをまとめた C#プロジェクト(単体テスト付き)
BOOTHにて配布しています。

  • 単体テストプロジェクト同梱で動作確認や学習がスムーズ
  • 記事更新にあわせてアップデート予定

👉 商品ページはこちら

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?