OpenCV图像数据处理:convertTo,normalize和scaleAdd

发布于:2025-07-14 ⋅ 阅读:(18) ⋅ 点赞:(0)

在 OpenCV 图像处理的世界里,有几个函数进行一些基本数据变换:

  • cv::convertTo():类型转换与线性缩放;

  • cv::normalize():归一化处理;

  • cv::scaleAdd():加权叠加运算。

  • cv::addWeighted(): 与scaleAdd相似,进行加权叠加运算;

一、cv::convertTo():线性变换 + 数据类型转换

void cv::Mat::convertTo(OutputArray dst, int rtype, double alpha = 1, double beta = 0) const;

其操作逻辑为:

dst(x, y) = saturate_cast<rtype>( src(x, y) * alpha + beta )

主要功能包括:

  • 类型转换,如CV_8U->CV_32F
  • 缩放变换,如alpha=1/255时实现归一化
  • 图像增强,如alpha > 1, beta ≠ 0 调整对比度与亮度 

二、cv::normalize():归一化到特定范围或分布

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_typeNORM_MINMAXalpha 表示 归一化后的最小值

  • 如果是其他范数(如 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():线性叠加的高效实现

void cv::scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst);

其操作逻辑为:

dst = src1 * alpha + src2;

用法场景:

  • 梯度融合;

  • 图像加权融合(曝光合成);

  • 向量叠加(例如 PCA 主成分叠加)。

四、完整实战示例:图像增强 + 归一化 + 加权融合

我们将演示如下流程:

  1. 读取一张图像并转换为浮点格式;

  2. 使用 convertTo 将其归一化到 [0,1];

  3. 使用 scaleAdd 将原图与边缘图像加权融合,输出增强图像。

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;
}

 

 


网站公告

今日签到

点亮在社区的每一天
去签到