在 OpenCV 图像处理的世界里,有几个函数进行一些基本数据变换:
-
cv::convertTo()
:类型转换与线性缩放; -
cv::normalize()
:归一化处理; -
cv::scaleAdd()
:加权叠加运算。 -
cv::addWeighted(): 与
scaleAdd相似,进行加权叠加运算;
一、cv::convertTo()
:线性变换 + 数据类型转换
cpp
void cv::Mat::convertTo(OutputArray dst, int rtype, double alpha = 1, double beta = 0) const;
其操作逻辑为:
cpp
dst(x, y) = saturate_cast<rtype>( src(x, y) * alpha + beta )
主要功能包括:
- 类型转换,如CV_8U->CV_32F
- 缩放变换,如alpha=1/255时实现归一化
- 图像增强,如
alpha > 1
,beta ≠ 0
调整对比度与亮度
二、cv::normalize()
:归一化到特定范围或分布
cpp
cv::normalize(InputArray src, OutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
src
:输入数组(cv::Mat
)
-
要被归一化的数据,可以是图像,也可以是向量或矩阵。
-
可以是任意深度(CV_8U、CV_32F、CV_64F等),任意通道数(灰度、彩色等)。
dst
:输出数组(cv::Mat
)
- 存储归一化后的结果,类型由
dtype
决定(默认与src
一致)。
alpha
:归一化下限或范数值(具体含义取决于 norm_type
)
-
如果
norm_type
是NORM_MINMAX
,alpha
表示 归一化后的最小值。 -
如果是其他范数(如
NORM_L1
,NORM_L2
),alpha
是规范化后的 目标范数。
beta
:归一化上限(仅在 NORM_MINMAX
有意义)
-
只有当
norm_type = NORM_MINMAX
时,beta
表示 归一化后的最大值。 -
对于其他归一化类型,
beta
会被忽略。
norm_type
:归一化类型(cv::NormTypes
枚举)
cv::NORM_MINMAX,
将数组线性映射到[alpha, beta]
区间,常用于图像对比度增强。cv::NORM_L1,
将向量归一化为 L1 范数(绝对值和)为alpha
。cv::NORM_L2
(默认),将向量归一化为 L2 范数(欧几里得范数)为alpha
。cv::NORM_INF,
将向量归一化为最大绝对值为alpha。
dtype
:输出数据类型(默认 -1
表示与 src
一致)
-
可以指定输出图像的数据类型,如
CV_8U
,CV_32F
等。 -
如果
dtype = -1
,表示dst
类型与src
保持一致。
mask
:掩膜(可选)
-
用于选择对哪些像素进行归一化,非零位置参与归一化计算。
-
对于不需要掩膜的常见情况,使用默认值
cv::noArray()
。
函数应用场景:
- 使用
NORM_MINMAX,
将图像所有像素值映射到[0,1]区间 - 使用
NORM_L2,将图像看作向量,使得所有元素构成向量的模长为alpha
三、cv::scaleAdd()
:线性叠加的高效实现
cpp
void cv::scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst);
其操作逻辑为:
cpp
dst = src1 * alpha + src2;
用法场景:
-
梯度融合;
-
图像加权融合(曝光合成);
-
向量叠加(例如 PCA 主成分叠加)。
四、完整实战示例:图像增强 + 归一化 + 加权融合
我们将演示如下流程:
-
读取一张图像并转换为浮点格式;
-
使用
convertTo
将其归一化到 [0,1]; -
使用
scaleAdd
将原图与边缘图像加权融合,输出增强图像。
cpp
int main() {
cv::Mat img = cv::imread("lena.png", cv::IMREAD_GRAYSCALE);
if (img.empty()) {
std::cerr << "Cannot read image!" << std::endl;
return -1;
}
// 1. 使用 convertTo 将图像转换为 float 并归一化
cv::Mat img_f;
img.convertTo(img_f, CV_32F, 1.0 / 255.0);
// 2. 使用 Sobel 提取边缘
cv::Mat grad_x, grad_y, grad;
cv::Sobel(img_f, grad_x, CV_32F, 1, 0, 3);
cv::Sobel(img_f, grad_y, CV_32F, 0, 1, 3);
cv::magnitude(grad_x, grad_y, grad);
// 3. 对梯度图 normalize 到 [0,1]
cv::Mat grad_norm;
cv::normalize(grad, grad_norm, 0.0, 1.0, cv::NORM_MINMAX);
// 4. 使用 scaleAdd 融合边缘与原图
cv::Mat enhanced;
cv::scaleAdd(grad_norm, 0.5, img_f, enhanced); // enhanced = grad_norm * 0.5 + img_f
// 5. 将增强图转换回 uchar 显示
cv::Mat enhanced_8u;
enhanced.convertTo(enhanced_8u, CV_8U, 255.0);
// 显示结果
cv::imshow("Original", img);
cv::imshow("Enhanced", enhanced_8u);
cv::waitKey(0);
return 0;
}
