如何从uint8原始图像数据创建uint16 numpy数组?USB相机Mono16存储问题
解决Mono16相机图像保存为16位numpy数组的问题
我之前对接USB相机采集Mono16格式图像时,也踩过完全一样的坑!核心问题其实是原始二进制数据的解析方式不对——Mono16每个像素占2字节,但如果直接默认用uint8去加载,就会把一个16位像素拆成两个8位元素,自然数组大小翻倍,数据类型也不对。
先给你两种最直接的解决方案:
方案1:直接读取为uint16数组(推荐)
如果你的相机SDK返回的是原始二进制字节流(比如bytes类型),直接用numpy的frombuffer方法指定dtype=np.uint16来读取,一步到位:
import numpy as np # 假设camera.read()返回原始Mono16格式的字节流 raw_data = camera.read() # 直接解析为uint16数组,注意相机的字节序(大端/小端),大部分相机是小端 image = np.frombuffer(raw_data, dtype=np.uint16) # 再根据相机分辨率reshape成二维图像 image = image.reshape((height, width))
这里要注意字节序:有些相机输出的Mono16是大端格式(big-endian),这时候需要把dtype改成'>u2'(大端无符号16位),如果是小端用'<u2',默认的np.uint16通常是小端,和大部分相机匹配,但如果图像看起来全是噪声,就需要切换字节序试试。
方案2:将已读取的uint8数组转换为uint16
如果你已经把数据读成了uint8数组,也不用慌,用view方法就能正确合并两个字节为一个16位像素,比as_strided更安全:
import numpy as np # 假设你已经得到了错误的uint8数组(大小为height*width*2) uint8_image = np.random.randint(0, 256, (height, width*2), dtype=np.uint8) # 转换为uint16,同样注意字节序 uint16_image = uint8_image.view(np.uint16).reshape((height, width)) # 如果是大端格式,用这个: # uint16_image = uint8_image.view('>u2').reshape((height, width))
为什么as_strided可能没解决?因为如果只是简单调整步长,很容易忽略字节序或者数组维度的对齐问题,而view是numpy专门用来在不复制数据的情况下转换数据类型的方法,更可靠。
最后提醒一下:保存图像的时候,比如用cv2.imwrite的话,要注意OpenCV默认可能不支持直接保存16位单通道图像,需要用cv2.imwrite('image.tiff', image)(TIFF格式支持16位),或者先归一化到0-255转成uint8保存,但这样会丢失精度。
内容的提问来源于stack exchange,提问作者Jack Bates
相关产品推荐
相关产品推荐

