索引地址:系列索引
像素归一化
像素值归一化就是要把图片像素值数据经过某种算法限制在需要的一定范围内。归一化可以使没有可比性的数据变得具有可比性,同时保持相比较的数据之间的相对关系。OpenCV提供了四种图片像素归一化的方法:
- L1归一化 : NORM_L1
- L2归一化 : NORM_L2
- INF归一化 : NORM_INF
- MINMAX归一化 : NORM_MINMAX(最常用)
使用的函数是normalize(),函数说明为:
1 2 3 4 5 6 7 8
| void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray() );
|
下面以20,80,100三个像素值为例解释OpenCV中四种归一化的计算方法,由于归一化后为小数,因此将20,80,100转换成浮点型20.0,80.0,100.0以减小精度丢失。
L1归一化:NORM_L1
L1归一化依据所有像素值之和,用原始像素值除以所有像素值之和即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的和为20.0+80.0+100.0=200.0
则
20.0/200.0=0.120.0/200.0=0.1
80.0/200.0=0.480.0/200.0=0.4
100.0/200.0=0.5
所以20.0,80.0,100.0经过L1归一化后的值分别为0.1,0.4,0.5。
L2归一化:NORM_L2
L2归一化依据于原始像素值组成的单位向量,用原始像素值除以所有原始像素值平方值之和的平方根即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的平方和为:20.0∗20.0+80.0∗80.0+100.0∗100.0=16800.0,开平方得129.61。
则
20.0/129.61=0.15420.0/129.61=0.154
80.0/129.61=0.61780.0/129.61=0.617
100.0/129.61=0.772
所以20.0,80.0,100.0经过L2归一化后的值分别为0.154,0.617,0.772。
INF归一化:NORM_INF
INF归一化依据于最大值,用原始像素值除以所有原始像素值中的最大值即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的最大值为100.0。
则
20.0/100.0=0.2
80.0/100.0=0.880.0/100.0=0.8
100.0/100.0=1.0
所以20.0,80.0,100.0经过INF归一化后的值分别为0.2,0.8,1.0。
MINMAX归一化:NORM_MINMAX
INF归一化依据于最大值与最小值的差值(记为delta),用原始像素值除以所有原始像素值中的最大值即为原始像素值归一化后的值。
例如对于20.0,80.0,100.0三个像素值,它们的最小值min为20.0,最大值maxmax为100.0,则delta=max−min=100.0−20.0=80.0
所以
(20.0−min)/delta=(20.0−20.0)/80.0=0.0
(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−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。
测试代码1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include<opencv2/opencv.hpp> #include<iostream> #include<Windows.h>
using namespace cv; using namespace std;
int main(int argc, char**argv) { 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;
return 0; }
|
输出结果为:
1 2 3 4 5 6 7 8 9
| $ ./normalize L1 normal: 0.1 0.4 0.5 L2 normal: 0.154303 0.617213 0.771517 INF normal: 0.2 0.8 1 MINMAX normal: 1.38778e-17 0.75 1
|
测试2
我们处理一下图片,可以看出归一化的对象要求每个像素只能有一个值,那么最好的就是灰度图或者黑白二值图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<opencv2/opencv.hpp> #include<iostream>
using namespace cv; using namespace std;
int main(int argc, char**argv) { Mat gray_input_image = imread("1.jpg", 0); if (gray_input_image.empty()){ cout << "read input error!" << endl; return -1; } imshow("gary_input", gray_input_image);
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);
return 0; }
|
处理结果:
说明
上面显示的就是我们使用OpenCV的正常流程,读取-处理-结果,如果需要调试,可以在中间加上显示来确保或者查看中间处理结果。