diff --git a/Main/src/main/java/com/chameleonvision/vision/Pipeline.java b/Main/src/main/java/com/chameleonvision/vision/Pipeline.java index b362c4953..2490a45af 100644 --- a/Main/src/main/java/com/chameleonvision/vision/Pipeline.java +++ b/Main/src/main/java/com/chameleonvision/vision/Pipeline.java @@ -23,4 +23,5 @@ public class Pipeline { public double m = 1; public double b = 0; public boolean isCalibrated = false; + public String nickname; } diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java b/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java index 717e6e3ba..8dbad40e4 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java @@ -1,6 +1,8 @@ package com.chameleonvision.vision.camera; +import com.chameleonvision.Main; import com.chameleonvision.settings.Platform; +import com.chameleonvision.settings.SettingsManager; import com.chameleonvision.vision.Pipeline; import com.chameleonvision.web.ServerHandler; import edu.wpi.cscore.*; @@ -9,6 +11,8 @@ import org.opencv.core.Mat; import java.util.Arrays; import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; import java.util.stream.IntStream; public class Camera { @@ -19,10 +23,13 @@ public class Camera { private static final int MINIMUM_WIDTH = 320; private static final int MINIMUM_HEIGHT = 200; private static final int MAX_INIT_MS = 1500; + private static final List ALLOWED_PIXEL_FORMATS = Arrays.asList(VideoMode.PixelFormat.kYUYV, VideoMode.PixelFormat.kMJPEG); public final String name; public final String path; + private String nickname; + private final UsbCamera UsbCam; private final VideoMode[] availableVideoModes; @@ -64,7 +71,14 @@ public class Camera { public Camera(String cameraName, UsbCameraInfo usbCamInfo, double fov, HashMap pipelines, int videoModeIndex, StreamDivisor divisor) { FOV = fov; name = cameraName; - path = usbCamInfo.path; + + if (Platform.getCurrentPlatform().isWindows()) { + path = usbCamInfo.path; + } else { + var truePath = Arrays.stream(usbCamInfo.otherPaths).filter(x -> x.contains("/dev/v4l/by-path")).findFirst(); + path = truePath.isPresent() ? truePath.toString() : null; + } + streamDivisor = divisor; UsbCam = new UsbCamera(name, path); @@ -83,7 +97,8 @@ public class Camera { System.out.printf("Camera initialized in %.2fms\n", initTimeMs); } var trueVideoModes = UsbCam.enumerateVideoModes(); - availableVideoModes = Arrays.stream(trueVideoModes).filter(v -> v.fps >= MINIMUM_FPS && v.width >= MINIMUM_WIDTH && v.height >= MINIMUM_HEIGHT).toArray(VideoMode[]::new); + availableVideoModes = Arrays.stream(trueVideoModes).filter(v -> + v.fps >= MINIMUM_FPS && v.width >= MINIMUM_WIDTH && v.height >= MINIMUM_HEIGHT && ALLOWED_PIXEL_FORMATS.contains(v.pixelFormat)).toArray(VideoMode[]::new); if (availableVideoModes.length == 0) { System.err.println("Camera not supported!"); throw new RuntimeException(new CameraException(CameraException.CameraExceptionType.BAD_CAMERA)); @@ -130,17 +145,31 @@ public class Camera { addPipeline(pipelines.size()); } + public void addPipeline(Pipeline pipeline) { + int newPipelineIndex = pipelines.size(); + addPipeline(newPipelineIndex, pipeline); + } + private void addPipeline(int pipelineNumber) { if (pipelines.containsKey(pipelineNumber)) return; pipelines.put(pipelineNumber, new Pipeline()); } + private void addPipeline(int pipelineIndex, Pipeline pipeline) { + if (pipelines.containsKey(pipelineIndex)) return; + pipelines.put(pipelineIndex, pipeline); + } + public void deleteCurrentPipeline() { pipelines.remove(getCurrentPipelineIndex()); } public Pipeline getCurrentPipeline() { - return pipelines.get(currentPipelineIndex); + return getPipelineByIndex(currentPipelineIndex); + } + + public Pipeline getPipelineByIndex(int pipelineIndex) { + return pipelines.get(pipelineIndex); } public int getCurrentPipelineIndex() { @@ -211,4 +240,18 @@ public class Camera { cvSource.putFrame(image); } } + + public List getResolutionList() { + return Arrays.stream(availableVideoModes) + .map(res -> String.format("%sx%s@%sFPS, %s", res.width, res.height, res.fps, res.pixelFormat.toString())) + .collect(Collectors.toList()); + } + + public void setNickname(String newNickname) { + nickname = newNickname; + } + + public String getNickname() { + return nickname == null ? name : nickname; + } } diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java index 8218778c4..d0440c7ca 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java @@ -16,10 +16,10 @@ public class CameraDeserializer implements JsonDeserializer { var jsonObj = jsonElement.getAsJsonObject(); var camFOV = jsonObj.get("FOV").getAsDouble(); var camName = jsonObj.get("name").getAsString(); + var camNickname = jsonObj.get("nickname").getAsString(); var videoModeIndex = jsonObj.get("resolution").getAsInt(); var divisor = StreamDivisor.values()[jsonObj.get("streamDivisor").getAsInt()]; - var pipelines = jsonObj.get("pipelines"); HashMap actualPipelines = new HashMap<>(); ObjectMapper mapper = new ObjectMapper(); @@ -31,6 +31,8 @@ public class CameraDeserializer implements JsonDeserializer { e.printStackTrace(); } - return actualPipelines != null ? new Camera(camName, camFOV, actualPipelines, videoModeIndex,divisor) : new Camera(camName, camFOV, videoModeIndex, divisor); + var newCamera = actualPipelines != null ? new Camera(camName, camFOV, actualPipelines, videoModeIndex, divisor) : new Camera(camName, camFOV, videoModeIndex, divisor); + newCamera.setNickname(camNickname != null ? camNickname : ""); + return newCamera; } } diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java index 3c7934ae3..1abeaa3e9 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.stream.Collectors; @@ -22,7 +23,7 @@ public class CameraManager { private static final Path CamConfigPath = Paths.get(SettingsManager.SettingsPath.toString(), "cameras"); - private static HashMap AllCamerasByName = new HashMap<>(); + private static LinkedHashMap AllCamerasByName = new LinkedHashMap<>(); private static HashMap AllVisionProcessesByName = new HashMap<>(); static HashMap AllUsbCameraInfosByName = new HashMap<>() {{ @@ -88,6 +89,10 @@ public class CameraManager { return AllCamerasByName.get(cameraName); } + public static Camera getCameraByIndex(int index) { + return AllCamerasByName.get( (AllCamerasByName.keySet().toArray())[ index ] ); + } + public static Camera getCurrentCamera() throws CameraException { if (AllCamerasByName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA); var curCam = AllCamerasByName.get(SettingsManager.GeneralSettings.currentCamera); @@ -113,14 +118,7 @@ public class CameraManager { SettingsManager.updatePipelineSetting(pipelineNumber); } - public static List getResolutionList() throws CameraException { - if (!SettingsManager.GeneralSettings.currentCamera.equals("")) { - return Arrays.stream(CameraManager.getCamera(SettingsManager.GeneralSettings.currentCamera).getAvailableVideoModes()) - .map(res -> String.format("%s X %s at %s fps using %s ", res.width, res.height, res.fps, res.pixelFormat.toString())).collect(Collectors.toList()); - } - throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA); - } - public static VisionProcess getCurrentCameraProcess() throws CameraException{ + public static VisionProcess getCurrentCameraProcess() throws CameraException { if (!SettingsManager.GeneralSettings.currentCamera.equals("")){ return AllVisionProcessesByName.get(SettingsManager.GeneralSettings.currentCamera); } diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraSerializer.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraSerializer.java index 2118b797f..e5e949070 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraSerializer.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraSerializer.java @@ -10,6 +10,7 @@ public class CameraSerializer implements JsonSerializer { obj.addProperty("FOV", camera.getFOV()); obj.addProperty("path", camera.path); obj.addProperty("name", camera.name); + obj.addProperty("nickname", camera.getNickname()); obj.addProperty("streamDivisor", camera.getStreamDivisor().ordinal()); var pipelines = context.serialize(camera.getPipelines()); diff --git a/Main/src/main/java/com/chameleonvision/web/ServerHandler.java b/Main/src/main/java/com/chameleonvision/web/ServerHandler.java index f270dd1be..5842f1ccd 100644 --- a/Main/src/main/java/com/chameleonvision/web/ServerHandler.java +++ b/Main/src/main/java/com/chameleonvision/web/ServerHandler.java @@ -64,23 +64,36 @@ public class ServerHandler { break; } case "changeCameraName": { - // needs to be implemented + CameraManager.getCurrentCamera().setNickname((String) entry.getValue()); + break; } case "changePipelineName": { - // needs to be implemented + CameraManager.getCurrentPipeline().nickname = (String) entry.getValue(); + break; } case "duplicatePipeline": { - // needs to be implemented + HashMap pipelineVals = (HashMap) entry.getValue(); + int pipelineIndex = (int) pipelineVals.get("pipeline"); + int cameraIndex = (int) pipelineVals.get("camera"); + + Pipeline origPipeline = CameraManager.getCurrentCamera().getPipelineByIndex(pipelineIndex); + + if (cameraIndex != -1) { + CameraManager.getCameraByIndex(cameraIndex).addPipeline(origPipeline); + } else { + CameraManager.getCurrentCamera().addPipeline(origPipeline); + } + break; } case "command": { + var cam = CameraManager.getCurrentCamera(); switch ((String) entry.getValue()) { case "addNewPipeline": - CameraManager.getCurrentCamera().addPipeline(); + cam.addPipeline(); break; case "deleteCurrentPipeline": - var cam = CameraManager.getCurrentCamera(); - CameraManager.getCurrentCamera().deleteCurrentPipeline(); - CameraManager.getCurrentCamera().setCurrentPipelineIndex(cam.getCurrentPipelineIndex() - 1); + cam.deleteCurrentPipeline(); + cam.setCurrentPipelineIndex(cam.getCurrentPipelineIndex() - 1); sendFullSettings(); break; } @@ -89,11 +102,12 @@ public class ServerHandler { } case "currentCamera": { CameraManager.setCurrentCamera((String) entry.getValue()); + var cam = CameraManager.getCurrentCamera(); HashMap tmp = new HashMap<>(); - tmp.put("pipeline", CameraManager.getCurrentCamera().getCurrentPipeline()); - tmp.put("pipelineList", CameraManager.getCurrentCamera().getPipelines().keySet()); - tmp.put("port", CameraManager.getCurrentCamera().getStreamPort()); - tmp.put("resolutionList", CameraManager.getResolutionList()); + tmp.put("pipeline", cam.getCurrentPipeline()); + tmp.put("pipelineList", cam.getPipelines().keySet()); + tmp.put("port", cam.getStreamPort()); + tmp.put("resolutionList", cam.getResolutionList()); broadcastMessage(tmp); break; } @@ -212,7 +226,7 @@ public class ServerHandler { var currentCamera = CameraManager.getCurrentCamera(); fullSettings.put("pipeline", getOrdinalPipeline()); fullSettings.put("pipelineList", currentCamera.getPipelines().keySet()); - fullSettings.put("resolutionList", CameraManager.getResolutionList()); + fullSettings.put("resolutionList", currentCamera.getResolutionList()); fullSettings.put("port", currentCamera.getStreamPort()); } catch (CameraException | IllegalAccessException e) { System.err.println("No camera found!"); diff --git a/Main/target/classes/web/index.html b/Main/target/classes/web/index.html index 1ecbca0d7..676e7dc19 100644 --- a/Main/target/classes/web/index.html +++ b/Main/target/classes/web/index.html @@ -1 +1 @@ -Chameleon Vision
\ No newline at end of file +Chameleon Vision
\ No newline at end of file