Skip to content

Commit

Permalink
refactor: moving examples to an example folder in the root directory
Browse files Browse the repository at this point in the history
  • Loading branch information
martincarapia committed Apr 9, 2024
1 parent cfce3f2 commit 36f09fc
Show file tree
Hide file tree
Showing 16 changed files with 833 additions and 0 deletions.
127 changes: 127 additions & 0 deletions EXAMPLES/examplecscore/CameraServer.java
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);
//}
}
}
}
39 changes: 39 additions & 0 deletions EXAMPLES/examplecscore/cvstream.py
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...")
35 changes: 35 additions & 0 deletions EXAMPLES/examplecscore/dual_cameraserver.py
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()
62 changes: 62 additions & 0 deletions EXAMPLES/examplecscore/enum_usb.py
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()
41 changes: 41 additions & 0 deletions EXAMPLES/examplecscore/httpcvstream.py
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()
63 changes: 63 additions & 0 deletions EXAMPLES/examplecscore/intermediate_cameraserver.py
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()
Loading

0 comments on commit 36f09fc

Please sign in to comment.