引言
图像是由像素组成的。黑白图像是单个像素矩阵,而彩色图像中每个颜色通道都有单独的像素矩阵,比如:红色,绿色,蓝色等颜色通道。
像素值为0~255范围内的整数。虽然可以直接将原图像的像素数据直接作为神经网络模型的训练数据,但可能给模型的训练过程带来一些问题,例如导致模型训练速度变慢。
而在模型训练前对图像的像素值做预处理,能避免很多不必要的麻烦,例如将像素值缩放到0-1之间。
归一化是一种数理统计中常用的数据预处理手段,在机器学习中归一化通常将数据向量每个维度的数据映射到(0,1)或(-1,1)之间的区间或者将数据向量的某个范数映射为1,归一化好处有两个:
- 消除数据单位的影响:其一可以将有单位的数据转为无单位的标准数据,如成年人的身高150-200cm、成年人体重50-90Kg,身高的单位是厘米而体重的单位是千克,不同维度的数据单位不一样,造成原始数据不能直接代入机器学习中进行处理,所以这些数据经过特定方法统一都映射到(0,1)这个区间,这样所有数据的取值范围都在同一个区间里的。
- 可提深度学习模型收敛速度: 如果不进行归一化处理,假设深度学习模型接受的输入向量只有两个维度x1和x2,其中X1取值为0-2000,x2取值为0-3。这样数据在进行梯度下降计算时梯度时对应一个很扁的椭圆形,很容易在垂直等高线的方向上走大量的之字形路线,是的迭代计算量大且迭代的次数多,造成深度学习模型收敛慢。
归一化的作用与定义
归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。
首先归一化是为了后面数据处理的方便,其次是保证程序运行时收敛加快。归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布。归一化有同一、统一和合一的意思。
归一化的目的,是使得没有可比性的数据变得具有可比性,同时又保持相比较的两个数据之间的相对关系,如大小关系;或是为了作图,原来很难在一张图上作出来,归一化后就可以很方便的给出图上的相对位置等。
像素归一化
首先,需要知道的是,对于大多数图像数据,像素值是介于0和255之间的整数。
在深度神经网络训练时一般使用较小的权重值来进行拟合,而当训练数据的值是较大整数值时,可能会减慢模型训练的过程。因此,一般需要图像的像素进行归一化,使得图像的每个像素值都在0-1之间。当图像的像素处于0-1范围时,由于任然介于0~255之间,所以图像依旧是有效的,并且可以正常查看图像。
像素的归一化可以通过将所有像素值除以最大像素值来实现,最大像素值一般为255。需要注意的是,不管图片是单通道的黑白图片还是多通道的彩色图片,都可以使用这种方法;不管图片的最大像素值是否有255,都除以255。
像素的归一化可以总结如下,这也是机器学习中一般的归一化方法,只不过像素归一化中X_min为0,忽略了这一项。
OpenCV中提供的归一化方法
- NORM_MINMAX------最常用
- NORM_INF
- NORM_L1
- NORM_L2
NORM_L1归一化
-
归一化数组的L1-范数(绝对值的和)
-
L1范数(L1 norm)是指向量中各个元素绝对值之和,也有个美称叫“稀疏规则算子”(Lasso regularization)。
比如 向量 , 那么A的L1范数为|1|+|-1|+|3|=5
-
依据:和为1
2.0+8.0+10.0=20 2.0 0.1 8.0 0.4 10.0 0.5
L2 归一化
-
归一化数组的(欧几里德)L2-范数
-
依据:单位向量为1,也即是每个数除以根号下所有数的平方和)
-
优势:
经过L2范数归一化后,一组向量的欧式距离和它们的余弦相似度可以等价。2.0 0.15 8.0 0. 62 10.0 0.77
NORM_INF 归一化
-
归一化数组的C-范数(绝对值的最大值)
-
依据是:最大值
2.0 0.2 8.0 0. 8 10.0 1.0
NORM_MINMAX 归一化
-
数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
-
依据是:delta=max-min,也即最小值为0,最大值为1。
2.0 0.0 8.0 0. 75 10.0 1.0
OpenCV提供的归一化函数
void normalize(InputArray src, InputOutputArray dst,
double alpha = 1, double beta = 0,
int norm_type = NORM_L2, int dtype = -1,
InputArray mask = noArray());
src:输入待处理数组
dst:与src大小相同的输出数组
alpha:可以用来规范值,也可以用来规范范围,并且是范围的下限。
beta:用来规范范围,并且是范围的上线。
norm_type:规范化类型
dtype:dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype)。
mask:操作掩膜,选择感兴趣区域,选定后只能对该区域进行操作。用于指示函数是否仅仅对指定的元素进行操作。
归一化公式
-
线性函数转换:norm_type=NORM_MINMAX
if mask(i,j)!=0
dst(i,j)= ( s r c ( i , j ) − m i n ( s r c ) ) ∗ ( b ′ − a ′ ) m a x ( s r c ) − m i n ( s r c ) \frac{(src(i,j)-min(src))*(b'-a')}{max(src)-min(src)} max(src)−min(src)(src(i,j)−min(src))∗(b′−a′)+a’
else
dst(i,j)=src(i,j)其中b’=MAX(alpha,beta),a’=MIN(alpha,beta);
-
当norm_type!=NORM_MINMAX:
if mask(i,j)!=0
dst(i,j)= s r c ( i , j ) ∗ a l p h a n o r m ( s r c , n o r m _ t y p e , m a s k ) \frac{src(i,j)*alpha}{norm(src,norm\_type,mask)} norm(src,norm_type,mask)src(i,j)∗alpha;
else
dst(i,j)=src(i,j);
其中norm的功能是:计算norm(范数)的绝对值
即有:
- NORM_INF:
dst(i,j)= s r c ( i , j ) M a x ∣ s r c ( x , y ) ∣ \frac{src(i,j)}{Max|src(x,y)|} Max∣src(x,y)∣src(i,j) - NORM_L1:
dst(i,j)= s r c ( i , j ) ∣ ∑ s r c ( x , y ) ∣ \frac{src(i,j)}{|\sum{src(x,y)|}} ∣∑src(x,y)∣src(i,j) - NORM_L2:
dst(i,j)= s r c ( i , j ) ∑ ( s r c ( x , y ) 2 ) \frac{src(i,j)}{\sqrt{\sum{(src(x,y)^2)}}} ∑(src(x,y)2)src(i,j)
// 读取一张灰度图像
Mat src = imread("D:/test/src1.jpg", IMREAD_GRAYSCALE);
if (src.empty()) {
cout << "could not load image.." << endl;
return -1;
}
imshow("src", src);
Mat gray_f;
// 转换为浮点数类型数组
src.convertTo(gray_f, CV_32F);
cout << "gray_f" << gray_f << endl;
// NORM_MINMAX 归一化,根据delta = max - min = 8.0
// 归一化到[alpha, beta],即[1.0, 0]
// 2.0 0.0 ((2.0 - 2.0)/8.0)
// 8.0 0.75 ((8.0 - 2.0)/8.0)
// 10.0 1.0 ((10.0 - 2.0)/8.0)
Mat dst = Mat::zeros(gray_f.size(), CV_32FC1);
normalize(gray_f, dst, 1.0, 0, NORM_MINMAX);
Mat result = dst * 255;
result.convertTo(dst, CV_8UC1);
imshow("NORM_MINMAX", dst);
// NORM_INF 归一化,根据最大值
// 2.0 0.2 (2.0/10.0)
// 8.0 0.8 (8.0/10.0)
// 10.0 1.0 (10.0/10.0)
normalize(gray_f, dst, 1.0, 0, NORM_INF);
result = dst * 255;
result.convertTo(dst, CV_8UC1);
imshow("NORM_INF", dst);
// NORM_L1 归一化,依据和为1
// sum(numbers) = 20.0
// 2.0 0.1 (2.0/20.0)
// 8.0 0.4 (8.0/20.0)
// 10.0 0.5 (10.0/20.0)
normalize(gray_f, dst, 1.0, 0, NORM_L1);
result = dst * 10000000;
result.convertTo(dst, CV_8UC1);
imshow("NORM_L1", dst);
// NORM_L2 归一化,根据单位向量为1
// ||positiveData|| = sqrt(2.0*2.0 + 8.0*8.0 + 10.0*10.0) = 12.96
// 2.0 0.15 (2.0/12.96)
// 8.0 0.62 (8.0/12.96)
// 10.0 0.77 (10.0/12.96)
normalize(gray_f, dst, 1.0, 0, NORM_L2);
result = dst * 10000;
result.convertTo(dst, CV_8UC1);
imshow("NORM_L2", dst);
学习:
opencv中归一化函数normalize()的原理讲解
OpenCV-Day-011:像素归一化
OpenCV4.0入门(11)像素归一化