Welcome back to the AI on the Edge class series! In this lesson, we are diving deep into some of the most critical foundational skills you need when working with video streams on edge devices: Resizing, Moving, Converting, and Tiling video frames using OpenCV.
When you are developing real-world AI applications on the edge, you rarely just display a single camera feed. You often need to manipulate frames to feed them into your AI models, look at grayscale versions for edge detection, or arrange multiple windows on your desktop neatly so you can monitor your data visually.
If you want to follow along exactly as we do in the video, make sure you have your Raspberry Pi 5 set up with your Camera Module.
What We Cover in This Lesson
-
Fixed FPS Estimation: We continue using our robust low-pass filter formula to track smooth, non-jittery frames-per-second data directly on the video frame.
-
Creating Named Windows: Understanding how
cv2.namedWindow()combined withcv2.WINDOW_GUI_NORMALgives you absolute programmatic control over the placement of your displays. -
Resizing & Moving Windows: How to accurately position multiple OpenCV windows on your screen using specific coordinates while accounting for operating system taskbars and window decorative margins.
-
Frame Manipulation: Using
cv2.resize()to scale down video frames andcv2.cvtColor()to transform the color space from BGR to grayscale. -
Window Tiling: Arranging a main camera view, a scaled-down color view, and a scaled-down grayscale view in a perfect grid layout on your desktop.
The Complete Lesson 20 Code
Below is the complete Python code we developed during this lesson. It sets up your hardware camera stream, calculates running performance metrics, processes three distinct variations of the video feed, and tiles them cleanly on your screen.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
import cv2 import time from picamera2 import Picamera2 piCam = Picamera2() W=640 H=360 tStart = time.time() fps = 0 RES = (W,H) piCam.preview_configuration.main.size = RES piCam.preview_configuration.main.format = "RGB888" piCam.preview_configuration.controls.FrameRate=60 piCam.preview_configuration.align() piCam.configure("preview") piCam.start() textLowerLeft = (int(W*.01),int(H*.05)) fontFace = cv2.FONT_HERSHEY_SIMPLEX fontThickness = int(W/425) fontScale = H*.0015 fontColor = (0,0,255) topBar = 65 windowWaste = 25 cv2.namedWindow("Camera", cv2.WINDOW_GUI_NORMAL) cv2.resizeWindow("Camera", W, H) cv2.moveWindow("Camera",0,topBar) cv2.namedWindow("Camera Small", cv2.WINDOW_GUI_NORMAL) cv2.resizeWindow("Camera Small", int(W/2), int(H/2)) cv2.moveWindow("Camera Small",0,topBar+windowWaste+H) cv2.namedWindow("Gray Small", cv2.WINDOW_GUI_NORMAL) cv2.resizeWindow("Gray Small", int(W/2), int(H/2)) cv2.moveWindow("Gray Small",int(W/2),topBar+windowWaste+H) while True: deltaT = time.time() - tStart tStart=time.time() fps = fps*.95 + (1/deltaT)*.05 frame= piCam.capture_array() frame=cv2.flip(frame,-1) frameSmall=cv2.resize(frame,(int(W/2),int(H/2))) frameGraySmall = cv2.cvtColor(frameSmall,cv2.COLOR_BGR2GRAY) myText = "FPS: "+str(round(fps,1)) cv2.putText(frame,myText,textLowerLeft,fontFace,fontScale,fontColor,fontThickness) cv2.imshow("Camera", frame) cv2.imshow("Camera Small",frameSmall) cv2.imshow("Gray Small",frameGraySmall) if cv2.waitKey(1)==ord('q'): break cv2.destroyAllWindows() print('Program Terminated') |