Search code examples
pythonopencvpygamewebcamblit

blit opencv camera capture with pygame throws TypeError: argument 1 must be pygame.Surface, not cv2.VideoCapture


I'm new to pygame and never used it before and wanted to know how I can blit or display my webcam into the surface by using pygame and opencv but I keep getting the message:

Traceback (most recent call last):
 File "<filename>.py", line 51, in <module>      
   mainWindow()
 File "<filename>.py", line 43, in mainWindow    
   draw_window()
 File "<filename>.py", line 24, in draw_window   
   WINDOW.blit(camera)
TypeError: argument 1 must be pygame.Surface, not cv2.VideoCapture
import pygame 
import cv2

pygame.init()

# setting the width and height of the window
WIDTH, HEIGHT = 1280, 720
WINDOW = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("name me")

# background color 
color = (0, 0, 0)

# 0 is the built in webcam
camera = cv2.VideoCapture(0)
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 700)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 900)

def draw_window():
    # background color 
    WINDOW.fill((color))

    # display object onto the surface (screen)
    WINDOW.blit(camera)

    # update the display
    pygame.display.update()


FPS = 30
def mainWindow():
    # keeping the window open 
    run = True 
    clock = pygame.time.Clock()
    while run: 
        # capping it at the set frame rate 
        clock.tick(FPS)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

        draw_window()


    # closing the window 
    pygame.quit()


# main #
mainWindow()

Solution

  • You can only blit a pygame.Surface. Therefore you have to get frame by frame from the camera and convert it to a pygame.Surface object.

    Grab a camera frame:

    success, camera_image = capture.read()
    

    Convert the camera frame to a pygame.Surface object using pygame.image.frombuffer:

    camera_surf = pygame.image.frombuffer(
                  camera_image.tobytes(), camera_image.shape[1::-1], "BGR")
    

    Do that in the function draw_window:

    def draw_window():
        # background color 
        WINDOW.fill((color))
        
        # display object onto the surface (screen)
        success, camera_image = camera.read()
        if success:
              camera_surf = pygame.image.frombuffer(camera_image.tobytes(), camera_image.shape[1::-1], "BGR")
              WINDOW.blit(camera_surf, (0, 0))
        
        # update the display
        pygame.display.update()
    

    Also see python pygame.camera.init() NO vidcapture and PyGameExamplesAndAnswers - Camera and Video


    Alternative but minimal example:

    import pygame
    import cv2
    
    capture = cv2.VideoCapture(0)
    success, camera_image = capture.read()
    
    window = pygame.display.set_mode(camera_image.shape[1::-1])
    clock = pygame.time.Clock()
    
    run = success
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        
        success, camera_image = capture.read()
        if success:
            camera_surf = pygame.image.frombuffer(
                camera_image.tobytes(), camera_image.shape[1::-1], "BGR")
        else:
            run = False
        window.blit(camera_surf, (0, 0))
        pygame.display.flip()
    
    pygame.quit()
    exit()