Как преобразовать изображение OpenCV (cv2) (BGR и BGRA) в объект pygame.Surface

Я создал изображения из OpenCV / opencv-python (_ 1_), и я хочу преобразовать их в pygame.Surface объект:

def cv2ImageToSurface(cv2Image):

    pygameSurface = # ? create from "cv2Image"

    return pygameSurface 

surface = cv2ImageToSurface(cv2Image)

Некоторые изображения имеют 3 канала (BGR), а некоторые изображения также имеют альфа-канал (BGRA). Что мне нужно сделать в cv2ImageToSurface, чтобы преобразовать изображения с одним из форматов в pygame.Surface < / a> объект?


person Rabbid76    schedule 03.10.2020    source источник


Ответы (1)


Атрибут shape в numpy.array - это количество элементов в каждое измерение. Первый элемент - это высота, второй - ширина, а третий - количество каналов.
A _ 3_ можно создать с помощью pygame.image.frombuffer . Первым аргументом может быть numpy.array, а вторым аргументом - формат (RGB или RGBA).

Получите размер (widht, height) для объекта pygame.Surface, нарезав:

size = cv2Image.shape[1::-1]

Определите целевой формат для объекта pygame.Surface в зависимости от третьего канала:

format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'

Поскольку исходный формат - BGR или BGRA, а целевой формат - RGB или RGBA, красный и синий каналы надо поменять местами:

cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]

В случае изображения в оттенках серого необходимо изменить форму массива с помощью numpy.reshape, а серый канал должен быть расширен до красно-зеленого и синего цветовых каналов с помощью _ 14_:

cv2Image = np.repeat(cv2Image.reshape(size[1], size[0], 1), 3, axis = 2)

С его данными объект pygame.Surface может быть сгенерирован pygame.image.frombuffer:

surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)

Чтобы изображение имело тот же формат пикселей, что и экран Surface, и для оптимальной производительности, Surface следует преобразовать с помощью _ 19_ или _ 20_:

surface = surface.convert_alpha() if format == 'RGBA' else surface.convert()

Полная функция cv2ImageToSurface:

def cv2ImageToSurface(cv2Image):
    if cv2Image.dtype.name == 'uint16':
        cv2Image = (cv2Image / 256).astype('uint8')
    size = cv2Image.shape[1::-1]
    if len(cv2Image.shape) == 2:
        cv2Image = np.repeat(cv2Image.reshape(size[1], size[0], 1), 3, axis = 2)
        format = 'RGB'
    else:
        format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
        cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
    surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

Минимальный пример:

import os
import pygame
import cv2
import numpy as np

def cv2ImageToSurface(cv2Image):
    if cv2Image.dtype.name == 'uint16':
        cv2Image = (cv2Image / 256).astype('uint8')
    size = cv2Image.shape[1::-1]
    if len(cv2Image.shape) == 2:
        cv2Image = np.repeat(cv2Image.reshape(size[1], size[0], 1), 3, axis = 2)
        format = 'RGB'
    else:
        format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
        cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
    surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

cv2Image1 = cv2.imread('woodtiles.jpg', cv2.IMREAD_GRAYSCALE)
cv2Image2 = cv2.imread('woodtiles.jpg', cv2.IMREAD_UNCHANGED)
cv2Image3 = cv2.imread('Apple1-256.png', cv2.IMREAD_UNCHANGED)
pygameSurface1 = cv2ImageToSurface(cv2Image1)
pygameSurface2 = cv2ImageToSurface(cv2Image2)
pygameSurface3 = cv2ImageToSurface(cv2Image3)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill(0)
    window.blit(pygameSurface1, pygameSurface1.get_rect(topleft = window.get_rect().inflate(-10, -10).topleft))
    window.blit(pygameSurface2, pygameSurface2.get_rect(center = window.get_rect().center))
    window.blit(pygameSurface3, pygameSurface3.get_rect(bottomright = window.get_rect().inflate(-10, -10).bottomright))
    pygame.display.flip()

pygame.quit()
person Rabbid76    schedule 03.10.2020