如何将OpenCVcv2图像BGR和BGRA转换为pygame.Surface对象

问题描述

我从OpenCV / opencv-pythonnumpy.array)创建了图像,并希望将它们转换为pygame.Surface对象:

def cv2ImagetoSurface(cv2Image):

    pygameSurface = # ? create from "cv2Image"

    return pygameSurface 

surface = cv2ImagetoSurface(cv2Image)

有些图像有3个通道( BGR ),有些图像还具有alpha通道( BGRA )。我需要在cv2ImagetoSurface中做什么才能将其中一种格式的图像转换为pygame.Surface对象?

解决方法

numpy.arrayshape属性是每个维度中元素的数量。第一个元素是高度,第二个元素是宽度,第三个元素是通道数。
pygame.Surface可以生成pygame.image.frombuffer。第一个参数可以是numpy.array,第二个参数可以是格式(RGBRGBA)。

通过切片获取pygame.Surface对象的大小( widht height ):

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更改阵列的形状,并且必须使用numpy.repeat将灰色通道扩展为红绿色和蓝色通道:>

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 应该使用convert或{ {3}}:

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],axis = 2)
        format = 'RGB'
    else:
        format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
        cv2Image[:,0]]
    surface = pygame.image.frombuffer(cv2Image.flatten(),format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

最小示例:

convert_alpha

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