Search code examples
pythonopencvpygamegoogle-colaboratoryvideo-editing

How to display the text on the video with Pygame and Opencv on Google Collab?


I'm trying to display a text on a video with Pygame and OpenCV on Google Collab, but the text isn't displayed on the output. The output file still the same as the original video. In the OpenCV view (cv2_imshow(frame_with_text)) the text also cannot be seen.

import pygame
import cv2
from google.colab.patches import cv2_imshow

# Upload video
cap = cv2.VideoCapture(os.path.join('sample_data', 'BACKGROUND.mp4'))

# Get video information
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = 30 #cap.get(cv2.CAP_PROP_FPS)
frames_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
duration = frames_count / fps

# Export video
directory = r'sample_data'
output_file = os.path.join(directory, f'teste.mp4')
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('/content/drive/MyDrive/teste.mp4', fourcc, fps, (width, height))

# Create a pygame suface with the same dimention as the video
pygame.init()
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()

def edit():
  while cap.isOpened():
      ret, frame = cap.read()

      if not ret:
          break
      
      font = pygame.font.SysFont('Arial', 50)
      text = "This is a test"
      pista_surface = font.render(text, True, (255, 255, 255))
      screen.blit(pista_surface, (94, 479))
      # Actual time in seconds
      current_time = cap.get(cv2.CAP_PROP_POS_FRAMES) / fps

      # Convert OpenCV frame to a pygame surface
      pygame_frame = pygame.surfarray.make_surface(frame.swapaxes(0, 1))

      # Update Pygame screen
      pygame.display.flip()

      # Convert Pygame surface to a OpenCV frame
      frame_with_text = pygame.surfarray.array3d(pygame_frame).swapaxes(0, 1)

      # Save frame to the output
      out.write(frame_with_text)

      # Visualize frame 
      cv2_imshow(frame_with_text)

      if cv2.waitKey(1) & 0xFF == ord('q'):
        break

      # Set the same FPS as the original video
      clock.tick(fps)

      # Verify if the end of the video was reached
      if current_time >= frames_count:
        break

  cap.release()
  out.release()
  cv2.destroyAllWindows()


edit()

I tried moviepy but I got the image magic error on Goggle Collab, therefore I'm using pygame this way.I have tried to install image magic, but all the solutions I have found didn't worked.


Solution

  • You must draw the text on the surface that is written to the output and you need to blit that surface on the Pygame screen

    def edit():
        while cap.isOpened():
            # [...]
    
            # Convert OpenCV frame to a pygame surface
            pygame_frame = pygame.surfarray.make_surface(frame.swapaxes(0, 1))
    
            # blit text on surface
            pygame_frame.blit(pista_surface, (94, 479))
    
            # blit surface on Pygame screen
            screen.blit(pygame_frame, (0, 0))
    
            # Update Pygame screen
            pygame.display.flip()
    
            # Convert Pygame surface to a OpenCV frame
            frame_with_text = pygame.surfarray.array3d(pygame_frame).swapaxes(0, 1)
    
            # Save frame to the output
            out.write(frame_with_text)
    
            # [...]