• CV预处理方式


    CV对于图片预处理方式种类繁多, 如果使用不同的图片预处理方式经过模型推理后,得到的结果差距较大。如何能训练好CV模型,首先需要对齐CV模型训练、推理过程的预处理方式。

    一、CV预处理种类&接收图片格式

    预处理方式接收图片格式读取数据类型
    OpenCV通道颜色 - BGR;通道顺序 - HWCnumpy数组;uint8的整数类型,范围0 - 255
    Pillow(PIL)通道颜色 - RGB;通道顺序 - HWC特有的数据结构(可以转换成numpy)
    torchvision(Pytorch)
    matplotlib通道颜色 - RGB;通道顺序 - HWCnumpy数组;uint8的整数类型,范围0 - 255

    二、图片读取实现

    代码参考:opencv、matplotlib、pillow和pytorch读取数据的通道顺序

    1. import cv2
    2. import matplotlib.pyplot as plt
    3. from PIL import Image
    4. import numpy as np
    5. import torch
    6. from torchvision import transforms
    7. # opencv读取数据通道顺序,默认颜色通道BGR, 数据通道顺序HWC
    8. def opencv_channel(img_path):
    9. image = cv2.imread(img_path)
    10. print("cv2 type is ", type(image))
    11. print("cv2 shape is ", image.shape)
    12. cv2.imshow("image", image)
    13. # cv2.waitKey(0)
    14. #opencv将BGR颜色通道顺序 更改为 RGB颜色通道顺序
    15. # 1.
    16. cvColor_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    17. # 2.
    18. b, g, r = cv2.split(image)
    19. cvColor_image = cv2.merge([r, g, b])
    20. # 3.
    21. cvColor_image = image[:, :, :: -1]
    22. # matplotlib读取数据通道顺序, 默认颜色通道是RGB, 数据通道顺序是HWC
    23. def plt_channel(img_path):
    24. image = plt.imread(img_path)
    25. print("matplotlib type is ", type(image))
    26. print("matplotlib shape is ", image.shape)
    27. plt.imshow(image)
    28. plt.title("plt image")
    29. plt.show()
    30. # 将numpy数据转换成pillow数据
    31. pil_image = Image.fromarray(image)
    32. print("PIL type is ", type(pil_image))
    33. pil_image.show()
    34. def pillow_channel(img_path):
    35. image = Image.open(img_path)
    36. print("PIL type is ", type(image))
    37. print("PIL shape is ", image.size)
    38. image.show()
    39. # 将pillow数据转换成numpy数据
    40. np_image = np.array(image)
    41. print("matplotlib type is ", type(np_image))
    42. print("matplotlib shape is ", np_image.shape)
    43. plt.imshow(np_image)
    44. plt.title("pillow convert to numpy type")
    45. plt.show()
    46. if __name__ == "__main__":
    47. img_path = "./bee.jpg"
    48. pillow_channel(img_path)
    49. plt_channel(img_path)
    50. opencv_channel(img_path)

    三、CV预处理方式

    CV模型推理前包含多种预处理的方式,详细介绍部分常用的,且不同预处理方式存在diff的方法【模型预处理方式主要使用gocv、torchvision】

    resize

    参考:

    Python Pillow 和 OpenCV 中 resize 的区别 - 知乎

    Pillow vs cv2 resize

    cv2.resize()原理详解-CSDN博客

    作用:Resize() 修改图片的大小

    OpenCV

    • INTER_NEAREST - 最近邻插值
    • INTER_LINEAR - 双线性插值(默认使用)
    • INTER_AREA - 像素区域关系重采样【图片缩小优先使用方法】
    • INTER_CUBIC - 4*4临域双立方插值(三次样条插值) 【图片放大优先使用方法】
    • INTER_LANCZOS4 - x,y方向相邻八个点插值方法
    Totensor & Normalize

    作用:ToTensor() 数据归一化 + 图像HWC转换成CHW

    作用:Normalize() 数据标准化 【提高数据计算效率、模型准确性】

    1. def CV_Process(img_path):
    2. # ToTensor() 归一化到(0,1)之间; (H, W, C)的numpy.ndarray 转换为 (C, H, W)的tensor
    3. # Normalize() 再 (x-mean)/std 标准化到(-1,1)
    4. image = cv2.imread(img_path)
    5. print(image.shape)
    6. transform_2 = transforms.Compose([
    7. transforms.ToTensor(),
    8. transforms.Normalize(mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225])
    9. # 很多代码预处理Normalize中的参数值是从ImageNet训练集抽样计算而来
    10. ])
    11. transform_3 = transforms.Compose([
    12. transforms.ToTensor()
    13. ])
    14. image2 = transform_2(image)
    15. image3 = torch.from_numpy(image.transpose((2, 0, 1)))
    16. image3 = image3.float().div(255)
    17. channel_1 = image3[0].sub_(0.485).div_(0.229).unsqueeze(0)
    18. channel_2 = image3[1].sub_(0.456).div_(0.224).unsqueeze(0)
    19. channel_3 = image3[2].sub_(0.406).div_(0.225).unsqueeze(0)
    20. image3 = torch.cat([channel_1, channel_2, channel_3], dim = 0)
    21. print(image2.shape)
    22. print(image3.shape)
    23. print(image2.equal(image3)) # output: True

    四、torch操作详解

    1. torch.div & torch.div_ 区别

    torch.div和torch.div_的主要区别在于返回值和是否进行就地操作(in-place operations)。

    torch.div(a, b)的作用是对两个张量a和b逐元素地做除法操作,返回一个新的张量。如果a和b的shape不一致,torch会尝试将它们广播到一个合适的shape使得操作符合规则。

    torch.div_(a, b)的作用和torch.div类似,但是它会就地修改a的值,即直接将结果存储在a中。由于是就地操作,torch.div_只能对可写的(writable)张量使用。

    因此,torch.div和torch.div_在实现上略有不同,但作用是一致的,都是进行张量间的逐元素除法操作。一般来说,如果不需要就地修改操作,推荐直接使用torch.div,这样能保留原始张量的值,并且可读性更好。如果需要就地修改操作,需要使用torch.div_。

  • 相关阅读:
    Java中的方法递归(套娃检索)
    CMake输出编译时间信息
    STL技术——STL概述和入门
    嵌入式面试常见问题(一)
    3d激光SLAM:LIO-SAM框架---位姿融合输出
    动手学深度学习(Pytorch版)代码实践 -卷积神经网络-29残差网络ResNet
    【语音编码】基于matlab ADPCM编解码(Matlab代码实现)
    Pytorch学习:torch.max(input,dim,keepdim=False)
    第二节 threejs简单案例
    【EMQX】2.1.2 为什么选择EMQ X
  • 原文地址:https://blog.csdn.net/jiangchao98/article/details/133352532