一、知识点
1、OpenCV支持多种数据类型,每种类型都对应着不同的取值范围。
(1)、CV_8U取值范围[0, 255]。
(2)、CV_16U取值范围[0, 65535]。
(3)、CV_32F取值范围[0, 1]。
2、OpenCV提供convertTo()函数来转换数据类型,提供normalize()函数来改变取值范围。
3、void Mat::convertTo(OutputArray dst, int rtype, double alpha, double beta) const
(1)、Mat成员函数,将Mat对象转换到另一种数据类型。
(2)、参数说明:
dst: 输出数组。
rtype: 输出数组的期望类型,如CV_8UC1、CV_8UC3、CV_32FC3等。
alpha: 缩放因子,默认值为1,用于乘以输入矩阵的每个元素。
beta: 偏移量,默认值为0,用于将缩放后的值加上偏移量。
4、void normalize( InputArray src,
InputOutputArray dst,
double alpha = 1,
double beta = 0,
int norm_type = NORM_L2,
int dtype = -1,
InputArray mask = noArray());
(1)、将数组归一化到指定的取值范围。
(2)、参数说明:
src: 输入数组。
dst: 输出数组,其类型和输入数组相同。
alpha: 归一化后的最小值或缩放系数,具体取决于norm_type。 若为NORM_MINMAX则表示归一化后的最小值; 若为NORM_INF、NORM_L1、NORM_L2则表示缩放系数。
beta: 归一化后的最大值,仅当norm_type为NORM_MINMAX时有效。
norm_type: 归一化的方式,cv::NormTypes枚举值,详见5。
dtype: 为负数时,dst的类型和src相同; 否则,dst的通道数和src相同,但深度为dtype。
mask: 可选掩码,若不为空,则在指定数组中(非零掩码对应)归一化; 若为空,则在整个数组归一化。
(3)、注意,norm_type为NORM_MINMAX时,虽然alpha表示最小值,beta表示最大值,但是两值调换也不影响。
5、enum NormTypes {
NORM_INF = 1,
NORM_L1 = 2,
NORM_L2 = 4,
NORM_L2SQR = 5,
NORM_HAMMING = 6,
NORM_HAMMING2 = 7,
NORM_TYPE_MASK = 7,
NORM_RELATIVE = 8,
NORM_MINMAX = 32
};
(1)、常用NORM_INF、NORM_L1、NORM_L2、NORM_MINMAX这四种归一化方式。
(2)、NORM_L1,所有像素所有通道的值和为1。
cv::normalize(src, dst, 1.0, 0.0, cv::NORM_L1);
sum = 2 + 8 + 10 = 20
2 ---> 0.1 (2.0 / 20.0)
8 ---> 0.4 (8.0 / 20.0)
10 ---> 0.5 (10.0 / 20.0)
(3)、NORM_L2,所有像素所有通道的值求单位向量。 (默认)
cv::normalize(src, dst, 1.0, 0.0, cv::NORM_L2);
|v| = 开根号(2 * 2 + 8 * 8 + 10 * 10) = 开根号(168) = 12.96
2 ---> 0.15 (2.0 / 12.96)
8 ---> 0.62 (8.0 / 12.96)
10 ---> 0.77 (10.0 / 12.96)
(4)、NORM_INF,每个值除以所有像素所有通道的最大值。
cv::normalize(src, dst, 1.0, 0.0, cv::NORM_INF);
Max = 10
2 ---> 0.2 (2.0 / 10.0)
8 ---> 0.8 (8.0 / 10.0)
10 ---> 1.0 (10.0 / 10.0)
(5)、NORM_MINMAX (常用)
cv::normalize(src, dst, 0.0, 1.0, cv::NORM_MINMAX);
alpha = 0.0, beta = 1.0, 归一化范围[0.0, 1.0],简记为[a, b]
找到样本数据最小值Min = 2, 最大值Max = 10
计算系数k = (b - a) / (Max - Min) = 1.0 / 8.0 = 0.125
归一化值 = a + k * (当前值 - Min)
2 ---> 0.0 (0.0 + 0.125 * (2 - 2))
8 ---> 0.75 (0.0 + 0.125 * (8 - 2))
10 ---> 1.0 (0.0 + 0.125 * (10 - 2))
6、注意:
(1)、将CV_8UC3转换为CV_32FC3,8U取值范围[0, 255],32F取值范围[0.0, 1.0],如果不归一化,imshow会显示几乎全白图像。
(2)、将CV_8UC3图像不转换类型,直接归一化,imshow会显示全黑图片。
二、示例代码
#include <iostream>
#include <opencv2/opencv.hpp>int main()
{//自定义src1,CV_8UC3类型的src1转为CV_32FC3类型的dst1,类型值改变但是元素值不变cv::Mat src1 = cv::Mat::zeros(3, 3, CV_8UC3);src1 = cv::Scalar(45, 60, 80);std::cout << "src1 type = " << src1.type() << std::endl << src1 << std::endl;cv::Mat dst1;src1.convertTo(dst1, CV_32FC3, 1.0, 0.0);std::cout << "dst1 type = " << dst1.type() << std::endl << dst1 << std::endl;//NORM_L1, 所有像素所有通道的值求和为1cv::Mat dst2;cv::normalize(dst1, dst2, 1.0, 0.0, cv::NORM_L1);std::cout << "dst2 type = " << dst2.type() << std::endl << dst2 << std::endl;//NORM_L2, 所有像素所有通道的值求单位向量cv::Mat dst3;cv::normalize(dst1, dst3, 1.0, 0.0, cv::NORM_L2);std::cout << "dst3 type = " << dst3.type() << std::endl << dst3 << std::endl;//NORM_INF, 每个值除以所有像素所有通道的最大值cv::Mat dst4;cv::normalize(dst1, dst4, 1.0, 0.0, cv::NORM_INF);std::cout << "dst4 type = " << dst4.type() << std::endl << dst4 << std::endl;//NORM_MINMAXcv::Mat dst5;cv::normalize(dst1, dst5, 0.0, 1.0, cv::NORM_MINMAX);std::cout << "dst5 type = " << dst5.type() << std::endl << dst5 << std::endl;//src2是读取的图像cv::Mat src2 = cv::imread("../images/6.png");if (src2.empty()){std::cout << "load src2 image error..." << std::endl;return -1;}cv::imshow("原始图像", src2);//CV_8UC3转为32FC3,值没有变化,但是显示会非常白的图片src2.convertTo(src2, CV_32FC3);cv::imshow("类型转换", src2);//NORM_L1,结果值太小,图像显示黑色cv::Mat dst6;cv::normalize(src2, dst6, 1.0, 0.0, cv::NORM_L1);cv::imshow("NORM_L1", dst6);//NORM_L2,结果值太小,放大100倍,图像能显示出来cv::Mat dst7;cv::normalize(src2, dst7, 100.0, 0.0, cv::NORM_L2);cv::imshow("NORM_L2", dst7);//NORM_INFcv::Mat dst8;cv::normalize(src2, dst8, 1.0, 0.0, cv::NORM_INF);cv::imshow("NORM_INF", dst8);//NORM_MINMAXcv::Mat dst9;cv::normalize(src2, dst9, 1.0, 0.0, cv::NORM_MINMAX);cv::imshow("NORM_MINMAX", dst9);//src3和src2读取一样的原始图片, 但如果不转换类型,直接归一化,会显示全黑的图片cv::Mat src3 = cv::imread("../images/6.png");if (src3.empty()){std::cout << "load src3 image error..." << std::endl;return -1;}cv::Mat dst10;cv::normalize(src3, dst10, 1.0, 0.0, cv::NORM_MINMAX);cv::imshow("直接归一化", dst10);cv::waitKey(0);return 0;
}
输出结果:
src1 type = 16
[ 45, 60, 80, 45, 60, 80, 45, 60, 80;45, 60, 80, 45, 60, 80, 45, 60, 80;45, 60, 80, 45, 60, 80, 45, 60, 80]
dst1 type = 21
[45, 60, 80, 45, 60, 80, 45, 60, 80;45, 60, 80, 45, 60, 80, 45, 60, 80;45, 60, 80, 45, 60, 80, 45, 60, 80]
dst2 type = 21
[0.027027028, 0.036036037, 0.048048049, 0.027027028, 0.036036037, 0.048048049, 0.027027028, 0.036036037, 0.048048049;0.027027028, 0.036036037, 0.048048049, 0.027027028, 0.036036037, 0.048048049, 0.027027028, 0.036036037, 0.048048049;0.027027028, 0.036036037, 0.048048049, 0.027027028, 0.036036037, 0.048048049, 0.027027028, 0.036036037, 0.048048049]
dst3 type = 21
[0.13678823, 0.1823843, 0.24317907, 0.13678823, 0.1823843, 0.24317907, 0.13678823, 0.1823843, 0.24317907;0.13678823, 0.1823843, 0.24317907, 0.13678823, 0.1823843, 0.24317907, 0.13678823, 0.1823843, 0.24317907;0.13678823, 0.1823843, 0.24317907, 0.13678823, 0.1823843, 0.24317907, 0.13678823, 0.1823843, 0.24317907]
dst4 type = 21
[0.5625, 0.75, 1, 0.5625, 0.75, 1, 0.5625, 0.75, 1;0.5625, 0.75, 1, 0.5625, 0.75, 1, 0.5625, 0.75, 1;0.5625, 0.75, 1, 0.5625, 0.75, 1, 0.5625, 0.75, 1]
dst5 type = 21
[2.4214387e-08, 0.42857146, 1, 2.4214387e-08, 0.42857146, 1, 2.4214387e-08, 0.42857146, 1;2.4214387e-08, 0.42857146, 1, 2.4214387e-08, 0.42857146, 1, 2.4214387e-08, 0.42857146, 1;2.4214387e-08, 0.42857146, 1, 2.4214387e-08, 0.42857146, 1, 2.4214387e-08, 0.42857146, 1]