从给定的图像数据中提取像素数据。需要帮助理解代码
Extracting pixel data from given image data. Need Help Understanding the code
我一直在研究从图像数据构建纹理,但是一些教程中提供的代码涉及移位位以获得图像像素。但是我对位移很陌生。我理解二进制 &
和 |
,但我不知道为什么需要这段代码来获取像素数据。
这是纹理数据:
static char* g_pTextureData =
"?VE`8U)K13Y:1C];2$%:5DQA>'&!@WB*:UQR9EET9%ES8UAP9UMZ>&%[A6Z$>6-Z"
"S[6XR[*PIH2\"IXN0HY2>DWR#VL;+TL3,LYZ<QZVNUL\"_L)..NJJXN:>[V<#)R;\"Y"
"W\G,Y-/4P9^3SZ^KZ-K>RJN?S:VMY=/4U[NPW<+![-GCV<\"UX,C&Y-7BZ=K>V\2^"
"W\F^XL[!R*.6UK:PYM7/RZB:U[R^V;^POY:)SZ^:Y]#/Y=')SZ^:Y]#/Y=')UKBH"
"OY*%O9*%K()WPYF+Q)Z+JGUVU[RUO9.\"HW=MN9)\R)N)MXQVM9!WRIN+QIJ+L8-W"
"GG9FJGYNIGMMJ'YMK()PHWIKN9J+HX)GGGI?L8YQL8US@653F7EBJGYJJGUIEVU@"
"GGY:F7E9E'18G'I9G'M:E'1;CW->C')6AVE3E'==F7ED<UQ5@6M4EWE5F7Y6DG92"
"C'!6AVI5@613AVQ5B6U5@6=6?FA8?F96>V)5@6E6AVY<:UE6:UM1>V90@6E0@6A0"
"<U]7=E]7<UE6<%M7=F!7<%M5:5=4:5M7;EI6:UM2;EY29%138E53:UA1:5A0<%]2"
"9%E6<%U:;EE;;EA::UE79E548E%39%15:5957U)29E=58E-69EA6<%Y6<%Y6:5E5"
"6U)3:UY<=F5A<U]?=F1>:UI:9EA7:5E78E158E-6;EQ89E=69%54:5M6<V189%E6"
"4$I/7556;F->;F!?;EY>:UI=;EY=<&%=9%588E-59%55<&!;:5A96TY25DY/5D]0"
"/SQ*03],1D-/23$)44$-65DI76TY86TQ674Y674Y49EA::5E;64Y2/SQ(/CQ("
",#%'+C!',#))-#-,-S--.3-./#9//#9./#1-0SM02D%013U,/SA*-S-(+BY%,3!&"
"(R-%&Q]$&A]%'B)'(R1()\"5((B-(*2=(*\"9)+\"E)+2M))21%(\"%#'!Y#(\"%$(B)%"
"\"A)\"\"A)\"\"1-\"\"A-\"\"A1\"\"A-\"\"Q-\"#!5\"#A5\"#A5\"#Q9\"$AA"
"\"&QU$%QM#\"Q-\"\"A-\""
"";
提供的用于获取颜色的位数据表示的宏:
#define HEADER_PIXEL(data,pixel) { \
pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4)); \
pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \
pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \
data += 4; \
}
我的理解是 '?'
的十进制值为 63。
所以按照宏,63 - 33 = 30
然后左移2位
(00000000 00000000 00000000 00011110) << 2
(00000000 00000000 00000000 01111000) = 120
接下来是 V,十进制值为 86
使用宏,86 - 33 = 53
然后右移4位
(00000000 00000000 00000000 00110101) >> 4
(00000000 00000000 00000000 00001101) = 13
然后我们进行按位或操作
01111000
00001101
========
01111101 = 125
我理解这背后的数学原理。但我的问题是为什么需要数学?为什么是 33 位和位移位?另外,为什么我们需要 0xF 和 0x3?
是否解压图片数据?还是它在做别的事情?
这是我需要知道的任何事情吗?或者这只是一个非常具体的例子,因为这就是我们 compress/decompress 图片的方式?
更新,感谢@v154c1 帮我把它装进包里。
对于遇到此问题的任何其他人。这就是我使用 @v154c1 所展示的内容对其进行合理化的方式。
00rrrrrr << 2 = rrrrrr00
00rrgggg >> 4 = 000000rr
rrrrrr00 | 000000rr = rrrrrrrr
00rrgggg & 00001111 = 0000gggg << 4 = gggg0000
00ggggbb & >> 2 = 0000gggg
gggg0000 | 0000gggg = gggggggg
00ggggbb & 00000011 = 000000bb << 6 = bb000000
00bbbbbb
bb000000 | 00bbbbbb = bbbbbbbb
Roger Rowland (Explanation of Header Pixel in GIMP created C Header File of an XPM image) 链接的答案实际上解释得很好。
它们将 RGB 值(24 位)存储在 4 个可打印字符中。
魔法值 33
是他们使用的第一个可打印字符(ASCII 中的 !
)。
所以GIMP完成的过程是:
首先,您有 1 个像素,其中 3 个 8 位值用于 R、G 和 B。您可以这样成像:
rrrrrrrr gggggggg bbbbbbbb
但是您不能简单地将其转储到头文件中。所以你把它分成 6 位组:(值 0 - 63):
rrrrrr rrgggg ggggbb bbbbbb
然后将数字33
添加到每个组(因此值为33 - 96。)然后将其作为4个字符存储到头文件中。
为了将其解码回像素数据,您只需减去 33 即可得到原始的 6 位值,然后它们再次将位组合成 3 个 8 位值。
这个移位和掩码 (&
) 只是将位组合在一起。
比如拿第一个:
pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4));
data[0]
和 data[1]
是第一个和第二个字符(添加了 33)。
所以你减去它(data[0] - 33
)并得到:
data[0] - 33 = rrrrrr
data[1] - 33 = rrgggg
然后轮班将值推到正确的位置:
rrrrrr << 2 = rrrrrr00
rrgggg >> 4 = rr
当你把它加在一起时,你有原始值 rrrrrrrr
。
值 33 到 96 映射到字符:
!, ", #, $, %, &, \', (, ), *, +, ,, -, ., /, 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, :, ;, <, =, >, ?, @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, `
您已经收到了您的 "main question" 的答复,所以我会答复其他人。 :-)
Is it decompressing the image data? Or is it doing something else?
您看到的是 encoding。压缩是一种编码,但这不是压缩。
考虑一下,如果我告诉你你需要发送一个介于 4 和 9 之间的数字给我。但是如果我告诉你你只能使用 A
、[=13= 的符号集呢? ], C
.如果你只是想编造一些东西,你可能会选择:
4 => A
5 => B
6 => C
7 => AA
8 => BB
9 => CC
当然可以有其他编码。有些可能更容易阅读和理解,可能是 "wasteful":
4 => AAAA
5 => AAAAA
6 => AAAAAA
7 => AAAAAAA
8 => AAAAAAAA
9 => AAAAAAAAA
仍然只有 6 个不同的值 "in the abstract",不管你看左边还是右边。保留相同数量的数据。但是你只需要看看你的屏幕就会发现,如果我们要用 characters 的计数而不是 states 来衡量它,它就会变长。
这就是图像数据在这种情况下发生的情况。您正在获取三个字节的像素数据,并将其存储在有限集合中的四个字节大小的字符中。因为一个像素和一个字符都占用一个字节,所以可以认为是"getting bigger".
(但在某种程度上,它实际上不是。:-P)
Is this anything that I would need to ever know? Or is this just a very specific instance in that this is how we compress/decompress images?
我会说你 "need" 知道什么完全取决于你 "want" 完成什么。 :-)
但是如果你想成为一名程序员,理解关于编码的抽象点是很重要的。人们可以在不接触 C 的情况下将整个职业生涯都花在软件上(有些人可能会说你很可能 better off for it)。然而,无论您使用什么编程,我在这个答案中提到的关于编码的概念都会出现。
我一直在研究从图像数据构建纹理,但是一些教程中提供的代码涉及移位位以获得图像像素。但是我对位移很陌生。我理解二进制 &
和 |
,但我不知道为什么需要这段代码来获取像素数据。
这是纹理数据:
static char* g_pTextureData =
"?VE`8U)K13Y:1C];2$%:5DQA>'&!@WB*:UQR9EET9%ES8UAP9UMZ>&%[A6Z$>6-Z"
"S[6XR[*PIH2\"IXN0HY2>DWR#VL;+TL3,LYZ<QZVNUL\"_L)..NJJXN:>[V<#)R;\"Y"
"W\G,Y-/4P9^3SZ^KZ-K>RJN?S:VMY=/4U[NPW<+![-GCV<\"UX,C&Y-7BZ=K>V\2^"
"W\F^XL[!R*.6UK:PYM7/RZB:U[R^V;^POY:)SZ^:Y]#/Y=')SZ^:Y]#/Y=')UKBH"
"OY*%O9*%K()WPYF+Q)Z+JGUVU[RUO9.\"HW=MN9)\R)N)MXQVM9!WRIN+QIJ+L8-W"
"GG9FJGYNIGMMJ'YMK()PHWIKN9J+HX)GGGI?L8YQL8US@653F7EBJGYJJGUIEVU@"
"GGY:F7E9E'18G'I9G'M:E'1;CW->C')6AVE3E'==F7ED<UQ5@6M4EWE5F7Y6DG92"
"C'!6AVI5@613AVQ5B6U5@6=6?FA8?F96>V)5@6E6AVY<:UE6:UM1>V90@6E0@6A0"
"<U]7=E]7<UE6<%M7=F!7<%M5:5=4:5M7;EI6:UM2;EY29%138E53:UA1:5A0<%]2"
"9%E6<%U:;EE;;EA::UE79E548E%39%15:5957U)29E=58E-69EA6<%Y6<%Y6:5E5"
"6U)3:UY<=F5A<U]?=F1>:UI:9EA7:5E78E158E-6;EQ89E=69%54:5M6<V189%E6"
"4$I/7556;F->;F!?;EY>:UI=;EY=<&%=9%588E-59%55<&!;:5A96TY25DY/5D]0"
"/SQ*03],1D-/23$)44$-65DI76TY86TQ674Y674Y49EA::5E;64Y2/SQ(/CQ("
",#%'+C!',#))-#-,-S--.3-./#9//#9./#1-0SM02D%013U,/SA*-S-(+BY%,3!&"
"(R-%&Q]$&A]%'B)'(R1()\"5((B-(*2=(*\"9)+\"E)+2M))21%(\"%#'!Y#(\"%$(B)%"
"\"A)\"\"A)\"\"1-\"\"A-\"\"A1\"\"A-\"\"Q-\"#!5\"#A5\"#A5\"#Q9\"$AA"
"\"&QU$%QM#\"Q-\"\"A-\""
"";
提供的用于获取颜色的位数据表示的宏:
#define HEADER_PIXEL(data,pixel) { \
pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4)); \
pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \
pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \
data += 4; \
}
我的理解是 '?'
的十进制值为 63。
所以按照宏,63 - 33 = 30
然后左移2位
(00000000 00000000 00000000 00011110) << 2
(00000000 00000000 00000000 01111000) = 120
接下来是 V,十进制值为 86 使用宏,86 - 33 = 53 然后右移4位
(00000000 00000000 00000000 00110101) >> 4
(00000000 00000000 00000000 00001101) = 13
然后我们进行按位或操作
01111000
00001101
========
01111101 = 125
我理解这背后的数学原理。但我的问题是为什么需要数学?为什么是 33 位和位移位?另外,为什么我们需要 0xF 和 0x3?
是否解压图片数据?还是它在做别的事情?
这是我需要知道的任何事情吗?或者这只是一个非常具体的例子,因为这就是我们 compress/decompress 图片的方式?
更新,感谢@v154c1 帮我把它装进包里。
对于遇到此问题的任何其他人。这就是我使用 @v154c1 所展示的内容对其进行合理化的方式。
00rrrrrr << 2 = rrrrrr00
00rrgggg >> 4 = 000000rr
rrrrrr00 | 000000rr = rrrrrrrr
00rrgggg & 00001111 = 0000gggg << 4 = gggg0000
00ggggbb & >> 2 = 0000gggg
gggg0000 | 0000gggg = gggggggg
00ggggbb & 00000011 = 000000bb << 6 = bb000000
00bbbbbb
bb000000 | 00bbbbbb = bbbbbbbb
Roger Rowland (Explanation of Header Pixel in GIMP created C Header File of an XPM image) 链接的答案实际上解释得很好。 它们将 RGB 值(24 位)存储在 4 个可打印字符中。
魔法值 33
是他们使用的第一个可打印字符(ASCII 中的 !
)。
所以GIMP完成的过程是:
首先,您有 1 个像素,其中 3 个 8 位值用于 R、G 和 B。您可以这样成像:
rrrrrrrr gggggggg bbbbbbbb
但是您不能简单地将其转储到头文件中。所以你把它分成 6 位组:(值 0 - 63):
rrrrrr rrgggg ggggbb bbbbbb
然后将数字33
添加到每个组(因此值为33 - 96。)然后将其作为4个字符存储到头文件中。
为了将其解码回像素数据,您只需减去 33 即可得到原始的 6 位值,然后它们再次将位组合成 3 个 8 位值。
这个移位和掩码 (&
) 只是将位组合在一起。
比如拿第一个:
pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4));
data[0]
和 data[1]
是第一个和第二个字符(添加了 33)。
所以你减去它(data[0] - 33
)并得到:
data[0] - 33 = rrrrrr
data[1] - 33 = rrgggg
然后轮班将值推到正确的位置:
rrrrrr << 2 = rrrrrr00
rrgggg >> 4 = rr
当你把它加在一起时,你有原始值 rrrrrrrr
。
值 33 到 96 映射到字符:
!, ", #, $, %, &, \', (, ), *, +, ,, -, ., /, 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, :, ;, <, =, >, ?, @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, `
您已经收到了您的 "main question" 的答复,所以我会答复其他人。 :-)
Is it decompressing the image data? Or is it doing something else?
您看到的是 encoding。压缩是一种编码,但这不是压缩。
考虑一下,如果我告诉你你需要发送一个介于 4 和 9 之间的数字给我。但是如果我告诉你你只能使用 A
、[=13= 的符号集呢? ], C
.如果你只是想编造一些东西,你可能会选择:
4 => A
5 => B
6 => C
7 => AA
8 => BB
9 => CC
当然可以有其他编码。有些可能更容易阅读和理解,可能是 "wasteful":
4 => AAAA
5 => AAAAA
6 => AAAAAA
7 => AAAAAAA
8 => AAAAAAAA
9 => AAAAAAAAA
仍然只有 6 个不同的值 "in the abstract",不管你看左边还是右边。保留相同数量的数据。但是你只需要看看你的屏幕就会发现,如果我们要用 characters 的计数而不是 states 来衡量它,它就会变长。
这就是图像数据在这种情况下发生的情况。您正在获取三个字节的像素数据,并将其存储在有限集合中的四个字节大小的字符中。因为一个像素和一个字符都占用一个字节,所以可以认为是"getting bigger".
(但在某种程度上,它实际上不是。:-P)
Is this anything that I would need to ever know? Or is this just a very specific instance in that this is how we compress/decompress images?
我会说你 "need" 知道什么完全取决于你 "want" 完成什么。 :-)
但是如果你想成为一名程序员,理解关于编码的抽象点是很重要的。人们可以在不接触 C 的情况下将整个职业生涯都花在软件上(有些人可能会说你很可能 better off for it)。然而,无论您使用什么编程,我在这个答案中提到的关于编码的概念都会出现。