Cv2.HConcat / VConcat の使い方【OpenCV/C#(OpenCvSharp)】〜画像を横・縦に連結する〜

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

Cv2.HConcat / VConcat の使い方【OpenCV/C#(OpenCvSharp)】〜画像を横・縦に連結する〜

Cv2.HConcat は複数の Mat を横方向(水平)に、Cv2.VConcat は縦方向(垂直)に連結して1枚の Mat を返す関数です。処理前後の比較表示や、複数カメラ映像のタイル合成など、実務で頻繁に使う操作をシンプルに記述できます。

最小の呼び出し例は次のとおりです。

Cv2.HConcat(new Mat[] { left, right }, dst);  // 横に並べる
Cv2.VConcat(new Mat[] { top, bottom }, dst);  // 縦に並べる

動作環境

  • OpenCV 4.x(OpenCvSharp4)
  • .NET 8 コンソールアプリ
  • NuGet: OpenCvSharp4 + OpenCvSharp4.runtime.win(Windows 実行時)

環境構築がまだの方は環境構築ガイドを先にどうぞ。

基本の使い方

横連結(HConcat)の完全プログラム

using OpenCvSharp;

// --- 入力画像をロード ---
using var src1 = Cv2.ImRead("input1.png", ImreadModes.Color);
using var src2 = Cv2.ImRead("input2.png", ImreadModes.Color);

if (src1.Empty() || src2.Empty())
{
    Console.WriteLine("画像の読み込みに失敗しました");
    return;
}

// 高さが異なると HConcat が失敗するため、あらかじめ揃える
using var resized2 = new Mat();
Cv2.Resize(src2, resized2, new Size(src2.Width, src1.Height));

// 横方向に連結
using var hDst = new Mat();
Cv2.HConcat(new Mat[] { src1, resized2 }, hDst);

Cv2.ImWrite("hconcat_result.png", hDst);
Console.WriteLine($"横連結: {hDst.Width} x {hDst.Height}");

実行結果(例: 入力がどちらも 640×480 の場合)

横連結: 1280 x 480

2枚の画像が左右に並んだ 1280×480 の画像が hconcat_result.png として保存されます。

縦連結(VConcat)の完全プログラム

using OpenCvSharp;

using var src1 = Cv2.ImRead("input1.png", ImreadModes.Color);
using var src2 = Cv2.ImRead("input2.png", ImreadModes.Color);

if (src1.Empty() || src2.Empty())
{
    Console.WriteLine("画像の読み込みに失敗しました");
    return;
}

// 幅が異なると VConcat が失敗するため、幅を揃える
using var resized2 = new Mat();
Cv2.Resize(src2, resized2, new Size(src1.Width, src2.Height));

// 縦方向に連結
using var vDst = new Mat();
Cv2.VConcat(new Mat[] { src1, resized2 }, vDst);

Cv2.ImWrite("vconcat_result.png", vDst);
Console.WriteLine($"縦連結: {vDst.Width} x {vDst.Height}");

実行結果(例: 入力がどちらも 640×480 の場合)

縦連結: 640 x 960

各行の解説

箇所 説明
Cv2.ImRead(...) カラー画像を読み込む。ImreadModes.Color でBGR3チャンネル
Cv2.Resize(...) サイズ不一致による連結失敗を防ぐため事前に揃える
Cv2.HConcat(Mat[], dst) 配列内の Mat を左から順に横方向へ並べて dst に書き込む
Cv2.VConcat(Mat[], dst) 配列内の Mat を上から順に縦方向へ並べて dst に書き込む

引数と戻り値

Cv2.HConcat

引数 型 説明
src IEnumerable<Mat> 連結する Mat のコレクション
dst Mat 出力 Mat(既存の Mat に書き込まれる)

制約: 全 Mat の 行数(高さ)が同一、かつ チャンネル数・ビット深度が同一 でなければなりません。

Cv2.VConcat

引数 型 説明
src IEnumerable<Mat> 連結する Mat のコレクション
dst Mat 出力 Mat

制約: 全 Mat の 列数(幅)が同一、かつ チャンネル数・ビット深度が同一 でなければなりません。

戻り値は void。結果は dst に格納されます。

実践例

処理前後を横並びで比較保存する

