Video writing in OpenCV turns processed frames, generated graphics, or annotated camera output into a file that other tools can replay. The VideoWriter object owns the output path, codec code, frame rate, and frame size, so those values need to match every frame sent to it.
The Python script writes generated NumPy frames to an .mp4 file with the mp4v FourCC. Each frame is a color image with the same width and height passed to cv.VideoWriter, and the script checks isOpened() before writing.
Codec support comes from the video backend compiled into the local OpenCV build. Reopening the output with cv.VideoCapture confirms that the file was finalized, the frame count is readable, and the saved dimensions match the writer settings.
Steps to write a video file with OpenCV:
- Save the video writer script.
- write_video.py
#!/usr/bin/env python3 from pathlib import Path import cv2 as cv import numpy as np output_path = Path("output/generated-motion.mp4") width, height = 640, 360 fps = 24.0 frame_count = 72 fourcc_label = "mp4v" fourcc = cv.VideoWriter_fourcc(*fourcc_label) output_path.parent.mkdir(parents=True, exist_ok=True) writer = cv.VideoWriter(str(output_path), fourcc, fps, (width, height)) if not writer.isOpened(): raise SystemExit(f"Could not open VideoWriter for: {output_path}") for index in range(frame_count): frame = np.zeros((height, width, 3), dtype=np.uint8) frame[:] = (34, 42, 58) progress = index / max(frame_count - 1, 1) center_x = int(70 + progress * (width - 140)) center_y = height // 2 color = (40, 180 + index % 60, 245) cv.circle(frame, (center_x, center_y), 42, color, -1) cv.putText( frame, f"Frame {index + 1:02d}/{frame_count}", (36, 62), cv.FONT_HERSHEY_SIMPLEX, 1.1, (245, 245, 245), 2, cv.LINE_AA, ) cv.putText( frame, "OpenCV VideoWriter", (36, height - 34), cv.FONT_HERSHEY_SIMPLEX, 0.85, (215, 230, 255), 2, cv.LINE_AA, ) writer.write(frame) writer.release() capture = cv.VideoCapture(str(output_path)) if not capture.isOpened(): raise SystemExit(f"Could not reopen video: {output_path}") saved_frames = int(capture.get(cv.CAP_PROP_FRAME_COUNT)) saved_fps = capture.get(cv.CAP_PROP_FPS) saved_width = int(capture.get(cv.CAP_PROP_FRAME_WIDTH)) saved_height = int(capture.get(cv.CAP_PROP_FRAME_HEIGHT)) ok, first_frame = capture.read() capture.release() if not ok or first_frame is None: raise SystemExit(f"Could not read first frame from: {output_path}") size_kib = output_path.stat().st_size / 1024 print(f"wrote: {output_path}") print(f"fourcc: {fourcc_label}") print(f"frames written: {frame_count}") print(f"frames read back: {saved_frames}") print(f"fps: {saved_fps:.1f}") print(f"size: {saved_width}x{saved_height}") print(f"first frame: {first_frame.shape[1]}x{first_frame.shape[0]}x{first_frame.shape[2]}") print(f"file size: {size_kib:.1f} KiB")
For project frames, keep width and height equal to the actual frame shape. Common FFMPEG paths handle even dimensions most predictably for MP4 output.
- Run the script to write and verify the video.
$ python3 write_video.py wrote: output/generated-motion.mp4 fourcc: mp4v frames written: 72 frames read back: 72 fps: 24.0 size: 640x360 first frame: 640x360x3 file size: 142.4 KiB
The exact file size can change with the backend, encoder settings, and frame content. Success means the writer opened, the read-back frame count matches frame_count, and the reported size matches width by height.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.