cv::addweighted不能直接实现半透明遮罩,因其仅支持全图逐像素线性混合、无掩膜机制;正确做法是结合roi、单通道掩膜与addweighted,在指定区域叠加并用mask控制写入范围。

cv::addWeighted 为什么不能直接实现半透明遮罩
直接用 cv::addWeighted 叠加纯色图到原图,看似能调透明度(alpha 参数),但实际只支持“两图逐像素线性混合”,无法对特定区域(比如矩形、多边形)做局部半透明覆盖。它没有掩膜(mask)概念,整张图参与计算,遮罩区域外也会被污染。
- 错误做法:
cv::addWeighted(src, 1.0, overlay, alpha, 0, dst)——overlay若是全图大小的纯色图,会把整张图都染上底色 - 真正需要的是:只在感兴趣区域(ROI)叠加带 alpha 的颜色,其余像素保持不变
- OpenCV 默认 Mat 不支持每像素 4 通道(RGBA)的 alpha 混合渲染,需手动实现 blend 操作
正确做法:用 ROI + cv::addWeighted 配合掩膜
核心思路是先提取目标区域(ROI),再对 ROI 内部做“带掩膜的加权叠加”。关键不是靠 Mat 自带 alpha 通道,而是用二值掩膜控制哪些像素参与混合。
- 准备一个和 ROI 等大的单通道
mask(CV_8UC1),遮罩区域填 255,其余填 0 - 构造一个同尺寸的三通道
overlay(如cv::Scalar(0,0,255)表示红色) - 用
cv::addWeighted对 ROI 和 overlay 做混合:cv::addWeighted(roi, 1-alpha, overlay, alpha, 0, roi) - 再用
cv::bitwise_and+cv::bitwise_not把 mask 外的原始 ROI 值保留回来(否则混合会覆盖整个 ROI 区域)
更稳妥的做法是:先复制 ROI 到临时 Mat,混合后用 mask 把结果“贴回”原图:
cv::Mat roi = src(cv::Rect(x, y, w, h)); cv::Mat roi_copy = roi.clone(); cv::Mat overlay = cv::Mat::zeros(roi.size(), CV_8UC3) + cv::Scalar(0, 0, 255); // 红色遮罩 cv::Mat mask = cv::Mat::ones(roi.size(), CV_8UC1) * 255; // 全白掩膜,可替换为自定义形状 <p>cv::addWeighted(roi, 1 - alpha, overlay, alpha, 0, roi_copy); roi.copyTo(roi, mask); // 仅在 mask=255 处写入 roi_copy.copyTo(roi, mask);</p>
绘制任意形状遮罩(如圆形、多边形)时怎么生成 mask
OpenCV 的绘图函数(cv::circle、cv::fillPoly)默认画在三通道图上,但 mask 必须是单通道。直接往 CV_8UC1 图上画即可,注意初始化为全黑(0),再用 cv::FILLED 填充目标区域。
- 画圆形遮罩:
cv::circle(mask, center, radius, 255, cv::FILLED) - 画多边形遮罩:
cv::fillPoly(mask, std::vector<:vector>>{points}, 255)</:vector> - mask 类型必须是
CV_8UC1,且尺寸与目标 ROI 严格一致,否则copyTo会报错OpenCV(4.x): error: (-215:Assertion failed) ... size == m.size() - 如果 ROI 是从原图切出来的子矩阵(
src(cv::Rect(...))),mask 也必须是同样cv::Size(w, h)
alpha 值设多少才看起来“半透明”且不发灰
alpha 是混合权重,不是 Photoshop 里的透明度百分比。设 0.3–0.5 通常比较自然;但要注意:过低(0.7)会严重压制原图细节,尤其在纹理丰富区域容易显得“脏”或“发灰”。
- 推荐起始值:
alpha = 0.4,然后根据图像明暗动态调整 - 深色背景上,相同 alpha 下遮罩更显眼,可适当降低(如 0.3)
- 浅色区域叠加深色遮罩(如红框)时,alpha > 0.5 容易导致边缘生硬,建议配合
cv::GaussianBlur轻微模糊 mask 边缘 - 不要试图用 float 型 alpha 去“精细调节”,视觉差异在 0.05 内基本不可辨,优先保证 mask 形状和 ROI 对齐
最常被忽略的一点:所有操作必须确保 ROI、overlay、mask 三者尺寸完全一致,且 ROI 是原图的引用(非深拷贝),否则修改不会反映到原图上。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











