CV预处理方式

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

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

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

二、图片读取实现

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

import cv2
import matplotlib.pyplot as plt
from PIL import Image

import numpy as np
import torch
from torchvision import transforms

# opencv读取数据通道顺序,默认颜色通道BGR, 数据通道顺序HWC
def opencv_channel(img_path):
	image = cv2.imread(img_path)
	print("cv2 type is ", type(image))  
	print("cv2 shape is ", image.shape)

	cv2.imshow("image", image)
	# cv2.waitKey(0)
    
	#opencv将BGR颜色通道顺序 更改为 RGB颜色通道顺序
	# 1. 
	cvColor_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 2.
	b, g, r = cv2.split(image)
	cvColor_image = cv2.merge([r, g, b])
	# 3.
	cvColor_image = image[:, :, :: -1]
      
# matplotlib读取数据通道顺序, 默认颜色通道是RGB, 数据通道顺序是HWC
def plt_channel(img_path):
	image = plt.imread(img_path)
	print("matplotlib type is ", type(image))
	print("matplotlib shape is ", image.shape)

	plt.imshow(image)
	plt.title("plt image")
	plt.show()

	# 将numpy数据转换成pillow数据
	pil_image = Image.fromarray(image)
	print("PIL type is ", type(pil_image))
	pil_image.show()

def pillow_channel(img_path):
	image = Image.open(img_path)
	print("PIL type is ", type(image))
	print("PIL shape is ", image.size)

	image.show()

	# 将pillow数据转换成numpy数据
	np_image = np.array(image)
	print("matplotlib type is ", type(np_image))
	print("matplotlib shape is ", np_image.shape)
	plt.imshow(np_image)
	plt.title("pillow convert to numpy type")
	plt.show()

if __name__ == "__main__":
	img_path = "./bee.jpg"
	pillow_channel(img_path)
	plt_channel(img_path)
	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() 数据标准化 【提高数据计算效率、模型准确性】

def CV_Process(img_path):
	# ToTensor() 归一化到(0,1)之间; (H, W, C)的numpy.ndarray 转换为 (C, H, W)的tensor
	# Normalize() 再 (x-mean)/std 标准化到(-1,1)

	image = cv2.imread(img_path)
	print(image.shape)

	transform_2 = transforms.Compose([
		transforms.ToTensor(),
		transforms.Normalize(mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225])
		# 很多代码预处理Normalize中的参数值是从ImageNet训练集抽样计算而来
	])

	transform_3 = transforms.Compose([
		transforms.ToTensor()
	])

	image2 = transform_2(image)
	image3 = torch.from_numpy(image.transpose((2, 0, 1)))
	image3 = image3.float().div(255)
	channel_1 = image3[0].sub_(0.485).div_(0.229).unsqueeze(0)
	channel_2 = image3[1].sub_(0.456).div_(0.224).unsqueeze(0)
	channel_3 = image3[2].sub_(0.406).div_(0.225).unsqueeze(0)
	image3 = torch.cat([channel_1, channel_2, channel_3], dim = 0)
	print(image2.shape)
	print(image3.shape)
	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_。

你可能感兴趣的:(pytorch)