在 Python 中将单个整数像素数组转换为 RGB 三元组
Posted
技术标签:
【中文标题】在 Python 中将单个整数像素数组转换为 RGB 三元组【英文标题】:Convert array of single integer pixels to RGB triplets in Python 【发布时间】:2013-10-26 06:42:45 【问题描述】:我正在使用 Micro-Manager 1.4 为显微镜使用相机。使用 Python 界面,我已经设法访问相机、更改曝光时间等,并且可以捕获单个图像。
但是,每个图像都作为 NumPy 数组返回,其中每个像素都表示为单个整数,例如“7765869”。据我在网上找到,这在 Java 中被称为“BufferedImage”,这意味着 RGB 值被编码为:
BufferedImage = R * 2^16 + G * 2^8 + B
我的问题是:我怎样才能使用例如Numpy 或 OpenCV,将这种数组转换为更方便的数组,其中每个像素都是 uint8 值的 RGB 三元组?不用说,转换应该尽可能高效。
【问题讨论】:
为了扩展这背后的理论,你所拥有的是一个a * x + b * y + c * z == n
形式的线性丢番图方程,在我们的例子中是a = 2**16, b = 2**8, c = 1
。通常,这些方程的解涉及找到gcd(a, b, c)
并希望它除以n
;如果没有,那么就没有解决方案。假设存在一个解决方案,则存在无限多个解决方案。但是,在这种情况下,我们受限于找到解决方案0 <= x, y, z < 256
,因此鉴于gcd(a, b, c) | n
,将只有一个解决方案。
【参考方案1】:
最简单的方法是让 numpy 为您进行转换。您的 numpy 数组可能是 np.uint32
类型。如果您将其视为np.uint8
的数组,您将拥有一个RGB0 格式的图像,即每个像素的R、G 和B 值,再加上一个空的np.uint8
。很容易重塑和丢弃那个零值:
>>> img = np.array([7765869, 16777215], dtype=np.uint32)
>>> img.view(np.uint8)
array([109, 127, 118, 0, 255, 255, 255, 0], dtype=uint8)
>>> img.view(np.uint8).reshape(img.shape+(4,))[..., :3]
array([[109, 127, 118],
[255, 255, 255]], dtype=uint8)
最好的事情是无需计算或复制数据,只需重新解释原始图像的内容:我认为没有比这更有效的方法了!
我记得对于某些操作,OpenCV 需要一个连续的数组,因此您可能必须在该表达式的末尾添加一个 .copy()
才能真正摆脱零列,而不是简单地忽略它,尽管这会当然会触发上面代码避免的数据副本。
【讨论】:
完美运行!将“img2”定义为“img.view(np.uint8).reshape(img.shape+(4,))[..., :3]”,然后使用“cv2.imwrite”完美保存图像。谢谢! @Bjarke 您可能需要确保保存的是 RGB 图像,而不是 BGR 图像...这取决于系统的字节序。如果有误,只需在img2
定义的末尾加上 [::-1]
,它就会颠倒读取它们的顺序。
非常聪明的解决方案!
@tom10 是的,它很聪明,尽管平心而论,这是别人的聪明:我以设计打印机管道为生,这种字节摆弄或多或少是我们 (HP) 产品中的标准程序.【参考方案2】:
最快的方法可能是将其保存在 numpy 中:
from numpy import *
x = array([211*2**16 + 11*2**8 + 7]) # test data
b, g, r = bitwise_and(x, 255), bitwise_and(right_shift(x, 8), 255), bitwise_and(right_shift, 16), 255)
print r, g, b
(array([211]), array([11]), array([7]))
【讨论】:
【参考方案3】:rgbs = [((x&0xff0000)>>16,(x&0xff00)>>8,x&0xff) for x in values]
至少我认为...
afaik 上面的公式也可以写成
BufferedRGB = RED<<16 + GREEN << 8 + BLUE
red,green,blue = 0xFF,0x99,0xAA
red<<16 + green << 8 + blue #= 0xFF99AA (buffered into one value)
#apply a bitmask to get colors back
red = (0xFF99AA & 0xFF0000) >> 16 # = 0xFF
green = (0xFF99AA & 0xFF00) >> 8 # = 0x99
blue = 0xFF99AA & 0xFF # = 0xAA
这对我来说更具可读性并且清楚发生了什么
【讨论】:
【参考方案4】:一种方法是
Red = BufferedImage / 2**16
Green = (BufferedImage % 2**16) / 2**8
Blue = (BufferedImage % 2**8)
但是,我怀疑这是最优雅(Pythonic?)或最快的方式。
【讨论】:
以上是关于在 Python 中将单个整数像素数组转换为 RGB 三元组的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Java 中将 getRGB(x,y) 整数像素转换为 Color(r,g,b,a)?