-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: moving examples to an example folder in the root directory
- Loading branch information
1 parent
cfce3f2
commit 36f09fc
Showing
16 changed files
with
833 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package io.github.robotpy.cscore; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.lang.ProcessBuilder.Redirect; | ||
import java.nio.file.Files; | ||
import java.nio.file.Paths; | ||
import java.nio.file.StandardCopyOption; | ||
|
||
import edu.wpi.first.wpilibj.DriverStation; | ||
|
||
/** | ||
* Provides a way to launch an out of process Python robotpy-cscore based | ||
* camera service instance from a Java robot program. | ||
* | ||
* You must have Python and python36-robotpy-cscore installed, or this | ||
* just simply won't work. Refer to the RobotPy documentation for details. | ||
* | ||
* The python code should be a single file, and must compiled into your java | ||
* jar file. If your file was in the src directory as 'vision.py', you would | ||
* add this to the 'project' section of build.xml: | ||
*/ | ||
// <!-- add vision.py to JAR file --> | ||
// <target name="jar" depends="compile"> | ||
// <echo>[athena-jar] Making jar ${dist.jar}.</echo> | ||
// <mkdir dir="${dist.dir}" /> | ||
// <mkdir dir="${build.jars}" /> | ||
// | ||
// <echo>[athena-jar] Copying jars to ${build.jars}.</echo> | ||
// <copy todir="${build.jars}" flatten="true"> | ||
// <path refid="classpath.path"/> | ||
// </copy> | ||
// | ||
// <jar destfile="${dist.jar}" update="false"> | ||
// <manifest> | ||
// <attribute name="Main-Class" value="edu.wpi.first.wpilibj.RobotBase"/> | ||
// <attribute name="Robot-Class" value="${robot.class}"/> | ||
// <attribute name="Class-Path" value="."/> | ||
// </manifest> | ||
// | ||
// <fileset dir="${build.dir}" includes="**/*.class"/> | ||
// <fileset file="${src.dir}/vision.py"/> | ||
// | ||
// <zipgroupfileset dir="${build.jars}"/> | ||
// </jar> | ||
// </target> | ||
public class CameraServer { | ||
|
||
public static String visionPath = "/home/lvuser/vision.py"; | ||
private static boolean isAlive = false; | ||
private static boolean launched = false; | ||
|
||
/** | ||
* @return true if the vision process is (probably) alive | ||
*/ | ||
public static boolean isAlive() { | ||
return isAlive; | ||
} | ||
|
||
/** | ||
* Launches an embedded resource called "vision.py" which contains a | ||
* "main" function. | ||
*/ | ||
public static void startPythonVision() { | ||
startPythonVision("/vision.py", "main"); | ||
} | ||
|
||
/** | ||
* Call this function to launch a python vision program in an external | ||
* process. | ||
* | ||
* @param resource The resource built into the jar (see above), such as /vision.py | ||
* @param functionName The name of the function to call | ||
*/ | ||
public static void startPythonVision(String resource, String functionName) { | ||
// don't allow restart | ||
if (launched) { | ||
return; | ||
} | ||
|
||
launched = true; | ||
|
||
System.out.println("Launching python process from " + resource); | ||
|
||
try { | ||
// extract the resource and write it to vision.py | ||
InputStream is = CameraServer.class.getResourceAsStream(resource); | ||
if (is == null) { | ||
throw new IOException("Resource " + resource + " not found"); | ||
} | ||
|
||
Files.copy(is, Paths.get(visionPath), StandardCopyOption.REPLACE_EXISTING); | ||
|
||
// launch the process | ||
ProcessBuilder pb = new ProcessBuilder(); | ||
pb.command("/usr/local/bin/python3", "-m", "cscore", visionPath + ":" + functionName); | ||
|
||
// we open a pipe to it so that when the robot program exits, the child dies | ||
pb.redirectInput(Redirect.PIPE); | ||
|
||
// and let us see stdout/stderr | ||
pb.redirectOutput(Redirect.INHERIT); | ||
pb.redirectError(Redirect.INHERIT); | ||
|
||
final Process p = pb.start(); | ||
isAlive = true; | ||
|
||
Thread t = new Thread(()-> { | ||
try { | ||
p.waitFor(); | ||
} catch (InterruptedException e) { | ||
// empty | ||
} | ||
|
||
isAlive = false; | ||
}); | ||
t.setDaemon(true); | ||
t.start(); | ||
|
||
} catch (IOException e) { | ||
System.out.println("Error launching vision! " + e.toString()); | ||
//if (!DriverStation.getInstance().isFMSAttached()) { | ||
// throw new RuntimeException("Error launching vision", e); | ||
//} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# WARNING: You should only use this approach for testing cscore on platforms that | ||
# it doesn't support using UsbCamera | ||
# | ||
|
||
import cscore as cs | ||
|
||
if hasattr(cs, "UsbCamera"): | ||
camera = cs.UsbCamera("usbcam", 0) | ||
camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30) | ||
else: | ||
import cv2 | ||
import threading | ||
|
||
camera = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30) | ||
|
||
# tell OpenCV to capture video for us | ||
cap = cv2.VideoCapture(0) | ||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) | ||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) | ||
|
||
# Do it in another thread | ||
def _thread(): | ||
img = None | ||
while True: | ||
retval, img = cap.read(img) | ||
if retval: | ||
camera.putFrame(img) | ||
|
||
th = threading.Thread(target=_thread, daemon=True) | ||
th.start() | ||
|
||
|
||
mjpegServer = cs.MjpegServer("httpserver", 8081) | ||
mjpegServer.setSource(camera) | ||
|
||
print("mjpg server listening at http://0.0.0.0:8081") | ||
input("Press enter to exit...") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Uses the CameraServer class to automatically capture video from two USB | ||
# webcams and send it to the FRC dashboard without doing any vision | ||
# processing. | ||
# | ||
# Warning: If you're using this with a python-based robot, do not run this | ||
# in the same program as your robot code! | ||
# | ||
|
||
from cscore import CameraServer as CS | ||
|
||
|
||
def main(): | ||
CS.enableLogging() | ||
|
||
usb1 = CS.startAutomaticCapture(dev=0) | ||
usb2 = CS.startAutomaticCapture(dev=1) | ||
|
||
CS.waitForever() | ||
|
||
|
||
if __name__ == "__main__": | ||
# To see messages from networktables, you must setup logging | ||
import logging | ||
|
||
logging.basicConfig(level=logging.DEBUG) | ||
|
||
# You should uncomment these to connect to the RoboRIO | ||
# import ntcore | ||
# nt = ntcore.NetworkTableInstance.getDefault() | ||
# nt.setServerTeam(XXXX) | ||
# nt.startClient4(__file__) | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import cscore as cs | ||
|
||
|
||
def main(): | ||
for caminfo in cs.UsbCamera.enumerateUsbCameras(): | ||
print("%s: %s (%s)" % (caminfo.dev, caminfo.path, caminfo.name)) | ||
if caminfo.otherPaths: | ||
print("Other device paths:") | ||
for path in caminfo.otherPaths: | ||
print(" ", path) | ||
|
||
camera = cs.UsbCamera("usbcam", caminfo.dev) | ||
|
||
print("Properties:") | ||
for prop in camera.enumerateProperties(): | ||
kind = prop.getKind() | ||
if kind == cs.VideoProperty.Kind.kBoolean: | ||
print( | ||
prop.getName(), | ||
"(bool) value=%s default=%s" % (prop.get(), prop.getDefault()), | ||
) | ||
elif kind == cs.VideoProperty.Kind.kInteger: | ||
print( | ||
prop.getName(), | ||
"(int): value=%s min=%s max=%s step=%s default=%s" | ||
% ( | ||
prop.get(), | ||
prop.getMin(), | ||
prop.getMax(), | ||
prop.getStep(), | ||
prop.getDefault(), | ||
), | ||
) | ||
elif kind == cs.VideoProperty.Kind.kString: | ||
print(prop.getName(), "(string):", prop.getString()) | ||
elif kind == cs.VideoProperty.Kind.kEnum: | ||
print(prop.getName(), "(enum): value=%s" % prop.get()) | ||
for i, choice in enumerate(prop.getChoices()): | ||
if choice: | ||
print(" %s: %s" % (i, choice)) | ||
|
||
print("Video Modes") | ||
for mode in camera.enumerateVideoModes(): | ||
if mode.pixelFormat == cs.VideoMode.PixelFormat.kMJPEG: | ||
fmt = "MJPEG" | ||
elif mode.pixelFormat == cs.VideoMode.PixelFormat.kYUYV: | ||
fmt = "YUYV" | ||
elif mode.pixelFormat == cs.VideoMode.PixelFormat.kRGB565: | ||
fmt = "RGB565" | ||
else: | ||
fmt = "Unknown" | ||
|
||
print(" PixelFormat:", fmt) | ||
print(" Width:", mode.width) | ||
print(" Height:", mode.height) | ||
print(" FPS: ", mode.fps) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Demonstrates streaming from a HTTP camera server | ||
# | ||
|
||
|
||
import cscore as cs | ||
import numpy as np | ||
import cv2 | ||
|
||
|
||
def main(): | ||
camera = cs.HttpCamera("httpcam", "http://localhost:8081/?action=stream") | ||
camera.setVideoMode(cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30) | ||
|
||
cvsink = cs.CvSink("cvsink") | ||
cvsink.setSource(camera) | ||
|
||
cvSource = cs.CvSource("cvsource", cs.VideoMode.PixelFormat.kMJPEG, 320, 240, 30) | ||
cvMjpegServer = cs.MjpegServer("cvhttpserver", 8083) | ||
cvMjpegServer.setSource(cvSource) | ||
|
||
print("OpenCV output mjpg server listening at http://0.0.0.0:8083") | ||
|
||
test = np.zeros(shape=(240, 320, 3), dtype=np.uint8) | ||
flip = np.zeros(shape=(240, 320, 3), dtype=np.uint8) | ||
|
||
while True: | ||
time, test = cvsink.grabFrame(test) | ||
if time == 0: | ||
print("error:", cvsink.getError()) | ||
continue | ||
|
||
print("got frame at time", time, test.shape) | ||
|
||
cv2.flip(test, flipCode=0, dst=flip) | ||
cvSource.putFrame(flip) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# This is a demo program showing CameraServer usage with OpenCV to do image | ||
# processing. The image is acquired from the USB camera, then a rectangle | ||
# is put on the image and sent to the dashboard. OpenCV has many methods | ||
# for different types of processing. | ||
# | ||
# Warning: If you're using this with a python-based robot, do not run this | ||
# in the same program as your robot code! | ||
# | ||
|
||
import cv2 | ||
import numpy as np | ||
|
||
from cscore import CameraServer as CS | ||
|
||
|
||
def main(): | ||
CS.enableLogging() | ||
|
||
camera = CS.startAutomaticCapture() | ||
|
||
camera.setResolution(640, 480) | ||
|
||
# Get a CvSink. This will capture images from the camera | ||
cvSink = CS.getVideo() | ||
|
||
# (optional) Setup a CvSource. This will send images back to the Dashboard | ||
outputStream = CS.putVideo("Rectangle", 640, 480) | ||
|
||
# Allocating new images is very expensive, always try to preallocate | ||
img = np.zeros(shape=(480, 640, 3), dtype=np.uint8) | ||
|
||
while True: | ||
# Tell the CvSink to grab a frame from the camera and put it | ||
# in the source image. If there is an error notify the output. | ||
time, img = cvSink.grabFrame(img) | ||
if time == 0: | ||
# Send the output the error. | ||
outputStream.notifyError(cvSink.getError()) | ||
# skip the rest of the current iteration | ||
continue | ||
|
||
# Put a rectangle on the image | ||
cv2.rectangle(img, (100, 100), (400, 400), (255, 255, 255), 5) | ||
|
||
# Give the output stream a new image to display | ||
outputStream.putFrame(img) | ||
|
||
|
||
if __name__ == "__main__": | ||
# To see messages from networktables, you must setup logging | ||
import logging | ||
|
||
logging.basicConfig(level=logging.DEBUG) | ||
|
||
# You should uncomment these to connect to the RoboRIO | ||
# import ntcore | ||
# nt = ntcore.NetworkTableInstance.getDefault() | ||
# nt.setServerTeam(XXXX) | ||
# nt.startClient4(__file__) | ||
|
||
main() |
Oops, something went wrong.