Skip to content

Commit 0d76a2c

Browse files
committed
Add an example of using cscore to overlay something on an image
1 parent d05973b commit 0d76a2c

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

CSCoreAnnotation/robot.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) FIRST and other WPILib contributors.
4+
# Open Source Software; you can modify and/or share it under the terms of
5+
# the WPILib BSD license file in the root directory of this project.
6+
#
7+
8+
9+
import threading
10+
import time
11+
12+
import cv2
13+
import numpy as np
14+
15+
import wpilib
16+
from cscore import CameraServer
17+
18+
19+
class MyRobot(wpilib.TimedRobot):
20+
"""
21+
This is a sample program showing how to overlay a red rectangle on a camera feed.
22+
The rectangle's position is controlled from robot code during teleop.
23+
This requires at least one USB camera connected to the robot.
24+
Use a dashboard client to view the camera stream. Two streams are available:
25+
- "Annotated Stream": The camera feed with the red rectangle overlay.
26+
- "<your camera name>": The raw camera feed without any annotations.
27+
"""
28+
29+
def robotInit(self):
30+
"""Robot initialization function"""
31+
32+
CameraServer.enableLogging()
33+
34+
# State variables - this will be the center position of the rectangle, in units of pixels.
35+
self.rectX = 0
36+
self.rectY = 0
37+
38+
# Start reading data from the camera, and serving the raw stream
39+
self.camera = CameraServer.startAutomaticCapture()
40+
self.camera.setResolution(640, 480)
41+
42+
# Record a reference to the video source (which should be the first camera connected):
43+
self.source = self.camera.enumerateSources()
44+
45+
# Set up a second server to provide an annotated stream
46+
self.cvSink = CameraServer.getVideo()
47+
self.outputStream = CameraServer.putVideo("Annotated Stream", 640, 480)
48+
49+
# Allocate memory for creating the annotated image.
50+
self.img = np.zeros((480, 640, 3), dtype=np.uint8)
51+
52+
# Start the background thread for image processing
53+
self.processingThread = threading.Thread(target=self.processImages, daemon=True)
54+
self.processingThread.start()
55+
56+
57+
def processImages(self):
58+
"""Thread to read information from the camera, and provide the overlaid image"""
59+
60+
while True:
61+
# Grab a frame from the camera
62+
frameTime, self.img = self.cvSink.grabFrame(self.img)
63+
64+
if frameTime == 0:
65+
# If there's an error, skip processing
66+
print(self.cvSink.getError())
67+
continue
68+
69+
# Draw a red box on the image
70+
width = 50
71+
height= 50
72+
topLeft = (int(self.rectX-width/2), int(self.rectY-height/2))
73+
botRight = (int(self.rectX+width/2), int(self.rectY+height/2))
74+
colorBGR = (0, 0, 255)
75+
lineWidth = 2
76+
cv2.rectangle(self.img,
77+
topLeft,
78+
botRight,
79+
colorBGR,
80+
lineWidth)
81+
82+
# Publish the annotated image
83+
self.outputStream.putFrame(self.img)
84+
85+
# Yield execution to other threads
86+
time.sleep(0.001)
87+
88+
def teleopPeriodic(self):
89+
# Update the rectangle position.
90+
# For this example, we'll use a joystick as input.
91+
joystick = wpilib.Joystick(0)
92+
self.rectX += joystick.getX() * 5
93+
self.rectY += joystick.getY() * 5
94+
95+
# Ensure the rectangle stays within bounds
96+
self.rectX = max(0, min(self.rectX, 640))
97+
self.rectY = max(0, min(self.rectY, 480))

0 commit comments

Comments
 (0)