OpenCV 图像像素类型转换与归一化

一、知识点
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 
#include 


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, 所有像素所有通道的值求和为1
    cv::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_MINMAX
    cv::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_INF
    cv::Mat dst8;
    cv::normalize(src2, dst8, 1.0, 0.0, cv::NORM_INF);
    cv::imshow("NORM_INF", dst8);

    //NORM_MINMAX
    cv::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]

你可能感兴趣的:(OpenCV,opencv,人工智能,计算机视觉,图像处理)