如何实现摄像头流图像保存为视频并在TFT LCD实时预览?
Got it, let's fix this for you! The core issue here is that your current script treats each camera frame as an isolated io.BytesIO object instead of streaming consecutive frames into a proper video container. To handle both TFT preview and video recording simultaneously, we'll use a video writer library (like OpenCV's VideoWriter) to persist frames while sending the same data to your TFT screen.
Solution Overview
We'll break this into 3 key steps:
- Initialize a video writer with matching camera specs (resolution, framerate, encoding)
- In each loop iteration, capture the frame, write it to the video file first
- Convert the frame to a format compatible with your TFT screen and display it
Example Code (Using OpenCV + PIL for TFT)
This assumes you're using a standard USB camera and Adafruit's TFT library—adjust pin numbers and libraries to match your hardware:
import cv2 from PIL import Image # Replace with your TFT driver library (adjust pins for your setup) import Adafruit_ILI9341 as TFT import Adafruit_GPIO as GPIO import Adafruit_GPIO.SPI as SPI # Initialize TFT LCD screen DC_PIN = 23 RST_PIN = 24 SPI_PORT = 0 SPI_DEVICE = 0 disp = TFT.ILI9341(DC_PIN, rst=RST_PIN, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=64000000)) disp.begin() disp.clear() # Initialize camera and video writer cap = cv2.VideoCapture(0) # 0 = default camera if not cap.isOpened(): print("Failed to open camera") exit() # Get camera native specs fps = cap.get(cv2.CAP_PROP_FPS) frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # Set up video writer (MP4 format with mp4v encoding) fourcc = cv2.VideoWriter_fourcc(*'mp4v') video_out = cv2.VideoWriter('camera_recording.mp4', fourcc, fps, (frame_width, frame_height)) try: while True: # Capture a single frame ret, frame = cap.read() if not ret: print("Failed to grab frame—exiting") break # 1. Write frame to video file first video_out.write(frame) # 2. Convert frame for TFT display (OpenCV uses BGR, PIL needs RGB) frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) tft_img = Image.fromarray(frame_rgb) # Resize to match TFT resolution (adjust to your screen's dimensions) tft_img = tft_img.resize((disp.width, disp.height), Image.Resampling.LANCZOS) # Display on TFT disp.display(tft_img) # Exit loop when 'q' is pressed if cv2.waitKey(1) & 0xFF == ord('q'): break finally: # Clean up resources to avoid leaks cap.release() video_out.release() cv2.destroyAllWindows() disp.clear()
Key Details to Note
- Video Encoding: Use
mp4vfor MP4 files, orXVIDfor AVI. If you get encoding errors, tryavc1(H.264) if your system supports it. - Frame Format Conversion: OpenCV captures frames in BGR format, but PIL (used by most TFT libraries) expects RGB—don't skip the
cv2.cvtColorstep. - Resource Management: The
try-finallyblock ensures we always release the camera and video writer, even if the script crashes. - Performance: If your TFT screen has a lower resolution than the camera, resize the frame before displaying to reduce processing load.
For Raspberry Pi Picamera Users
If you're using the Pi's native camera module, here's a modified version using picamera library:
from picamera import PiCamera from picamera.array import PiRGBArray import cv2 from PIL import Image import Adafruit_ILI9341 as TFT import Adafruit_GPIO as GPIO import Adafruit_GPIO.SPI as SPI # Initialize TFT (same as before) DC_PIN = 23 RST_PIN = 24 SPI_PORT = 0 SPI_DEVICE = 0 disp = TFT.ILI9341(DC_PIN, rst=RST_PIN, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=64000000)) disp.begin() disp.clear() # Initialize Pi Camera camera = PiCamera() camera.resolution = (640, 480) camera.framerate = 30 raw_capture = PiRGBArray(camera, size=(640, 480)) # Set up video writer fourcc = cv2.VideoWriter_fourcc(*'mp4v') video_out = cv2.VideoWriter('pi_camera_recording.mp4', fourcc, 30, (640, 480)) try: for frame in camera.capture_continuous(raw_capture, format="bgr", use_video_port=True): # Get frame data img = frame.array # Write to video video_out.write(img) # Convert and display on TFT img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) tft_img = Image.fromarray(img_rgb).resize((disp.width, disp.height), Image.Resampling.LANCZOS) disp.display(tft_img) # Clear buffer for next frame raw_capture.truncate(0) # Exit on 'q' press if cv2.waitKey(1) & 0xFF == ord('q'): break finally: camera.close() video_out.release() cv2.destroyAllWindows() disp.clear()
内容的提问来源于stack exchange,提问作者haykp

