cv::Exception「!_src.empty()」の原因と解決方法【C#(OpenCvSharp)】

OpenCV for C#
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイド / C#(OpenCvSharp)セットアップ

はじめに:このエラーが出る典型的な場面

OpenCvSharp で画像処理を書いていると、次のような例外が突然スローされることがあります。

OpenCvSharp.OpenCVException:
  OpenCV: Assertion failed (count > 0) in cv::createMat
  または
  OpenCV: Assertion failed (!_src.empty()) in cv::cvtColor

Cv2.CvtColor や Cv2.ImShow、Cv2.Resize などを呼んだ直後にこの例外が発生するケースが最も多く、初心者が最初にハマるエラーとして知られています。

エラーメッセージの核心は !_src.empty() ——つまり「入力 Mat が空だ」という OpenCV 内部のアサーションです。なぜ空になるのか、そしてどう防ぐのかを順に解説します。


原因

原因1:Cv2.ImRead が失敗して空の Mat を返している

最も多い原因です。Cv2.ImRead はファイルが見つからなくても例外を投げません。空の Mat(mat.Empty == true)を返して処理を続行します。その Mat を次の関数に渡すと !_src.empty() アサーションで落ちます。

よくある失敗パターンを示します。

// ✗ ファイルが存在しなくても例外が出ず、次の行で落ちる
using var src = Cv2.ImRead("image.png");
Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2GRAY); // ← ここでアサーション失敗

ファイルが見つからない主な理由は以下の3つです。

  • パスが間違っている(絶対パスと相対パスの混同)
  • 実行ディレクトリとファイルの場所がずれている(Visual Studio の実行カレントは bin\Debug\net8.0\ 等)
  • 日本語・スペースを含むパスをOSが処理できていない(稀なケース)

原因2:VideoCapture.Read が失敗している

カメラや動画ファイルからフレームを取得するとき、デバイスが開けていない・動画が終端に達したなどの理由でフレームが空になることがあります。VideoCapture の使い方でも触れていますが、Read の戻り値チェックを省略するとこのアサーションに当たります。

原因3:Mat の生成後に中身を入れ忘れている

new Mat() で作成しただけの Mat は空です。何も画像データを入れないまま処理に渡すと同じエラーになります。


解決方法

解決1:ImRead 直後に Empty チェックを入れる

using OpenCvSharp;

// 実行前に bin フォルダへ sample.png を配置しておく
string path = "sample.png";

using var src = Cv2.ImRead(path);

// ⚠️ Empty チェックは必須
if (src.Empty())
{
    Console.Error.WriteLine($"画像の読み込みに失敗しました: {path}");
    Console.Error.WriteLine($"絶対パス確認: {Path.GetFullPath(path)}");
    return;
}

using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
Cv2.ImShow("Gray", gray);
Cv2.WaitKey(0);

Path.GetFullPath(path) でログに絶対パスを出力するのがポイントです。「ファイルはあるはずなのに」というケースでも、実際のカレントディレクトリが想定と違うことがほぼ確実に判明します。

解決2:カレントディレクトリを明示的に指定する

Visual Studio でデバッグ実行すると、カレントは bin\Debug\net8.0\ になります。プロジェクトルートに置いた画像を参照したい場合は以下のようにします。

using OpenCvSharp;

// AppContext.BaseDirectory = 実行ファイルと同じフォルダ
string path = Path.Combine(AppContext.BaseDirectory, "sample.png");

using var src = Cv2.ImRead(path);

if (src.Empty())
{
    Console.Error.WriteLine($"読み込み失敗。確認パス: {path}");
    return;
}

using var dst = new Mat();
Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2GRAY);
Cv2.ImWrite("output_gray.png", dst);
Console.WriteLine("グレースケール変換完了");

プロジェクトファイル(.csproj)で画像を出力フォルダにコピーするよう設定しておくと、パスずれが起きません。

<!-- .csproj に追加 -->
<ItemGroup>
  <None Update="sample.png">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

解決3:VideoCapture のフレーム取得チェック

using OpenCvSharp;

using var cap = new VideoCapture("video.mp4");

if (!cap.IsOpened())
{
    Console.Error.WriteLine("動画ファイルを開けませんでした");
    return;
}

using var frame = new Mat();

while (cap.Read(frame))
{
    // Read が false を返したら(終端 or エラー)ループ終了
    if (frame.Empty()) break;

    Cv2.ImShow("Frame", frame);
    if (Cv2.WaitKey(30) == 27) break; // Esc で終了
}

Cv2.DestroyAllWindows();

再発防止

ImRead の直後には必ず Empty() チェックを書く ことをチームルールにしましょう。OpenCV の設計上、ファイル読み込み失敗は例外ではなく「空の Mat」で表現されます。これを知らないと、原因究明に時間がかかります。

以下のようなヘルパーメソッドを用意してプロジェクト内で共有するのも有効です。

using OpenCvSharp;

/// <summary>
/// 画像を読み込む。失敗時は例外をスローする(失敗を黙殺しない)
/// </summary>
static Mat LoadImageOrThrow(string path, ImreadModes flags = ImreadModes.Color)
{
    var mat = Cv2.ImRead(path, flags);
    if (mat.Empty())
        throw new FileNotFoundException(
            $"画像の読み込みに失敗しました。パスを確認してください: {Path.GetFullPath(path)}", path);
    return mat;
}

呼び出し側は using var src = LoadImageOrThrow("sample.png"); と書くだけになり、空チェックを書き忘れる心配がなくなります。


つまずきポイント

⚠️ ImRead は失敗しても例外を出さない
Python の cv2.imread と同じ挙動です。戻り値を確認しないと、何行も後になって全然関係なさそうな関数の中でアサーションが飛びます。エラー行だけ見ても原因はわかりません。

⚠️ 実行ディレクトリと作業ディレクトリのずれ
"./image.png" で指定したつもりが bin\Debug\net8.0\image.png を探している、というのが最多パターンです。Console.WriteLine(Directory.GetCurrentDirectory()) を仮置きしてカレントを確認する習慣をつけてください。

⚠️ Mat の Dispose 漏れ
空チェックで早期リターンするとき、using ブロックの外で Mat を生成していると Dispose が呼ばれない可能性があります。必ず using var で宣言し、早期リターンしても確実に解放されるようにしてください。


まとめ

状況 対処
ImRead のパスが間違っている Path.GetFullPath でパスを確認し修正
実行ディレクトリに画像がない .csproj で CopyToOutputDirectory を設定
VideoCapture.Read の失敗を無視している 戻り値と frame.Empty() を必ずチェック
new Mat() のまま処理に渡している データを入れてから渡す

!_src.empty() アサーションは 「空の Mat を処理しようとした」 というシンプルなメッセージです。原因は常に「その Mat に画像データが入っていない」ことなので、データがどこで失われたかを Empty() チェックで追いかければ必ず解決できます。

🛠 画像処理のプロが開発するSDK/API

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

タイトルとURLをコピーしました