mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-20 00:51:41 +00:00
Added Runnables for VisionProcess threads
This commit is contained in:
@@ -16,18 +16,19 @@ import java.util.function.Consumer;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static final String PORT_KEY = "--port"; // expects integer
|
||||
private static final String NT_SERVERMODE_KEY = "--nt-servermode"; // no args for this setting
|
||||
private static final String NT_CLIENTMODESERVER_KEY = "--nt-client-server"; // expects String representing an IP address (hostnames will be rejected!)
|
||||
private static final String NETWORK_MANAGE_KEY = "--unmanage-network"; // no args for this setting
|
||||
private static final String IGNORE_ROOT = "--ignore-root"; // no args for this setting
|
||||
private static final String IGNORE_ROOT_KEY = "--ignore-root"; // no args for this setting
|
||||
private static final String TEST_MODE_KEY = "--cv-development";
|
||||
|
||||
private static final int DEFAULT_PORT = 8888;
|
||||
private static final int DEFAULT_PORT = 5800;
|
||||
|
||||
private static boolean ntServerMode = false;
|
||||
private static boolean manageNetwork = true;
|
||||
private static boolean ignoreRoot = false;
|
||||
private static String ntClientModeServer = null;
|
||||
private static boolean testMode = false;
|
||||
|
||||
private static class NTLogger implements Consumer<LogMessage> {
|
||||
|
||||
@@ -51,7 +52,6 @@ public class Main {
|
||||
|
||||
// this switch handles arguments with a value. Add any settings with a value here.
|
||||
switch (key) {
|
||||
case PORT_KEY:
|
||||
case NT_CLIENTMODESERVER_KEY:
|
||||
var potentialValue = args[i + 1];
|
||||
// ensures this "value" isnt null, blank, nor another argument
|
||||
@@ -62,21 +62,14 @@ public class Main {
|
||||
break;
|
||||
case NT_SERVERMODE_KEY:
|
||||
case NETWORK_MANAGE_KEY:
|
||||
case IGNORE_ROOT:
|
||||
case IGNORE_ROOT_KEY:
|
||||
case TEST_MODE_KEY:
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// this switch actually handles the arguments.
|
||||
switch (key) {
|
||||
case PORT_KEY:
|
||||
System.out.println("INFO - The \"--port\" argument is currently disabled.");
|
||||
// try {
|
||||
// if (value == null) throw new Exception("Bad or No argument value");
|
||||
// webserverPort = Integer.parseInt(value);
|
||||
// } catch (Exception ex) {
|
||||
// System.err.printf("Argument for port was invalid, starting server at port %d\n", DEFAULT_PORT);
|
||||
// }
|
||||
break;
|
||||
case NT_SERVERMODE_KEY:
|
||||
ntServerMode = true;
|
||||
break;
|
||||
@@ -97,8 +90,12 @@ public class Main {
|
||||
case NETWORK_MANAGE_KEY:
|
||||
manageNetwork = false;
|
||||
break;
|
||||
case IGNORE_ROOT:
|
||||
case IGNORE_ROOT_KEY:
|
||||
ignoreRoot = true;
|
||||
break;
|
||||
case TEST_MODE_KEY:
|
||||
testMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,30 +127,34 @@ public class Main {
|
||||
CameraServerCvJNI.forceLoad();
|
||||
} catch (UnsatisfiedLinkError | IOException e) {
|
||||
if(Platform.getCurrentPlatform().isWindows())
|
||||
System.err.println("Try to download the VC++ Redistributable, see announcements in discord");
|
||||
System.err.println("Try to download the VC++ Redistributable, https://aka.ms/vs/16/release/vc_redist.x64.exe");
|
||||
throw new RuntimeException("Failed to load JNI Libraries!");
|
||||
}
|
||||
if (CameraManager.initializeCameras()) {
|
||||
SettingsManager.initialize();
|
||||
NetworkManager.initialize(manageNetwork);
|
||||
CameraManager.initializeThreads();
|
||||
if (ntServerMode) {
|
||||
System.out.println("Starting NT Server");
|
||||
NetworkTableInstance.getDefault().startServer();
|
||||
} else {
|
||||
NetworkTableInstance.getDefault().addLogger(new NTLogger(), 0, 255); // to hide error messages
|
||||
if (ntClientModeServer != null) {
|
||||
NetworkTableInstance.getDefault().startClient(ntClientModeServer);
|
||||
} else {
|
||||
NetworkTableInstance.getDefault().startClientTeam(SettingsManager.generalSettings.teamNumber);
|
||||
}
|
||||
}
|
||||
|
||||
int webserverPort = DEFAULT_PORT;
|
||||
System.out.printf("Starting Webserver at port %d\n", webserverPort);
|
||||
Server.main(webserverPort);
|
||||
if (testMode) {
|
||||
// todo: boot in to the new classabstraction stuff
|
||||
} else {
|
||||
System.err.println("No cameras connected!");
|
||||
if (CameraManager.initializeCameras()) {
|
||||
SettingsManager.initialize();
|
||||
NetworkManager.initialize(manageNetwork);
|
||||
CameraManager.initializeThreads();
|
||||
if (ntServerMode) {
|
||||
System.out.println("Starting NT Server");
|
||||
NetworkTableInstance.getDefault().startServer();
|
||||
} else {
|
||||
NetworkTableInstance.getDefault().addLogger(new NTLogger(), 0, 255); // to hide error messages
|
||||
if (ntClientModeServer != null) {
|
||||
NetworkTableInstance.getDefault().startClient(ntClientModeServer);
|
||||
} else {
|
||||
NetworkTableInstance.getDefault().startClientTeam(SettingsManager.generalSettings.teamNumber);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.printf("Starting Webserver at port %d\n", DEFAULT_PORT);
|
||||
Server.main(DEFAULT_PORT);
|
||||
} else {
|
||||
System.err.println("No cameras connected!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -28,7 +27,6 @@ public class VisionManager {
|
||||
public static final LinkedHashMap<String, UsbCameraInfo> UsbCameraInfosByCameraName = new LinkedHashMap<>();
|
||||
public static final LinkedHashMap<String, VisionProcess> VisionProcessesByCameraName = new LinkedHashMap<>();
|
||||
|
||||
|
||||
public static boolean initializeSources() {
|
||||
int suffix = 0;
|
||||
for (UsbCameraInfo info : UsbCamera.enumerateUsbCameras()) {
|
||||
@@ -48,19 +46,26 @@ public class VisionManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
FileHelper.CheckPath(CamConfigPath);
|
||||
UsbCameraInfosByCameraName.forEach((cameraName, cameraInfo) -> {
|
||||
Path cameraConfigPath = Paths.get(CamConfigPath.toString(), String.format("%s.json", cameraName));
|
||||
File cameraConfigFile = new File(cameraConfigPath.toString());
|
||||
if (cameraConfigFile.exists() && cameraConfigFile.length() != 0) {
|
||||
// try {
|
||||
// Gson gson = new GsonBuilder().registerTypeAdapter(USBCameraProcess.class, new CameraDeserializer());
|
||||
// }
|
||||
}
|
||||
});
|
||||
// FileHelper.CheckPath(CamConfigPath);
|
||||
// UsbCameraInfosByCameraName.forEach((cameraName, cameraInfo) -> {
|
||||
// Path cameraConfigPath = Paths.get(CamConfigPath.toString(), String.format("%s.json", cameraName));
|
||||
// File cameraConfigFile = new File(cameraConfigPath.toString());
|
||||
// if (cameraConfigFile.exists() && cameraConfigFile.length() != 0) {
|
||||
//// try {
|
||||
//// Gson gson = new GsonBuilder().registerTypeAdapter(USBCameraProcess.class, new CameraDeserializer());
|
||||
//// }
|
||||
// }
|
||||
// })
|
||||
// TODO: implement new camera JSON loads
|
||||
return true;
|
||||
}
|
||||
|
||||
public void PipelineSerializer(List<CVPipelineSettings> list, Path path) throws IOException {
|
||||
File pipelineFile = new File(path.toString());
|
||||
ObjectMapper objectMapper = new ObjectMapper().enableDefaultTyping();
|
||||
objectMapper.writeValue(pipelineFile,list);
|
||||
}
|
||||
|
||||
|
||||
public static void initializeProcesses() {
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package com.chameleonvision.classabstraction;
|
||||
|
||||
import com.chameleonvision.classabstraction.camera.CameraProcess;
|
||||
import com.chameleonvision.classabstraction.pipeline.CVPipeline;
|
||||
import com.chameleonvision.classabstraction.pipeline.CVPipelineResult;
|
||||
import com.chameleonvision.classabstraction.pipeline.CVPipelineSettings;
|
||||
import com.chameleonvision.classabstraction.pipeline.DriverVisionPipeline;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,6 +16,8 @@ public class VisionProcess {
|
||||
private final List<CVPipeline> pipelines = new ArrayList<>();
|
||||
private CVPipeline currentPipeline;
|
||||
|
||||
private final CameraFrameRunnable cameraFrameRunnable;
|
||||
|
||||
private final CVPipelineSettings driverVisionSettings = new CVPipelineSettings();
|
||||
|
||||
public VisionProcess(CameraProcess cameraProcess) {
|
||||
@@ -21,6 +25,8 @@ public class VisionProcess {
|
||||
|
||||
pipelines.add(new DriverVisionPipeline(() -> driverVisionSettings));
|
||||
setPipeline(pipelines.get(0));
|
||||
|
||||
cameraFrameRunnable = new CameraFrameRunnable();
|
||||
}
|
||||
|
||||
public void setPipeline(int pipelineIndex) {
|
||||
@@ -38,4 +44,42 @@ public class VisionProcess {
|
||||
public CVPipeline getCurrentPipeline() {
|
||||
return currentPipeline;
|
||||
}
|
||||
|
||||
protected class CameraFrameRunnable implements Runnable {
|
||||
private Mat cameraFrame = new Mat();
|
||||
private long timestampMicros;
|
||||
|
||||
private final Object frameLock = new Object();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(Thread.interrupted()) {
|
||||
var camData = cameraProcess.getFrame();
|
||||
synchronized (frameLock) {
|
||||
cameraFrame = camData.getLeft();
|
||||
}
|
||||
timestampMicros = camData.getRight();
|
||||
}
|
||||
}
|
||||
|
||||
public Mat getFrame() {
|
||||
return cameraFrame;
|
||||
}
|
||||
|
||||
public long getTimestampMicros() {
|
||||
return timestampMicros;
|
||||
}
|
||||
}
|
||||
|
||||
private class VisionThread implements Runnable {
|
||||
|
||||
private CVPipelineResult result;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(!Thread.interrupted()) {
|
||||
result = currentPipeline.runPipeline(cameraFrameRunnable.getFrame());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,9 @@ public interface CameraProcess {
|
||||
|
||||
/**
|
||||
* Get the next camera frame
|
||||
* @param frame the frame to copy the image into
|
||||
* @return a Pair of the captured image and how long it took to grab the frame (in uS)
|
||||
*/
|
||||
Pair<Mat, Long> getFrame(Mat frame);
|
||||
Pair<Mat, Long> getFrame();
|
||||
|
||||
/**
|
||||
* Set the exposure of the camera
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.chameleonvision.classabstraction.camera;
|
||||
|
||||
import com.chameleonvision.vision.camera.CameraManager;
|
||||
import com.chameleonvision.vision.camera.StreamDivisor;
|
||||
import com.chameleonvision.web.ServerHandler;
|
||||
import edu.wpi.cscore.CvSource;
|
||||
@@ -11,7 +10,6 @@ import org.opencv.core.Size;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
public class CameraStreamer {
|
||||
|
||||
private final CameraProcess cameraProcess;
|
||||
private final String name;
|
||||
private StreamDivisor divisor = StreamDivisor.NONE;
|
||||
@@ -27,7 +25,6 @@ public class CameraStreamer {
|
||||
cameraProcess.getProperties().staticProperties.imageHeight / divisor.value);
|
||||
}
|
||||
|
||||
|
||||
public void setDivisor(StreamDivisor newDivisor) {
|
||||
this.divisor = newDivisor;
|
||||
var camValues = cameraProcess.getProperties();
|
||||
@@ -42,9 +39,7 @@ public class CameraStreamer {
|
||||
ServerHandler.sendFullSettings();
|
||||
}
|
||||
|
||||
public void runStream() {
|
||||
var newFrame = cameraProcess.getFrame(streamBuffer);
|
||||
var image = newFrame.getLeft();
|
||||
public void runStream(Mat image) {
|
||||
if (divisor.value != 1) {
|
||||
var camVal = cameraProcess.getProperties().staticProperties;
|
||||
var newWidth = camVal.imageWidth / divisor.value;
|
||||
|
||||
@@ -28,13 +28,12 @@ public class USBCameraProcess implements CameraProcess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Mat, Long> getFrame(Mat frame) {
|
||||
public Pair<Mat, Long> getFrame() {
|
||||
Long deltaTime;
|
||||
synchronized (cvSink) {
|
||||
deltaTime = cvSink.grabFrame(imageBuffer) * 1000L;
|
||||
imageBuffer.copyTo(frame);
|
||||
}
|
||||
return Pair.of(frame, deltaTime);
|
||||
return Pair.of(imageBuffer, deltaTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,10 +8,12 @@ public abstract class CVPipelineResult<T> {
|
||||
public final List<T> targets;
|
||||
public final boolean hasTarget;
|
||||
public final Mat outputMat = new Mat();
|
||||
public final long processTime;
|
||||
|
||||
public CVPipelineResult(List<T> targets, Mat outputMat) {
|
||||
public CVPipelineResult(List<T> targets, Mat outputMat, long processTime) {
|
||||
this.targets = targets;
|
||||
hasTarget = targets != null && !targets.isEmpty();
|
||||
outputMat.copyTo(this.outputMat);
|
||||
this.processTime = processTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.chameleonvision.vision.process;
|
||||
|
||||
import com.chameleonvision.classabstraction.pipeline.CVPipeline2d;
|
||||
import com.chameleonvision.classabstraction.pipeline.CVPipeline2dSettings;
|
||||
import com.chameleonvision.classabstraction.pipeline.DriverVisionPipeline;
|
||||
import com.chameleonvision.settings.SettingsManager;
|
||||
import com.chameleonvision.vision.Orientation;
|
||||
|
||||
Reference in New Issue
Block a user