【openCV中的BGR和RGB】img[:,:,::-1]和img[:, :, (2, 1, 0)]对图像操作

以下放在开头,备忘:

  1. img = Image.open(ImgPath)
    打开的图片是PIL类型,默认RGB。
    将PIL类型转化为numpy类型:im = numpy.array(img)
    才能看到shape属性,是(height, width, channel)数组,channel的通道数据是RGB。
  2. cv2.imread(path, 读取方式):
    path: 图片的路径;
    读取方式: cv2.IMREAD_COLOR:读入一副彩色图片;cv2.IMREAD_GRAYSCALE:以灰度模式读入图片;cv2.IMREAD_UNCHANGED:读入一幅图片,并包括其alpha通道。
    默认为cv2.IMREAD_COLOR。
    返回值是(height,width,channel)数组,channel的顺序是BGR顺序
  3. 两者之间的相互转换
    PIL Image转化为OpenCV格式:
    img = Image.open()
    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    OpenCV转化为PIL Image格式:
    img = cv2.imread()
    img2 = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
  4. plt.imshow()和cv2.imshow()
    这个显示是和读取对着的,也就是说要想可视化出来正常的RGB格式,给plt.imshow()的应该是rgb格式的图片,给cv2.imshow()的应该是bgr格式的图片。多说一些plt.imshow(),因为我平时几乎不用cv2.imshow()。在plt.imshow()中,接受的图片类型可以是np.ndarray,tensor, PIL Image这些任意的类型。

在SSD和YOLO的源码中,使用opencv读取图片,其处理图片时都有以下图片通道转换的代码,做以下记录:

https://github.com/ultralytics/yolov3中的一部分为例:

img0 = cv2.imread(path)  # BGR
 # Padded resize
img = letterbox(img0, self.img_size, stride=self.stride)[0]

# Convert
img = img[:, :, ::-1].transpose(2, 0, 1)  # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img)

其中的Padded resize不用管,是YOLO对输入图片按Padded方式进行Resize。
我们要分析的是img = img[:, :, ::-1].transpose(2, 0, 1)这句代码
先放结论:

img[:,:,::-1] 这句的作用,是说:图像张量有三个维度,分别表示宽度、长度和颜色通道。既然image[:,:,::-1]的作用是对颜色通道把RGB转换成BGR。

怎么转换的呢?

1. img[:,:,::-1]作用

对于列表img进行img[:,:,::-1]的作用是列表数组左右翻转,例如:

import numpy as np
 
a = np.arange(27).reshape(3,3,3)
print(a)
'''
[[[ 0  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]]]
'''
b = a[:,:,::-1]
print(b)
'''
[[[ 2  1  0]
  [ 5  4  3]
  [ 8  7  6]]
 [[11 10  9]
  [14 13 12]
  [17 16 15]]
 [[20 19 18]
  [23 22 21]
  [26 25 24]]]
'''

可以明确看出,[:,:,::-1]的作用就是对数组进行左右翻转。那为什么对于图像而言却能实现RGB通道转换为BGR通道呢?先看一些读取图片的方法是怎么读取吧

一般有opencv(cv2)和matplotlib(plt)的读取方式:(cv2把图片读取后是把图片读成BGR形式的,plt则是读成RGB形式)

证明如下:

以一张图片为样例:

正常显示就是以RGB为格式显示的。当我们用plt读取时:

from matplotlib import pyplot as plt
import cv2
img_name = r'C:\Users\Administrator\Desktop\airball\val\35.jpg'
img = plt.imread(img_name)
print(img)

打印出来的是:

取第一个值,(129,80,73),在网上以查,颜色是深棕色的,确实跟图片的左上角是一致的:

证明plt读取图片的方式确实是以RGB的格式读取。

接着:

当执行 [:,:,::-1]后,数组会左右翻折:

from matplotlib import pyplot as plt
import cv2
img_name = r'C:\Users\Administrator\Desktop\airball\val\35.jpg'
img = plt.imread(img_name)
print(img)
print('-----------------------')
img = img[:, :, ::-1]
print(img)

可以看到(129 80 73)变成(73 80 129)。

通过网上查询(73 80 129)是什么颜色的,发现是蓝色的。

所以,如果拆测没错的话,这是后显示出来的图片应该左上角就是蓝色的,我们试试:

from matplotlib import pyplot as plt
import cv2
img_name = r'C:\Users\Administrator\Desktop\airball\val\35.jpg'
img = plt.imread(img_name)
print(img)
print('-----------------------')
img = img[:, :, ::-1]
plt.imshow(img)
plt.show()

果然左上角就是蓝色的。因此,这应该是BRG格式的图片了。所以得证,[:,:,::-1]的作用就是把RGB(或BRG)转换成BGR(或者RGB)。

=============================

插一句题外话,用opencv(即cv2)读取图片,是以BGR的形式来读取的。我们用cv2的imshow()函数显示图片发现跟我们打开图片的样子一样,是因为cv2的imshow()又把BGR转回RGB再显示。但cv2确实是以BGR形式读取图片的,而plt则是以RGB形式。

2. img[:, :, (2, 1, 0)]

代码中有时也会有img[:, :, (2, 1, 0)]这种操作,这个的意义也是通道的转换。其实都是因为opencv中imread读取出来的图片是BGR格式,也就是说下列三组代码是完全等价的,操作的结果都是将imread读取的BGR格式的图片转换为RGB格式

#第一组
image = cv2.imread(path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)          # 转化为RGB

#第二组
image = cv2.imread(path)
image = image[:, :, (2, 1, 0)]

#第三组
image = cv2.imread(path)
image = image[:,:,::-1]

回到最初的问题,img = img[:, :, ::-1].transpose(2, 0, 1)这句代码transpose(2,0,1)有什么用,一句话总结:

这时的image是H,W,C的顺序,因此需要转化为C, H, W,维度变换正好2,0,1
变换维度的目的仅仅是为了方便计算。

常见如下代码

image = torch.from_numpy(image).permute(2, 0, 1)

3. PIL读取

PIL读取很正常,没什么操作,通常也不进行转换

image = Image.open(os.path.join(self.image_path, image_name)) 
 # 读取到的是RGB, C, H, W

参考:

图像领域img[:,:,::-1]的理解

pytorch:读取图像的两种方法

  • 34
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值