首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >像素格式位endianness

像素格式位endianness
EN

Stack Overflow用户
提问于 2022-02-28 23:45:57
回答 2查看 445关注 0票数 1

我目前正在实现一个程序,从BMP文件中读取和解码图像。但我真的对像素格式感到困惑,尤其是对比特的痴迷。

我目前的理解是,当提到像素格式时,例如RGBA32,我们是用人类的方式来表示它,即使用大端字节,因此第一个字节是R,第二个G,第三个B,第四个A:

代码语言:javascript
运行
复制
RGBA32
11111111 22222222 33333333 44444444
R        G        B        A

在此格式(如RGBA32BE/RGBA32LE,)中添加大/小端点时,这将相应地更改字节顺序,如下所示:

代码语言:javascript
运行
复制
RGBA32BE (unchanged)
11111111 22222222 33333333 44444444
R        G        B        A

RGBA32LE (reversed)
11111111 22222222 33333333 44444444
A        B        G        R

这一切在我看来都很自然,只要我们假设每个组件的单个值就是我们读取的字节的值。

然而,当组件大小小于1字节或8位时,我开始感到困惑。假设是RGB555BE,我想下面是如何将其表示为字节数组的:

代码语言:javascript
运行
复制
RGB555BE
1'22222'33 333'44444
A   R      G     B
0'00001'00 000'00000
  1. 我们是将R组件读取为10000=16还是00001=1
  2. 对于我们读取组件的方式(位endianness)是否与字节endianness有关,我更加困惑了吗?
  3. RGB555LE格式用字节数组表示的是哪种方式? RGB555LE_v1 333'44444 1'22222'33 G“B‘000'00000 0'00001'00或RGB555LE_v2 ? 44444'333 33'22222'1 B 00000'000 00'10000'0
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-03-01 12:37:45

我们可以使用FFmpeg测试不同的像素格式。

结论是:

  • 这里没有一点endianness,只有字节endianness。
  • 当基元素为2个字节(uint16)时,endianness是相关的。 uint16元素的字节顺序是: LSB,MSB。 位端点:uint16元素的字节顺序是: MSB,LSB。

执行FFmpeg CLI命令进行测试:

例如,从rgb24开始:

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=red:size=8x8:rate=1:duration=1 -pix_fmt rgb24 -f rawvideo red.raw
ffmpeg -y -lavfi color=0x00FF00:size=8x8:rate=1:duration=1 -pix_fmt rgb24 -f rawvideo green.raw
ffmpeg -y -lavfi color=blue:size=8x8:rate=1:duration=1 -pix_fmt rgb24 -f rawvideo blue.raw

使用像HxD这样的十六进制查看器来检查原始文件内容。

red.raw FF 00 00 FF 00 00...

blue.raw 00 FF 00 00 FF 00...

green.raw 00 00 FF 00 00 FF...

rgba像素格式:

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=red:size=8x8:rate=1:duration=1 -pix_fmt rgba -f rawvideo red.raw
ffmpeg -y -lavfi color=0x00FF00:size=8x8:rate=1:duration=1 -pix_fmt rgba -f rawvideo green.raw
ffmpeg -y -lavfi color=blue:size=8x8:rate=1:duration=1 -pix_fmt rgba -f rawvideo blue.raw

r:FF 00 00 FF

g:00 FF 00 FF

b:00 00 FF FF

FFmpeg约定是字节的顺序。

我们不能说命名是否适用于很少或大的endian。

在使用uint16组件(而不是uint8组件)时,endianness是相关的。

rgba像素格式:

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=red:size=8x8:rate=1:duration=1 -pix_fmt rgba -f rawvideo red.raw
ffmpeg -y -lavfi color=0x00FF00:size=8x8:rate=1:duration=1 -pix_fmt rgba -f rawvideo green.raw
ffmpeg -y -lavfi color=blue:size=8x8:rate=1:duration=1 -pix_fmt rgba -f rawvideo blue.raw

r:FF 00 00 FF

g:00 FF 00 FF

b:00 00 FF FF

ARGBA.

我们可以称rgbaRGBA32BE,但这太让人困惑了.

rgb555le像素格式:

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=red:size=8x8:rate=1:duration=1 -pix_fmt rgb555le -f rawvideo red.raw
ffmpeg -y -lavfi color=0x00FF00:size=8x8:rate=1:duration=1 -pix_fmt rgb555le -f rawvideo green.raw
ffmpeg -y -lavfi color=blue:size=8x8:rate=1:duration=1 -pix_fmt rgb555le -f rawvideo blue.raw

