OpenCV读取图像时按照BGR的顺序HWC排列,PyTorch按照RGB的顺序CHW排列,HWC格式排列,那么内存位置计算公式是?

修正20240422,计算HWC格式排列,那么内存位置计算公式错误

OpenCV读取RGB图像

在OpenCV中,读取的图片默认是HWC格式,即按照高度、宽度和通道数的顺序排列图像尺寸的格式。我们看最后一个维度是C,因此最小颗粒度是C。

例如,一张形状为256×256×3的RGB图像,在OpenCV中读取后的格式为[256, 256, 3],其中最后一个维度表示图像的通道数。在OpenCV中,可以通过cv2.imread()函数读取图片,该函数的返回值是一个NumPy数组,表示读取的图像像素值。

需要注意的是,OpenCV读取的图像像素值是按照BGR顺序排列的,而不是RGB顺序。因此,如果需要将OpenCV读取的图像转换为RGB顺序,可以使用cv2.cvtColor()函数进行转换。

OpenCV读取一张RGB图像时,它会将像素数据按照BGR的顺序排列,对于一张3×4的RGB图像,其像素信息在内存中的排列方式如下所示:

[
[[B G R] [B G R] [B G R][B G R],
[[B G R] [B G R] [B G R][B G R],
[[B G R] [B G R] [B G R][B G R], ]

可知,每一个像素点都由三个值组成,分别表示该像素点在蓝色、绿色和红色通道中的颜色值,而整张图像的像素数据则按照BGR的顺序排列。

在HWC格式中,最小的像素坐标是(0,0),如果像素点的坐标为(i, j),且其在第k个通道中的值需要被访问,那么其在内存中的存储位置可以表示为:
o f f s e t = i ∗ W ∗ C + j ∗ C + k offset = i * W * C + j * C + k offset=iWC+jC+k

也可以写成
o f f s e t = ( i ∗ W + j ) ∗ C + k offset = (i * W + j) * C + k offset=(iW+j)C+k

其中:

  • i 表示像素点的高度索引(在0到H-1之间,H是图像的高度)。
  • j 表示像素点的宽度索引(在0到W-1之间,W是图像的宽度)。
  • k 表示通道索引(在0到C-1之间,C是通道数,对于RGB图像,C通常是3)。
  • W 表示图像的宽度。
  • C 表示通道数。

所以,对于 按照 BGR 排列的图像中的任意一个像素点(i, j),如果你想要获取该像素点的蓝色通道的值,你需要计算该像素点在内存中的偏移量,然后加上0,如果你想要获取绿色通道的值,则加上1,对于红色通道则加上2。

首先计算了像素点(i, j)在整个图像中的线性位置(i * W + j),然后乘以通道数(C)以找到该像素点第一个通道值的起始位置。最后,加上通道索引(k)来得到特定通道的内存偏移量。

与CHW格式相比,HWC格式更直观,因为它首先按照图像的二维空间布局(高度和宽度)来排列数据,然后再按照通道来组织。这也是许多图像处理库(如OpenCV)和某些深度学习框架中默认的图像数据格式。

在PyTorch中读取RGB图像

特别是使用PyTorch等框架时,数据可能以CHW(通道、高度、宽度)或NHWC(批量大小、高度、宽度、通道)的格式存储,但这通常是在特定的库或框架内部为了计算效率而进行的优化,而不是图像在磁盘上的存储格式或常规处理时的格式。因此,在计算偏移量时,需要根据实际数据的布局来确定正确的公式。像素值通常采用浮点数的形式表示,并且像素值的范围通常是[0, 1]或[-1, 1]。

一般pytorch中的tensor,即网络的输入,要转换为plane的格式,即rrrrggggbbbb。

[
[[R R R R] [R R R R] [R R R R]],
[[G G G G] [G G G G] [G G G G]],
[[B B B B] [B B B B] [B B B B]], ]

在PyTorch中,模型接收的RGB图像通常采用CHW格式,即按照通道数、高度和宽度的顺序排列像素信息的方式。

在这种格式下,对于一个特定的像素点(i, j)在通道k中,其在内存中的存储位置(或偏移量)可以通过以下公式计算:

offset = k * H * W + i * W + j

其中:

  • k 是通道索引(在0到C-1之间,C是通道数)。
  • i 是高度索引(在0到H-1之间,H是图像的高度)。
  • j 是宽度索引(在0到W-1之间,W是图像的宽度)。
  • H 是图像的高度。
  • W 是图像的宽度。

这个公式首先计算了通道k在整个图像中的起始位置(k * H * W),然后加上当前行在通道k中的起始位置(i * W),最后加上当前像素点在当前行中的位置(j)。这样就得到了像素点(i, j)在通道k中的内存偏移量。

请注意,这个公式假设图像数据是紧密排列的,没有额外的填充或间隙。此外,这里计算的是以字节为单位的偏移量,实际上每个像素点可能由多个字节组成(例如,对于浮点数表示的图像),但这不影响偏移量的计算,只需在访问数据时考虑每个像素点的大小即可。

实验

1 生成一张图片

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# 用随机数模拟一张图像
image = np.random.randint(256, size=60)
image = image.reshape((5,4,3))
image_hwc = np.uint8(image)

# 展示图像
image_show = Image.fromarray(image_hwc)
plt.imshow(image_show)
plt.show()

# 打印图像像素值,[h, w, c]格式
print(image_hwc)

# 打印像素值,[c, h, w]格式
image_chw = np.transpose(image_hwc, (2,0,1))
print(image_chw)

以上代码模拟生成的图像如下图所示,图中有5行4列总共20个像素。
在这里插入图片描述

上图的所有像素及其像素值如下图所示,[h, w, c]格式。可以看出,最里层的括号内为单个像素在三个通道上的像素值。

我们看这种维度的一个方法是:看最后一个维度的含义,[h,w,c]最后一个维度是3,因此意味着最小的颗粒度维度是3。

在这里插入图片描述
如果以[c, h, w]格式表示的话,应该是下图这样的:
看最后一个维度的含义,[c,h,w]最后一个维度是w(我们实验中是4),因此意味着最小的颗粒度维度是4。

我们想象,一束光通过三棱镜后分解为彩色光,我们取出其中一个频段的数据,把这个频段的数据进行二维排列,就是该通道的情况。

在这里插入图片描述

2 CHW和HWC的本质

本质是一个规范,排列多维度的数据的规范,换句话说,就是定义了一个数据类型的结构体。

转换过程

  1. 其实数据可以看做是一堆无序的数据,轴的存在让这些数据按照一定层级及次序排布
  2. 转换前的数据是这样排布的,先按照图像高分成3堆,对这3堆的每一堆按照图像图像宽分2堆,分好的2堆分别按照通道数分成3堆
  3. 转换后的数据排布顺序变了,它先按照通道数分成3堆,分好的3堆各自按照图像高分成3堆,再按照图像宽分成2堆。

在这里插入图片描述

参考

https://blog.csdn.net/hh1357102/article/details/130622666
https://zhuanlan.zhihu.com/p/476310426

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hali_Botebie

文中错误请不吝指正!!!!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值