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.CopyMakeBorder — 画像にパディング(余白)を追加する。サイズを揃えてから連結したいときに組み合わせて使う
- Cv2.Resize — 連結前のサイズ統一に必須
- Cv2.CalcHist の使い方【OpenCV/C#(OpenCvSharp)】〜ヒストグラムを計算する〜 — 処理前後の分布比較をHConcatで並べると視覚的に分かりやすい
- Cv2.EqualizeHist / CLAHE の使い方【OpenCV/C#(OpenCvSharp)】〜ヒストグラム平坦化で画像のコントラストを改善する〜 — 補正前後を横並び比較する実践例に組み合わせられる
まとめ
Cv2.HConcat / Cv2.VConcat は、高さ(または幅)とチャンネル数を揃えた Mat の配列を渡すだけで連結画像を生成できます。処理前後の比較保存やマルチカメラのタイル表示など、実務での出番は多い関数です。サイズ・チャンネルの不一致だけ事前にケアすれば、複雑なピクセルコピーを書かずに済みます。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