r:00 7C 00 7C

g:E0 03 E0 03

b:1F 00 1F 00

我们还可以检查较低的位(关于位的排序):

将颜色设置为8,因此在移动后值为1。

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=0x000008:size=8x8:rate=1:duration=1 -pix_fmt rgb555le -f rawvideo red.raw
ffmpeg -y -lavfi color=0x000800:size=8x8:rate=1:duration=1 -pix_fmt rgb555le -f rawvideo green.raw
ffmpeg -y -lavfi color=0x080000:size=8x8:rate=1:duration=1 -pix_fmt rgb555le -f rawvideo blue.raw

r:01 00 01 00 2字节(以位为单位):00000001 00000000

g:20 00 20 00 2字节(位):00100000 00000000

b:00 04 00 04 2字节(以位为单位):00000000 00000100

rgb555be像素格式:

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=red:size=8x8:rate=1:duration=1 -pix_fmt rgb555be -f rawvideo red.raw
ffmpeg -y -lavfi color=0x00FF00:size=8x8:rate=1:duration=1 -pix_fmt rgb555be -f rawvideo green.raw
ffmpeg -y -lavfi color=blue:size=8x8:rate=1:duration=1 -pix_fmt rgb555be -f rawvideo blue.raw

r:7C 00 7C 00

g:03 E0 03 E0

b:00 1F 00 1F

检查下位(查看位序):

代码语言:javascript
运行
复制
ffmpeg -y -lavfi color=0x000008:size=8x8:rate=1:duration=1 -pix_fmt rgb555be -f rawvideo red.raw
ffmpeg -y -lavfi color=0x000800:size=8x8:rate=1:duration=1 -pix_fmt rgb555be -f rawvideo green.raw
ffmpeg -y -lavfi color=0x080000:size=8x8:rate=1:duration=1 -pix_fmt rgb555be -f rawvideo blue.raw

r:00 01 00 01

g:00 20 00 20

b:04 00 04 00

在大端字节格式中,只交换字节。

(对于每个uint16元素(两个字节),交换第一个和第二个字节的顺序)。

问题的答案:

  1. 我们是以10000=16还是00001=1 ?的形式读取R组件

答案:

rgb555le:00000001 00000000

rgb555be:00000000 00000001

  1. 对于我们读取组件的方式(位endianness)是否与字节endianness有关,我更加困惑了吗?

答案:

在像素格式的上下文中,没有“位endianness”,只有“字节endianness”。

Bits与串行通信更相关,从软件角度看,我们看不到每个字节中位的顺序。

  1. RGB555LE格式用字节数组表示的是哪种方式?

答案:

RGB555LE (as RGB555LE_v1):

byte0 byte1

gggbbbbb 0rrrrrgg

(大多数左位是每个字节中的上位)。

我们最好将数据看作一个uint16元素:

b:0000000000011111 (纯蓝色)

g:0000001111100000 (纯绿色)

r:0111110000000000 (纯红色)

我们可以把它看作是uint160rrrrrgggggbbbbb

票数 3
EN

Stack Overflow用户

发布于 2022-03-01 01:24:24

我认为endianness对rgb555并不重要,这就是为什么您的链接将rgb555rgb555lergb555be捆绑在一起的原因。因此,使用rgba的示例也不敏感,因为它的组件都是<= 8位。

至于rgb555是如何以2字节(嗯,15位)表示的,您可以在FFmpeg回购中搜索rgb555,看看编码器/解码器是如何处理这种像素格式的。这是我找到的第138行

代码语言:javascript
运行
复制
static uint16_t rgb24_to_rgb555(uint8_t *rgb24)
{
    uint16_t rgb555 = 0;
    uint32_t r, g, b;

    r = rgb24[0] >> 3;
    g = rgb24[1] >> 3;
    b = rgb24[2] >> 3;

    rgb555 |= (r << 10);
    rgb555 |= (g << 5);
    rgb555 |= (b << 0);

    return rgb555;
}

编码器采用rgb555 (16位无符号int ),a使用put_bits()实用程序函数将这15位推送到其比特流,如第683项所示。

代码语言:javascript
运行
复制
put_bits(&s->pb, 16, rgb24_to_rgb555(avg_color));

下面是指向bits.h的链接

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71302279

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档