像素值归一化就是要把图片像素值数据经过某种算法限制在需要的一定范围内。归一化可以使没有可比性的数据变得具有可比性,同时保持相比较的数据之间的相对关系。OpenCV提供了四种图片像素归一化的方法:
- L1归一化 : NORM_L1
- L2归一化 : NORM_L2
- INF归一化 : NORM_INF
- MINMAX归一化 : NORM_MINMAX(最常用)
使用的API是normalize():
void normalize( InputArray src, //输入图片
InputOutputArray dst, //输出图片
double alpha = 1, //norm_type = NORM_MINMAX时下限
double beta = 0,//norm_type = NORM_MINMAX时上限,norm_type = NORM_INF时最大值
int norm_type = NORM_L2,
int dtype = -1, //输出type与输入type相同
InputArray mask = noArray()
);
下面以20,80,100三个像素值为例解释OpenCV中四种归一化的计算方法,由于归一化后为小数,因此将20,80,100转换成浮点型20.0,80.0,100.0以减小精度丢失。
L1归一化依据所有像素值之和,用原始像素值除以所有像素值之和即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的和为
20.0 + 80.0 + 100.0 = 200.0 20.0+80.0+100.0=200.0 20.0+80.0+100.0=200.0则
20.0 / 200.0 = 0.1 20.0/200.0 = 0.1 20.0/200.0=0.1
80.0 / 200.0 = 0.4 80.0/200.0 = 0.4 80.0/200.0=0.4
100.0 / 200.0 = 0.5 100.0/200.0 = 0.5 100.0/200.0=0.5
所以20.0,80.0,100.0经过L1归一化后的值分别为0.1,0.4,0.5。
L2归一化依据于原始像素值组成的单位向量,用原始像素值除以所有原始像素值平方值之和的平方根即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的平方和为:
20.0 ∗ 20.0 + 80.0 ∗ 80.0 + 100.0 ∗ 100.0 = 16800.0 20.0*20.0+80.0*80.0+100.0*100.0=16800.0 20.0∗20.0+80.0∗80.0+100.0∗100.0=16800.0
开平方得129.61。
则
20.0 / 129.61 = 0.154 20.0/129.61=0.154 20.0/129.61=0.154
80.0 / 129.61 = 0.617 80.0/129.61=0.617 80.0/129.61=0.617
100.0 / 129.61 = 0.772 100.0/129.61=0.772 100.0/129.61=0.772
所以20.0,80.0,100.0经过L2归一化后的值分别为0.154,0.617,0.772。
INF归一化依据于最大值,用原始像素值除以所有原始像素值中的最大值即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的最大值为100.0,则
20.0 / 100.0 = 0.2 20.0/100.0=0.2 20.0/100.0=0.2
80.0 / 100.0 = 0.8 80.0/100.0=0.8 80.0/100.0=0.8
100.0 / 100.0 = 1.0 100.0/100.0=1.0 100.0/100.0=1.0
所以20.0,80.0,100.0经过INF归一化后的值分别为0.2,0.8,1.0。
INF归一化依据于最大值与最小值的差值(记为delta),用原始像素值除以所有原始像素值中的最大值即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的最小值 m i n min min为20.0,最大值 m a x max max为100.0,则
d e l t a = m a x − m i n = 100.0 − 20.0 = 80.0 delta=max-min=100.0-20.0=80.0 delta=max−min=100.0−20.0=80.0
所以
( 20.0 − m i n ) / d e l t a = ( 20.0 − 20.0 ) / 80.0 = 0.0 (20.0-min)/delta=(20.0-20.0)/80.0=0.0 (20.0−min)/delta=(20.0−20.0)/80.0=0.0
( 80.0 − m i n ) / d e l t a = ( 80.0 − 20.0 ) / 80.0 = 0.75 (80.0-min)/delta=(80.0-20.0)/80.0=0.75 (80.0−min)/delta=(80.0−20.0)/80.0=0.75
( 100.0 − m i n ) / d e l t a = ( 100.0 − 20.0 ) / 80.0 = 1.0 (100.0-min)/delta=(100.0-20.0)/80.0=1.0 (100.0−min)/delta=(100.0−20.0)/80.0=1.0
所以20.0,80.0,100.0经过MINMAX归一化后的值分别为0.0,0.75,1.0。
代码实现:
vector<double>a = {20,80,100};
vector<double>a1(3);
vector<double>a2(3);
vector<double>a3(3);
vector<double>a4(3);
cv::normalize(a, a1, 1, 0, NORM_L1);
cv::normalize(a, a2, 1, 0, NORM_L2);
cv::normalize(a, a3, 1, 0, NORM_INF);
cv::normalize(a, a4, 1, 0, NORM_MINMAX);
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char**argv)
{
#if 0
//get gray input image
Mat gray_input_image = imread("./whisper.jpg", 0);
if (gray_input_image.empty())
{
cout << "read input error!" << endl;
return -1;
}
imshow("gary_input", gray_input_image);
//转为32位浮点型
gray_input_image.convertTo(gray_input_image, CV_32F);
Mat result = Mat::zeros(gray_input_image.size(), CV_32FC1);
normalize(gray_input_image, result, 1.0, 0.0, NORM_MINMAX);
result = result * 255;
result.convertTo(result, CV_8UC1);
imshow("result", result);
waitKey(0);
destroyAllWindows();
#endif
vector<double>a = {20,80,100};
vector<double>a1(3);
vector<double>a2(3);
vector<double>a3(3);
vector<double>a4(3);
cv::normalize(a, a1, 1, 0, NORM_L1);
cv::normalize(a, a2, 1, 0, NORM_L2);
cv::normalize(a, a3, 1, 0, NORM_INF);
cv::normalize(a, a4, 1, 0, NORM_MINMAX);
cout << "L1 normal:" << endl;
for (int i = 0; i < a.size(); i++){
cout << a1[i]<<" ";
}
cout << endl;
cout << "L2 normal:" << endl;
for (int i = 0; i < a.size(); i++){
cout << a2[i] << " ";
}
cout << endl;
cout << "INF normal:" << endl;
for (int i = 0; i < a.size(); i++){
cout << a3[i] << " ";
}
cout << endl;
cout << "MINMAX normal:" << endl;
for (int i = 0; i < a.size(); i++){
cout << a4[i] << " ";
}
cout << endl;
system("pause");
return 0;
}