英文:
Numpy workaround for dtype=uint10, uint12, uint14 for RAW image import
问题
将16位无符号原始(图像)数据导入Python很简单:
data = numpy.fromfile( source_file, dtype=numpy.uint16 )
data = numpy.asarray( data )
但我还必须导入10、12和14位无符号整数数据,以便将这些数据编码为专有的图像格式。该格式简单地接受带有唯一标头的16位或32位整数数组。NumPy没有实现10、12和14位数据类型。
当我将10、12或14位RAW在ImageJ中以16位无符号图像(这是ImageJ中最小的可用无符号位深度)打开时,它看起来很奇怪,但像素都位于正确的位置。这是错误的位深度,所以我不感到惊讶。
然而,如果我在ImageJ中使用小端字节顺序打开RAW,那么10位图像在ImageJ中会完美地显示为16位无符号图像。所以我在Python中尝试了这个:
image_bitness = numpy.uint16
image_bitness = numpy.dtype( image_bitness ).newbyteorder( '<' )
data = numpy.fromfile( source_file, dtype=image_bitness )
data = numpy.asarray( data )
在Python中将字节顺序切换为小端没有效果。当我在Python中进行图像转换成新格式,然后在ImageJ中打开这个新图像时,图像仍然看起来很奇怪。
我已经为16位和32位无符号RAW实施了相同的文件转换,它完美地工作。
所以总结一下:
-
对于10、12或14位无符号数据类型,实际的解决方法尚不清楚
-
不确定如何将10位转换为16位,特别是如果我必须假定16位来调用
numpy.fromfile( source_file, dtype=numpy.uint16 )
以最初获取数据数组(请参见附录) -
不确定为什么ImageJ的小端显示图像是正确的。将小端图像视为大端图像可能会彻底破坏图像。也许我弄错了。
-
不确定为什么在Python中交换字节顺序没有与ImageJ相同的效果
示例10位图像
在ImageJ中没有"little endian"显示时,像素显示不正确。在Python中转换为新文件格式的图像如下所示:
在ImageJ中有"little endian"显示时,像素显示正确:
附录:用于获取16位的二进制的填充
我认为可以用0来填充我的二进制数,然后转换回十进制整数。我尝试了这个:
data = numpy.fromfile( source_file, dtype=numpy.uint16 ) #仍然适用于10位图像?
for i in data:
data[i] = int( bin( data[i] )[2:].zfill(16), 2 )
data = numpy.asarray( data )
这将0000001011
转换为0000000000001011
作为字符串,然后将该字符串转换回十进制整数。
然而,当我在转换后在ImageJ中打开我的图像时,它仍然看起来很奇怪。我假设这是因为0000001011
和0000000000001011
以及1011
仍然是相同的数字。如何强制分配更多内存?
我还尝试通过交换字节来交换字节顺序:
for i in data:
data[i] = int( bin( data[i] )[2:].zfill(16)[::-1], 2 )
这将使我的字符串变成0001
变成1000
。结果是相同的。在ImageJ中仍然是一个奇怪的图像。
英文:
Importing 16-bit unsigned raw (image) data into python is simple:
data = numpy.fromfile( source_file, dtype=numpy.uint16 )
data = numpy.asarray( data )
But I must also import 10, 12, and 14-bit unsigned integer data so I can encode those data into a proprietary image format. The format simply accepts an array of 16 or 32-bit integers with a unique header. Numpy has no implementation for 10, 12, and 14-bit data types.
When I open 10, 12, or 14-bit RAW in ImageJ as a 16-bit unsigned image (this is the smallest available unsigned bit depth for ImageJ), it looks funny, but the pixels are all in the correct location. This is the wrong bit depth, so I'm not surprised.
However, if I open the RAW in ImageJ with little endian byte order, the 10-bit image displays perfectly as a 16-bit unsigned image inside ImageJ. So I try this in Python:
image_bitness = numpy.uint16
image_bitness = numpy.dtype( image_bitness ).newbyteorder( '<' )
data = numpy.fromfile( source_file, dtype=image_bitness )
data = numpy.asarray( data )
Swapping the byte order to little endian has no effect in python. The image still looks funny when I conduct the image conversion in python into the new format, then open this new image in ImageJ.
I have implemented this same file conversion for 16 and 32-bit unsigned RAW and it works perfectly.
So to summarize:
-
An actual work-around for 10, 12, or 14-bit unsigned data types is the issue
-
Not sure how best to convert from 10 to 16-bit generally, especially if I must assume 16-bit to call
numpy.fromfile( source_file, dtype=numpy.uint16 )
to get an array of data initially (see Appendix) -
Not sure why ImageJ little endian displays the image correctly. Viewing a little endian image as big endian should probably scramble the image entirely. Maybe I'm mistaken.
-
Not sure why swapping byte order in Python does not have the same effect as ImageJ
Example 10-bit images
Incorrectly displayed pixels without "little endian" in ImageJ. Images converted in Python into new file format look like this:
Correctly displayed pixels with "little endian" in ImageJ:
Appendix: Padding base-2 binary to get 16-bits
I thought I could pad out my base-2 binary number with 0s, then convert back to base-10 integer. I tried this:
data = numpy.fromfile( source_file, dtype=numpy.uint16 ) #still compiles for 10-bit image?
for i in data:
data[i] = int( bin( data[i] )[2:].zfill(16), 2 )
data = numpy.asarray( data )
This converts 0000001011
to 0000000000001011
as a string, then converts that string back to a base-10 integer.
However - when I open my image in ImageJ after the conversion, it still looks funky. I'm assuming this is because 0000001011
and 0000000000001011
and 1011
are still the same number. How do I basically enforce greater memory allocation?
I also tried to swap the byte order by literally swapping the bytes:
for i in data:
data[i] = int( bin( data[i] )[2:].zfill(16)[::-1], 2 )
This will transpose my string so 0001
becomes 1000
. The result is the same. Still a funny-looking image in ImageJ.
答案1
得分: 0
import cv2
import numpy as np
# 定义参数
w, h, bytesPerPixel = 1392, 1040, 2
# 加载图像
data = np.fromfile('10bit_1392x1040_10Frames.raw', dtype=np.uint16, offset=0, count=w*h).reshape((h, w)) << 6
# 保存
cv2.imwrite('result.png', data)
如果您的数据是12位,将左移位从6更改为4。如果是14位,将左移位从6更改为2。
如果要获取第N帧,请将偏移量更改为 `N * w * h * bytesPerPixel`,因为它是以字节而不是样本来衡量的。
英文:
It's as simple as this:
import cv2
import numpy as np
# Define parameters
w, h, bytesPerPixel = 1392, 1040, 2
# Load image
data = np.fromfile('10bit_1392x1040_10Frames.raw', dtype=np.uint16, offset=0, count=w*h).reshape((h,w)) << 6
# Save
cv2.imwrite('result.png', data)
If your data is 12-bit, change the left-shift from 6 to 4. If 14-bit, change the left-shift from 6 to 2.
If you want the Nth frame, change the offset to N * w * h * bytesPerPixel
because it is measured in bytes not samples.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论