如何正确将3D数组转换为连续的RGB字节
我正在尝试将cv2.imread返回的三维数组转换为连续的RGB字节数组,这样才能在GTK中显示。下面是我的转换代码:
def ndarr2rgb(img):
r_arr = img[:, :, 0].ravel() # read channel
g_arr = img[:, :, 1].ravel() # green channel
b_arr = img[:, :, 2].ravel() # blue channel
numItems = img.shape[0] * img.shape[1] * img.shape[2] # number of entries in byte array
z = img.shape[2] # z dimension, always equal to 3
arr = np.zeros((numItems, 1))
# to fill the byte array with r,g,b channel
for i in xrange(0, numItems):
if i % z == 0:
arr[i] = r_arr[i/z]
if i % z == 1:
arr[i] = g_arr[i/z]
if i % z == 2:
arr[i] = b_arr[i/z]
return arr
在我的代码中,我首先分别获取三个维度的数据,分别存入r_arr、g_arr和b_arr,然后按照RGB的顺序把这些值放到一个叫'arr'的数组里。所以在循环结束后,数组'arr'的内容会像这样:'r0, g0, b0, r1, g1, b1, ...'。
接着,我使用"GdkPixbuf.Pixbuf.new_from_data"这个函数,从上面提到的"ndarr2rgb"函数返回的'arr'数组中获取pixbuf。然后我用"image.set_from_pixbuf"来显示这个图像。但是我得到了以下的结果:
看起来有一些噪点区域,所以请帮我解决这个问题,谢谢。
4 个回答
-1
你不需要写一个临时文件来解决 GdkPixbuf.Pixbuf.new_from_data 处理内存不正确的问题,[1],你可以使用pnm图像格式[2]:
from gi.repository import GdkPixbuf
import cv2
filename = './file.png'
# read and convert image from BGR to RGB (pnm uses RGB)
im = cv2.cvtColor(cv2.imread(filename), cv2.COLOR_BGR2RGB)
# get image dimensions (depth is not used)
height, width, depth = im.shape
pixl = GdkPixbuf.PixbufLoader.new_with_type('pnm')
# P6 is the magic number of PNM format,
# and 255 is the max color allowed, see [2]
pixl.write("P6 %d %d 255 " % (width, height) + im.tostring())
pix = pixl.get_pixbuf()
pixl.close()
在这个解决方法之后,你可以使用:image.set_from_pixbuf( pix )
参考资料:
1
由于io、PIL和/或GdkPixbuf的变化,我在弄明白这个问题时遇到了困难,尽管我阅读了很多建议。最后,我找到了一种比较简单的解决方案:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf
def array2pixbuf(width, height, arr):
# pnm
header = b"P6 %d %d 255 " % (width, height)
# flatten and convert to an array of bytes (not a bytearray!)
data = bytes(colour for pixel in arr for colour in pixel)
loader = GdkPixbuf.PixbufLoader.new()
loader.write(header)
loader.write(data)
pixbuf = loader.get_pixbuf()
loader.close()
return pixbuf
3
这个问题可能是因为 GdkPixbuf.Pixbuf.new_from_data 这个函数没有正确管理内存,具体可以参考 [1]。一个解决办法是把数据写入一个临时文件,然后使用 GdkPixbuf.Pixbuf.new_from_file [2] 来处理。下面是一个使用 PIL 的示例:
from PIL import Image
image = Image.frombytes('RGB', (width, height), data)
image.save(filename)
pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
3
只需这样做:
all_in_one_row = np.reshape(img,(-1))