diff --git a/Main/chameleon-vision.iml b/Main/chameleon-vision.iml index 487436a6c..d886581e1 100644 --- a/Main/chameleon-vision.iml +++ b/Main/chameleon-vision.iml @@ -41,9 +41,9 @@ - - - + + + diff --git a/Main/src/main/java/com/chameleonvision/Main.java b/Main/src/main/java/com/chameleonvision/Main.java index 7e2046a19..06b65b327 100644 --- a/Main/src/main/java/com/chameleonvision/Main.java +++ b/Main/src/main/java/com/chameleonvision/Main.java @@ -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 { @@ -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!"); + } } } } diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/VisionManager.java b/Main/src/main/java/com/chameleonvision/classabstraction/VisionManager.java index e2a7ee2f3..33ab13bc9 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/VisionManager.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/VisionManager.java @@ -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 UsbCameraInfosByCameraName = new LinkedHashMap<>(); public static final LinkedHashMap 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 list, Path path) throws IOException { + File pipelineFile = new File(path.toString()); + ObjectMapper objectMapper = new ObjectMapper().enableDefaultTyping(); + objectMapper.writeValue(pipelineFile,list); + } + public static void initializeProcesses() { diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/VisionProcess.java b/Main/src/main/java/com/chameleonvision/classabstraction/VisionProcess.java index eb54fcf7c..ded690973 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/VisionProcess.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/VisionProcess.java @@ -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 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()); + } + } + } } diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java index bab9235fd..f37aa7f37 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java @@ -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 getFrame(Mat frame); + Pair getFrame(); /** * Set the exposure of the camera diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java index 2f98f37c8..63dbc9078 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java @@ -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; diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java index f24b15e3d..1afadb6c1 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java @@ -28,13 +28,12 @@ public class USBCameraProcess implements CameraProcess { } @Override - public Pair getFrame(Mat frame) { + public Pair getFrame() { Long deltaTime; synchronized (cvSink) { deltaTime = cvSink.grabFrame(imageBuffer) * 1000L; - imageBuffer.copyTo(frame); } - return Pair.of(frame, deltaTime); + return Pair.of(imageBuffer, deltaTime); } @Override diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineResult.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineResult.java index 3ffe26d9d..484bf20b1 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineResult.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineResult.java @@ -8,10 +8,12 @@ public abstract class CVPipelineResult { public final List targets; public final boolean hasTarget; public final Mat outputMat = new Mat(); + public final long processTime; - public CVPipelineResult(List targets, Mat outputMat) { + public CVPipelineResult(List targets, Mat outputMat, long processTime) { this.targets = targets; hasTarget = targets != null && !targets.isEmpty(); outputMat.copyTo(this.outputMat); + this.processTime = processTime; } } diff --git a/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java b/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java index 30d460ce3..a329b82ce 100644 --- a/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java +++ b/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java @@ -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;