【问题标题】:How to correctly covert 3d array into continguous rgb bytes如何正确地将 3d 数组转换为连续的 rgb 字节
【发布时间】:2014-07-26 14:23:01
【问题描述】:

我正在尝试将 cv2.imread 返回的 3d 数组转换为连续的 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”来显示图像。但我得到了以下结果:
好像有一些嘈杂的地方,所以请帮我解决我的问题,谢谢。

【问题讨论】:

标签: python opencv gtk pygtk pygobject


【解决方案1】:

只是做:

all_in_one_row = np.reshape(img,(-1))

【讨论】:

  • 谢谢,这个方法不错。
【解决方案2】:

问题可能是由于 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)
  1. https://bugzilla.gnome.org/show_bug.cgi?id=721497
  2. http://lazka.github.io/pgi-docs/api/GdkPixbuf-2.0/classes/Pixbuf.html#GdkPixbuf.Pixbuf.new_from_file

【讨论】:

  • 非常感谢,虽然这个方法看起来不那么直接,但至少可以工作
【解决方案3】:

您无需编写临时文件即可解决 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. https://bugzilla.gnome.org/show_bug.cgi?id=732297
  2. http://en.wikipedia.org/wiki/Netpbm_format

【讨论】:

    【解决方案4】:

    由于 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
    

    【讨论】:

    • 这是唯一对我完全有效的东西。虽然我使用 arr.flatten().tobytes() 而不是 data 作为 numpy 数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-15
    • 2018-04-19
    • 2022-01-07
    • 2021-10-30
    相关资源
    最近更新 更多