cv::add / addWeighted の使い方【OpenCV/C++】〜画像の加算・ブレンド合成〜
cv::add は2枚の画像をピクセル単位で加算し、cv::addWeighted は重みを指定してブレンド合成する関数です。フェード・透かし・オーバーレイなど、現場でよく使う合成処理を飽和演算(クランプ)付きで安全に行えます。
最小の使い方はこうです。
cv::add(src1, src2, dst);
cv::addWeighted(src1, alpha, src2, beta, gamma, dst);
動作環境
- OpenCV 4.x
- C++17
- ビルド例:
g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4) -o main
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
cv::add — 単純加算
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat src1 = cv::imread("image1.png");
cv::Mat src2 = cv::imread("image2.png");
if (src1.empty() || src2.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return 1;
}
// サイズ・型を統一する(異なる場合は assertion で落ちる)
cv::resize(src2, src2, src1.size());
cv::Mat dst;
// ピクセル値を加算。255 を超えた部分は 255 にクランプされる
cv::add(src1, src2, dst);
cv::imwrite("add_result.png", dst);
std::cout << "add_result.png を保存しました" << std::endl;
return 0;
}
実行結果
add_result.png を保存しました
2枚の画像が重ね合わされた画像が保存されます。明るい領域が増え、白飛びしやすい(飽和演算)のが cv::add の特徴です。
cv::addWeighted — 重み付きブレンド合成
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat src1 = cv::imread("image1.png");
cv::Mat src2 = cv::imread("image2.png");
if (src1.empty() || src2.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return 1;
}
cv::resize(src2, src2, src1.size());
cv::Mat dst;
double alpha = 0.7; // src1 の重み
double beta = 0.3; // src2 の重み(alpha + beta = 1.0 が自然なブレンド)
double gamma = 0.0; // 加算するオフセット値
// dst = src1 * alpha + src2 * beta + gamma
cv::addWeighted(src1, alpha, src2, beta, gamma, dst);
cv::imwrite("blend_result.png", dst);
std::cout << "blend_result.png を保存しました" << std::endl;
return 0;
}
実行結果
blend_result.png を保存しました
alpha=0.7, beta=0.3 の場合、src1 が 70%・src2 が 30% の割合でブレンドされた画像が保存されます。alpha + beta = 1.0 にすると全体の輝度が変化しないため、自然な合成になります。
引数と戻り値
cv::add
| 引数 | 型 | 説明 |
|---|---|---|
src1 |
InputArray |
入力画像1 |
src2 |
InputArray |
入力画像2(スカラー値も可) |
dst |
OutputArray |
出力画像 |
mask |
InputArray |
処理対象のマスク(省略可、デフォルト noArray()) |
dtype |
int |
出力の深度(省略可、デフォルト -1 で入力と同じ) |
戻り値: なし(void)
cv::addWeighted
| 引数 | 型 | 説明 |
|---|---|---|
src1 |
InputArray |
入力画像1 |
alpha |
double |
src1 に掛ける重み |
src2 |
InputArray |
入力画像2 |
beta |
double |
src2 に掛ける重み |
gamma |
double |
結果に加算するオフセット値 |
dst |
OutputArray |
出力画像 |
dtype |
int |
出力の深度(省略可、デフォルト -1) |
戻り値: なし(void)
演算式: dst = src1 * alpha + src2 * beta + gamma
実践例
透かし(ウォーターマーク)の合成
ロゴ画像を薄く重ねてウォーターマークを合成する典型的なパターンです。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat base = cv::imread("photo.png");
cv::Mat logo = cv::imread("logo.png");
if (base.empty() || logo.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return 1;
}
// ロゴを右下に配置するための ROI を設定
int x = base.cols - logo.cols - 20;
int y = base.rows - logo.rows - 20;
if (x < 0 || y < 0) {
std::cerr << "ロゴが大きすぎます" << std::endl;
return 1;
}
cv::Mat roi = base(cv::Rect(x, y, logo.cols, logo.rows));
// ROI 領域にのみブレンド(ロゴを 30% の透明度で合成)
cv::addWeighted(roi, 1.0, logo, 0.3, 0.0, roi);
cv::imwrite("watermark_result.png", base);
std::cout << "watermark_result.png を保存しました" << std::endl;
return 0;
}
cv::Mat roi = base(cv::Rect(...)) は base との共有メモリなので、roi への書き込みがそのまま base に反映されます。ROI を使うことで、ループなしに特定領域だけ合成できます。
gamma によるコントラスト・輝度補正
cv::addWeighted の gamma は「自分自身にブレンド + オフセット」の形で輝度調整にも応用できます。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat src = cv::imread("photo.png");
if (src.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return 1;
}
cv::Mat dst;
// alpha=1.2 でコントラスト強調、gamma=-30 で全体を暗くオフセット
cv::addWeighted(src, 1.2, src, 0.0, -30.0, dst);
cv::imwrite("contrast_result.png", dst);
std::cout << "contrast_result.png を保存しました" << std::endl;
return 0;
}
src2 に同じ画像を渡し beta=0.0 にすると、実質 dst = src * alpha + gamma の線形変換になります。輝度・コントラストの粗調整に手軽に使えます。
つまずきポイント
⚠️ サイズ・型が一致しないと assertion で落ちる
cv::add / cv::addWeighted は src1 と src2 のサイズ・チャンネル数・深度が一致していないと実行時に assertion エラーになります。
OpenCV Error: Sizes of input arguments do not match
cv::resize でサイズを合わせ、チャンネル数は cv::cvtColor で揃えてから渡してください。グレースケール(CV_8UC1)とカラー(CV_8UC3)の混在は特に起きやすいミスです。
⚠️ alpha + beta の合計が 1.0 を超えると白飛びする
cv::addWeighted は内部で飽和演算を行うため、alpha + beta > 1.0 だと明るい領域が白飛びします。「自然なブレンド合成」を意図する場合は alpha + beta = 1.0 を守ってください。あえてハイキー表現にしたい場合を除き、まず合計を 1.0 に設定するところから始めるのが無難です。
⚠️ float 型(CV_32F)の画像に使う場合のクランプ挙動
入力が CV_32F の場合、飽和クランプは行われず 0〜255 の範囲を超えた値がそのままフロート値として格納されます。imwrite 前に convertTo で CV_8U に変換するか、出力を normalize してから保存してください。
関連する関数
- cv::subtract — 画像の減算(差分検出などに使用)
- cv::multiply — ピクセル単位の乗算(マスク合成や輝度スケーリング)
- cv::bitwise_and / or / xor — ビット演算による合成
- cv::calcHist の使い方【OpenCV/C++】〜ヒストグラムを計算する〜 — 合成後の輝度分布確認に組み合わせて使うと便利
- cv::matchTemplate の使い方【OpenCV/C++】〜テンプレートマッチングで物体位置を検出する〜 — 合成位置の検出に活用できる
まとめ
cv::addはピクセル値の飽和加算、cv::addWeightedは重み付きブレンド合成に使う。alpha + beta = 1.0にすることで自然な透過合成が実現できる。- サイズ・チャンネル数・深度の不一致は実行時エラーになるため、
resizeとcvtColorで前処理を統一することが重要。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

