Как правильно преобразовать трехмерный массив в непрерывные байты RGB
Я пытаюсь преобразовать 3d-массив, возвращаемый 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", чтобы получить pixbuf из arr, возвращенного функцией "ndarr2rgb" выше. И я использую "image.set_from_pixbuf" для отображения изображения. Но я получил следующий результат:Это похоже на шумную зону, поэтому, пожалуйста, помогите мне решить мою проблему, спасибо.
4 ответа
Возможно, проблема в том, что 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)
Из-за изменений в 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
Вам не нужно писать временный файл для того, чтобы workaroud 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)