#!/usr/bin/env python3
from pathlib import Path
# Load PNG as bytes and find "sBIT" chunk
png = Path('120130.png').read_bytes()
sBIToffset = png.find(b'sBIT')
if sBIToffset:
# 4 bytes before "sBIT" tell us how many values there are - could be 1-4 values
nValues = int.from_bytes(png[sBIToffset-4:sBIToffset], byteorder="big")
values = list(png[sBIToffset+4:sBIToffset+4+nValues])
print(f'Found sBIT chunk at offset: {sBIToffset} with value(s): {values}')
2条答案
按热度按时间wlzqhblo1#
这是查找
sBIT
块并提取比例因子的实现(恕我直言,非常糟糕)的替代方案。PNG块看起来像这样:
x1c 0d1x的数据
来源:Wikipedia
sBIT
块在十六进制中看起来像这样:字符串
在十六进制中,
73 42 49 54
(在第三行的中间)表示sBIT
,因此长度是之前的4个字节,即00 00 00 01
,这意味着块中有1个值-这是灰度图像中的预期值。根据图像类型,可能最多有4个值(grey,grey+alpha,RGB,RGBA)。这意味着在此图像中仅使用1个字节。该字节为09
,意味着值为9。因此,您可以更简单地像这样提取sBIT:
型
我将另一个实现描述为 “相当差”,因为它花费时间在内存中移动文件的整个内容,并且不处理多通道图像的多个有效位-它还读取文件两次,并且......
d5vmydt92#
我终于在NI论坛上得到了答案。非常感谢Andrew Dmitriev。
NI的16位PNG图像与sBIT存储在一起。这意味着像素的值被移到最高位(这是PNG标准的一部分,但大多数库都不知道这一点)。请参阅http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.sBIT
此外,有符号表示的偏移量存储在scAl块的前两个字节中。所以,所有你需要的-只需读取“RAW”png数据,然后根据sBIT值执行移位,然后减去从scAl块中获取的偏移量。这就是全部(如果你想在没有“额外”DLL的情况下完成任务)。附加I16和U16图像的示例。
顺便说一句-有一个错误,在PNG编码器从NI。而不是逻辑移位,他们执行旋转(以某种奇怪的形式),所以应该是零的较低有效位-不是零,因此我们有上面提到的这些奇怪的值(例如,当范围0.1000变成0.64062时,它应该是0.64000)。但这不是一个大问题,因为这些位在移回后就消失了。
同样在手册中,它错误地指出使用位深度输入仅适用于有符号的图像。在有符号的图像上,此控件将切断负值,但在无符号的图像上(当与IMAQ图像位深度一起使用时),此控件将允许保存“原生”16位值,因此图像可以在第三方库中打开而无需转换。
以下是dgagnon05使用openCV的代码:
字符串