问题描述
我从OpenCV / opencv-python(numpy.array
)创建了图像,并希望将它们转换为pygame.Surface
对象:
def cv2ImagetoSurface(cv2Image):
pygameSurface = # ? create from "cv2Image"
return pygameSurface
surface = cv2ImagetoSurface(cv2Image)
有些图像有3个通道( BGR ),有些图像还具有alpha通道( BGRA )。我需要在cv2ImagetoSurface
中做什么才能将其中一种格式的图像转换为pygame.Surface
对象?
解决方法
numpy.array
的shape
属性是每个维度中元素的数量。第一个元素是高度,第二个元素是宽度,第三个元素是通道数。pygame.Surface
可以生成pygame.image.frombuffer
。第一个参数可以是numpy.array
,第二个参数可以是格式(RGB
或RGBA
)。
通过切片获取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()
最小示例:
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()