検査システムや画像処理パイプラインのデバッグでよく使うパターンです。処理前の原画像と処理後の画像を横に並べて1枚で保存すると、レポートやログ確認が楽になります。

using OpenCvSharp;

using var original = Cv2.ImRead("input.png", ImreadModes.Color);
if (original.Empty()) return;

// グレースケール変換してカラーに戻す(チャンネルを揃えるため)
using var gray = new Mat();
using var grayColor = new Mat();
Cv2.CvtColor(original, gray, ColorConversionCodes.BGR2GRAY);
Cv2.CvtColor(gray, grayColor, ColorConversionCodes.GRAY2BGR);

// 原画像 | グレースケール を横に並べる
using var comparison = new Mat();
Cv2.HConcat(new Mat[] { original, grayColor }, comparison);

// ラベルを書き込む
Cv2.PutText(comparison, "Original", new Point(10, 30),
    HersheyFonts.HersheySimplex, 1.0, Scalar.White, 2);
Cv2.PutText(comparison, "Grayscale", new Point(original.Width + 10, 30),
    HersheyFonts.HersheySimplex, 1.0, Scalar.White, 2);

Cv2.ImWrite("comparison.png", comparison);
Console.WriteLine("比較画像を保存しました");

4枚をグリッド(2×2)に並べる

HConcat と VConcat を組み合わせると、任意のグリッドレイアウトを作れます。

using OpenCvSharp;

// 同サイズの画像を4枚用意(ここでは色違いのソリッドで代用)
Size cellSize = new Size(320, 240);
using var img0 = new Mat(cellSize, MatType.CV_8UC3, new Scalar(200, 50, 50));
using var img1 = new Mat(cellSize, MatType.CV_8UC3, new Scalar(50, 200, 50));
using var img2 = new Mat(cellSize, MatType.CV_8UC3, new Scalar(50, 50, 200));
using var img3 = new Mat(cellSize, MatType.CV_8UC3, new Scalar(200, 200, 50));

// 上段: img0 | img1
using var row0 = new Mat();
Cv2.HConcat(new Mat[] { img0, img1 }, row0);

// 下段: img2 | img3
using var row1 = new Mat();
Cv2.HConcat(new Mat[] { img2, img3 }, row1);

// 上段 / 下段 を縦に積む
using var grid = new Mat();
Cv2.VConcat(new Mat[] { row0, row1 }, grid);

Cv2.ImWrite("grid_2x2.png", grid);
Console.WriteLine($"グリッド: {grid.Width} x {grid.Height}");

実行結果

グリッド: 640 x 480

4色のセルが 2×2 に配置された 640×480 の画像が保存されます。

つまずきポイント

⚠️ サイズ不一致でクラッシュする

HConcat は高さ、VConcat は幅が揃っていないと実行時例外が発生します。エラーメッセージは OpenCV ネイティブ側から出るため、C# の例外スタックだけでは原因が分かりにくいことがあります。連結前に必ずサイズ確認・統一を行ってください。

// 悪い例: 高さが違う Mat をそのまま HConcat に渡す
Cv2.HConcat(new Mat[] { mat480px, mat600px }, dst);  // → 実行時例外

⚠️ チャンネル数・ビット深度の不一致

グレースケール(1ch)とカラー(3ch)を混在させると同様に失敗します。グレースケール Mat を連結する前に Cv2.CvtColor で3チャンネルに変換するか、チャンネル数を統一してください。

⚠️ dst の Mat を using で確実に解放する

HConcat / VConcat の出力 dst は内部でネイティブメモリを確保します。using var dst = new Mat(); のように using で宣言し、スコープを抜けたときに自動で Dispose されるようにしてください。長時間動作する検査システムで解放漏れが続くと、ネイティブヒープを圧迫してクラッシュする原因になります。

関連する関数

まとめ

Cv2.HConcat / Cv2.VConcat は、高さ(または幅)とチャンネル数を揃えた Mat の配列を渡すだけで連結画像を生成できます。処理前後の比較保存やマルチカメラのタイル表示など、実務での出番は多い関数です。サイズ・チャンネルの不一致だけ事前にケアすれば、複雑なピクセルコピーを書かずに済みます。

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

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

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

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