How do I convert an OpenCV (cv2) image (BGR and BGRA) to a pygame.Surface object

后端 未结 1 1327
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-07 05:05

I created images from OpenCV/opencv-python (numpy.array) and I want to convert them to a pygame.Surface object:

def cv2         


        
相关标签:
1条回答
  • 2020-12-07 06:02

    The shape attribute of a numpy.array is the number of elements in each dimension. The first element is the height, the second the width and the third the number of channels.
    A pygame.Surface can be generated by pygame.image.frombuffer. The 1st argument can be a numpy.array and the 2nd argument is the format (RGB or RGBA).

    Get the size (widht, height) for the pygame.Surface object by slicing:

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

    Determine the target format for the pygame.Surface object, depending on the third channel:

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

    Since the source format is BGR or BGRA, but the target format is RGB or RGBA, the red and blue channels have to be swapped:

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

    In the case of a grayscale image, the shape of the array must be changed using numpy.reshape and the gray channel must be expanded to a red-green and blue color channel using numpy.repeat:

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

    With his data the pygame.Surface object can be generated by pygame.image.frombuffer:

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

    To ensure that the image has the same pixel format as the display Surface and for optimal performance, the Surface should be converted with either convert or convert_alpha:

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

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

    Minimal example:

    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()
    
    0 讨论(0)
提交回复
热议问题