cv::hconcat / vconcat の使い方【OpenCV/C++】〜画像を連結する〜
cv::hconcat は複数の cv::Mat を水平方向(横並び)に、cv::vconcat は垂直方向(縦並び)に結合する関数です。処理前後の比較画像を並べたり、複数カメラ映像をタイル表示したりといった場面で頻繁に使います。
最小コードは次の通りです。
cv::Mat result;
cv::hconcat(left, right, result); // 横に並べる
cv::vconcat(top, bottom, result); // 縦に並べる
動作環境
- OpenCV 4.x
- C++17
- ビルド例:
g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4) -o main
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
int main()
{
// サンプル用にソリッドカラーの画像を生成
cv::Mat img_blue(200, 300, CV_8UC3, cv::Scalar(255, 0, 0));
cv::Mat img_green(200, 300, CV_8UC3, cv::Scalar(0, 255, 0));
cv::Mat img_red(200, 300, CV_8UC3, cv::Scalar(0, 0, 255));
// --- 水平連結(横並び)---
cv::Mat h_result;
cv::hconcat(img_blue, img_green, h_result); // 2枚を横に連結
cv::imshow("hconcat: blue | green", h_result);
// --- 3枚以上は std::vector を使う ---
std::vector<cv::Mat> imgs = {img_blue, img_green, img_red};
cv::Mat h_triple;
cv::hconcat(imgs, h_triple); // 3枚を横に連結
cv::imshow("hconcat: blue | green | red", h_triple);
// --- 垂直連結(縦並び)---
cv::Mat v_result;
cv::vconcat(img_blue, img_green, v_result);
cv::imshow("vconcat: blue / green", v_result);
cv::waitKey(0);
return 0;
}
実行結果:
ウィンドウ "hconcat: blue | green" → 横 600px × 縦 200px のウィンドウ(左半分が青、右半分が緑)
ウィンドウ "hconcat: blue | green | red" → 横 900px × 縦 200px(青・緑・赤が横並び)
ウィンドウ "vconcat: blue / green" → 横 300px × 縦 400px(上が青、下が緑)
行ごとの解説
cv::hconcat(src1, src2, dst)— 2引数版。内部ではsrc1とsrc2の行数・チャンネル数が一致しているかを検証し、横方向に並べた新しいMatをdstに書き出します。cv::hconcat(vector<Mat>, dst)—std::vector<cv::Mat>を渡すと任意枚数を一度に連結できます。vconcatも同様です。- 生成した
Matのサイズはhconcatなら(rows, sum_of_cols)、vconcatなら(sum_of_rows, cols)になります。
引数と戻り値
cv::hconcat
| 引数 | 型 | 説明 |
|---|---|---|
src1 |
InputArray |
1枚目の入力画像 |
src2 |
InputArray |
2枚目の入力画像 |
dst |
OutputArray |
出力画像(横に結合された結果) |
または
| 引数 | 型 | 説明 |
|---|---|---|
src |
InputArrayOfArrays |
連結する画像の配列(std::vector<cv::Mat> 等) |
dst |
OutputArray |
出力画像 |
戻り値: なし(void)
cv::vconcat
hconcat と同じシグネチャで、方向が垂直になります。
実践例
処理前後を横並びで比較する
画像処理の結果確認でよく使うパターンです。入力画像とフィルタ適用後の画像を横に並べて一つのウィンドウで確認できます。
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return 1;
}
// グレースケール変換してから3チャンネルに戻す(hconcat は型を揃える必要がある)
cv::Mat gray, gray_bgr;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
cv::cvtColor(gray, gray_bgr, cv::COLOR_GRAY2BGR); // チャンネル数を src に合わせる
// 横並びで比較
cv::Mat compare;
cv::hconcat(src, gray_bgr, compare);
cv::imshow("Before | After", compare);
cv::waitKey(0);
return 0;
}
実行結果:
"Before | After" ウィンドウに元画像(カラー)とグレースケール画像が横並びで表示されます。
ウィンドウ幅は元画像の2倍になります。
4枚をグリッド(2×2)表示する
hconcat と vconcat を組み合わせると格子状のタイル表示が作れます。
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
int main()
{
// 4枚分の画像をロード(実運用ではカメラ映像などを想定)
std::vector<std::string> paths = {"img0.jpg", "img1.jpg", "img2.jpg", "img3.jpg"};
std::vector<cv::Mat> imgs;
const cv::Size tile_size(320, 240); // タイルサイズを統一
for (const auto& p : paths) {
cv::Mat m = cv::imread(p);
if (m.empty()) {
std::cerr << "読み込み失敗: " << p << std::endl;
return 1;
}
cv::Mat resized;
cv::resize(m, resized, tile_size); // サイズを揃えないと連結できない
imgs.push_back(resized);
}
// 上段: imgs[0] | imgs[1]、下段: imgs[2] | imgs[3]
cv::Mat row0, row1, grid;
cv::hconcat(imgs[0], imgs[1], row0);
cv::hconcat(imgs[2], imgs[3], row1);
cv::vconcat(row0, row1, grid);
cv::imshow("2x2 Grid", grid);
cv::waitKey(0);
return 0;
}
実行結果:
640×480 のウィンドウに 4 枚の画像が 2×2 で並んで表示されます。
つまずきポイント
⚠️ サイズ・型が一致しないと assertion で落ちる
hconcat は行数(rows)とチャンネル数・深度が全画像で一致していないと実行時 assertion error になります。vconcat は列数(cols) が一致している必要があります。
// hconcat なら rows・型が異なると assertion 失敗
// vconcat なら cols・型が異なると assertion 失敗
対策として、連結前に cv::resize でサイズを統一し、cv::cvtColor でチャンネル数を揃えてください(グレースケールとカラーの混在に注意)。
⚠️ グレースケール(1ch)とカラー(3ch)を混在させると型エラー
よくあるミスは cv::imread で読んだカラー画像と cv::cvtColor で作ったグレースケール画像をそのまま連結しようとするケースです。チャンネル数が異なるため assertion で落ちます。
// NG: gray は CV_8UC1、src は CV_8UC3
cv::hconcat(src, gray, result);
// OK: gray を BGR に戻してから連結
cv::cvtColor(gray, gray_bgr, cv::COLOR_GRAY2BGR);
cv::hconcat(src, gray_bgr, result);
✅ copyMakeBorder と組み合わせてサイズを揃える
異なるサイズの画像をリサイズせずにそのまま並べたい場合は、小さい側に余白を付けてサイズを揃える方法があります。cv::copyMakeBorder の使い方 を参照してください。
関連する関数
- cv::copyMakeBorder — 画像に余白を追加してサイズを統一する際に hconcat と組み合わせて使います。記事はこちら
- cv::addWeighted — 並べるのではなく2枚を重ねてブレンドしたい場合に使います。cv::add / addWeighted の使い方
- cv::absdiff — 比較画像を作る用途で hconcat と一緒によく使います。cv::absdiff の使い方
- cv::resize — サイズ統一のセットで使う必須の前処理関数
- cv::Mat::push_back —
vconcatの代替として行単位で Mat を積み上げる方法
まとめ
cv::hconcat / vconcat は画像を横・縦に並べる最もシンプルな手段です。連結前にサイズ・チャンネル数・深度を揃えることが唯一かつ最重要の注意点です。std::vector<cv::Mat> を渡すオーバーロードを使えば3枚以上も一行で連結できます。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

