如何将OpenCV图像(BGR和BGRA)转换为pygame.Surface对象?

3
我使用 OpenCV/opencv-python(numpy.array)创建了图像,我想将它们转换为 pygame.Surface 对象。
def cvImageToSurface(cv2Image):

    pygameSurface = # ? create from "cvImage"

    return pygameSurface 

surface = cvImageToSurface(cv2Image)

一些图像具有三个通道(BGR),而另一些图像还具有一个 alpha 通道(BGRA)。在 cvImageToSurface 中,我需要做什么来将这些格式之一的图像转换为 pygame.Surface 对象?
1个回答

3
shape 属性是 numpy.array 中每个维度的元素数量。第一个元素是高度,第二个元素是宽度,第三个元素是通道数。 可以通过 pygame.image.frombuffer 生成一个 pygame.Surface。第一个参数可以是一个 numpy.array,第二个参数是格式(RGBRGBA)。
通过切片获取 pygame.Surface 对象的尺寸(宽度高度)。
size = cvImage.shape[1::-1]

根据第三通道确定pygame.Surface对象的目标格式。
format = 'RGBA' if cvImage.shape[2] == 4 else 'RGB'

由于源格式为BGR或BGRA,但目标格式为RGB或RGBA,因此需要交换红色和蓝色通道。
cvImage[:, :, [0, 2]] = cvImage[:, :, [2, 0]]

在灰度图像的情况下,必须使用numpy.reshape来改变数组的形状,并使用numpy.repeat将灰色通道扩展为红绿蓝三个颜色通道:
cvImage = np.repeat(cvImage.reshape(size[1], size[0], 1), 3, axis = 2)

使用他的数据,可以通过pygame.image.frombuffer生成pygame.Surface对象。
surface = pygame.image.frombuffer(cvImage.flatten(), size, format)

为了确保图像具有与显示表面相同的像素格式,并获得最佳性能,应使用convertconvert_alpha将表面转换为所需格式。
surface = surface.convert_alpha() if format == 'RGBA' else surface.convert()

完整的函数 cvImageToSurface 的功能:
def c2ImageToSurface(cvImage):
    if cvImage.dtype.name == 'uint16':
        cvImage = (cvImage / 256).astype('uint8')
    size = cvImage.shape[1::-1]
    if len(cvImage.shape) == 2:
        cvImage = np.repeat(cvImage.reshape(size[1], size[0], 1), 3, axis = 2)
        format = 'RGB'
    else:
        format = 'RGBA' if cvImage.shape[2] == 4 else 'RGB'
        cvImage[:, :, [0, 2]] = cvImage[:, :, [2, 0]]
    surface = pygame.image.frombuffer(cvImage.flatten(), size, format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

简单示例:

import os
import pygame
import cv2 as cv
import numpy as np

def cvImageToSurface(cvImage):
    if cvImage.dtype.name == 'uint16':
        cvImage = (cvImage / 256).astype('uint8')
    size = cvImage.shape[1::-1]
    if len(cvImage.shape) == 2:
        cvImage = np.repeat(cvImage.reshape(size[1], size[0], 1), 3, axis = 2)
        format = 'RGB'
    else:
        format = 'RGBA' if cvImage.shape[2] == 4 else 'RGB'
        cvImage[:, :, [0, 2]] = cvImage[:, :, [2, 0]]
    surface = pygame.image.frombuffer(cvImage.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()

cvImage1 = cv.imread('woodtiles.jpg', cv.IMREAD_GRAYSCALE)
cvImage2 = cv.imread('woodtiles.jpg', cv.IMREAD_UNCHANGED)
cvImage3 = cv.imread('Apple1-256.png', cv.IMREAD_UNCHANGED)
pygameSurface1 = cvImageToSurface(cvImage1)
pygameSurface2 = cvImageToSurface(cvImage2)
pygameSurface3 = cvImageToSurface(cvImage3)

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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接