diff --git a/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java b/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java index f10254417..2309d9be7 100644 --- a/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java +++ b/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java @@ -23,7 +23,7 @@ public class SettingsManager { private static SettingsManager instance; private SettingsManager() { - InitiateGeneralSettings(); + InitiateSavedSettings(); InitiateCamerasInfo(); InitiateUsbCameras(); InitiateCameras(); @@ -57,9 +57,11 @@ public class SettingsManager { private Path CamsPath = Paths.get(SettingsPath.toString(), "Cams"); - private void InitiateGeneralSettings() { + private void InitiateSavedSettings() { CheckPath(SettingsPath); try { + CamerasCurrentPipeline = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(),"SelectedPipelines.json").toString()),HashMap.class); +// CamerasCurrentPipeline = new JSONArray(Paths.get(SettingsPath.toString(),"SelectedPipelines.json")).toList(); GeneralSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(), "Settings.json").toString()), com.chameleonvision.vision.GeneralSettings.class); } catch (FileNotFoundException e) { GeneralSettings = new GeneralSettings(); @@ -152,16 +154,13 @@ public class SettingsManager { cam.FOV = 60.8; Cameras.put(CameraName, cam); - CreateNewPipeline(null, CameraName); - CreateNewPipeline(null, CameraName);//Created 2 pipeline for testing TODO add a create pipeline button + CreateNewPipeline(null,cam); + CreateNewPipeline(null,cam);//Created 2 pipeline for testing TODO add a create pipeline button + CamerasCurrentPipeline.put(CameraName,"pipeline0");//sets pipeline0 as the default pipeline } - private void CreateNewPipeline(String PipeName, String CamName) { - if (CamName == null) { - CamName = GeneralSettings.curr_camera; - } - var cam = Cameras.get(CamName); + public void CreateNewPipeline(String PipeName,Camera cam) { if (PipeName == null) { var suffix = 0; PipeName = "pipeline" + suffix; @@ -248,6 +247,7 @@ public class SettingsManager { public void SaveSettings() { SaveCameras(); SaveGeneralSettings(); + SaveSelectedPipelines(); } private void SaveCameras() { @@ -266,7 +266,6 @@ public class SettingsManager { private void SaveGeneralSettings() { try { - Gson gson = new Gson(); FileWriter writer = new FileWriter(Paths.get(SettingsPath.toString(), "Settings.json").toString()); new Gson().toJson(GeneralSettings, writer); writer.flush(); @@ -276,5 +275,15 @@ public class SettingsManager { } } + private void SaveSelectedPipelines() { + try { + FileWriter writer = new FileWriter(Paths.get(SettingsPath.toString(), "SelectedPipelines.json").toString()); + new Gson().toJson(CamerasCurrentPipeline, writer); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java b/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java index 6ab116b61..420776a90 100644 --- a/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java @@ -14,44 +14,46 @@ import org.opencv.imgproc.Imgproc; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class CameraProcess implements Runnable { private String CameraName; private CameraServer cs = CameraServer.getInstance(); - private NetworkTableEntry ntPipelineEntry, ntDriverModeEntry,ntYawEntry,ntPitchEntry,ntDistanceEntry,ntTimeStampEntry,ntValidEntry; + private NetworkTableEntry ntPipelineEntry, ntDriverModeEntry, ntYawEntry, ntPitchEntry, ntDistanceEntry, ntTimeStampEntry, ntValidEntry; private MemoryManager memManager = new MemoryManager(125); private int imgWidth, imgHeight; - private void ChangeCameraValues(int Exposure, int Brightness){ + + private void ChangeCameraValues(int Exposure, int Brightness) { SettingsManager.getInstance().UsbCameras.get(CameraName).setBrightness(Brightness); SettingsManager.getInstance().UsbCameras.get(CameraName).setExposureManual(Exposure); } - private void DriverModeListener(EntryNotification entryNotification){ - if (entryNotification.value.getBoolean()){ - ChangeCameraValues(25,15); - } else{ + + private void DriverModeListener(EntryNotification entryNotification) { + if (entryNotification.value.getBoolean()) { + ChangeCameraValues(25, 15); + } else { Pipeline pipeline = SettingsManager.Cameras.get(CameraName).pipelines.get(SettingsManager.CamerasCurrentPipeline.get(CameraName)); ChangeCameraValues(pipeline.exposure, pipeline.brightness); } } - private void PipelineListener(EntryNotification entryNotification){ - if (SettingsManager.Cameras.get(CameraName).pipelines.containsKey(entryNotification.value.getString())){ - SettingsManager.CamerasCurrentPipeline.put(CameraName,entryNotification.value.getString()); + + private void PipelineListener(EntryNotification entryNotification) { + if (SettingsManager.Cameras.get(CameraName).pipelines.containsKey(entryNotification.value.getString())) { + SettingsManager.CamerasCurrentPipeline.put(CameraName, entryNotification.value.getString()); Pipeline pipeline = SettingsManager.Cameras.get(CameraName).pipelines.get(SettingsManager.CamerasCurrentPipeline.get(CameraName)); ChangeCameraValues(pipeline.exposure, pipeline.brightness); //TODO Send Pipeline change using websocket to client - } else{ + } else { ntPipelineEntry.setString(SettingsManager.CamerasCurrentPipeline.get(CameraName)); } } + public CameraProcess(String CameraName) { this.CameraName = CameraName; - // add pipeline - SettingsManager.CamerasCurrentPipeline.put(CameraName, SettingsManager.Cameras.get(CameraName).pipelines.keySet().toArray()[0].toString()); - // NetworkTables NetworkTable ntTable = NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + CameraName); ntPipelineEntry = ntTable.getEntry("Pipeline"); @@ -93,7 +95,7 @@ public class CameraProcess implements Runnable { double processTimeMs; double fps; //camera results - double CalibratedX,CalibratedY , Pitch, Yaw; + double CalibratedX, CalibratedY, Pitch, Yaw; boolean isValid; while (!Thread.interrupted()) { @@ -103,6 +105,7 @@ public class CameraProcess implements Runnable { currentPipeline = SettingsManager.Cameras.get(CameraName).pipelines.get(SettingsManager.CamerasCurrentPipeline.get(CameraName)); +// System.out.println(SettingsManager.CamerasCurrentPipeline.get(CameraName)); // start fps counter right before grabbing input frame startTime = System.nanoTime(); cv_sink.grabFrame(inputMat); @@ -128,14 +131,14 @@ public class CameraProcess implements Runnable { GroupedContours = visionProcess.GroupTargets(FilteredContours, currentPipeline.target_intersection, currentPipeline.target_group); if (GroupedContours.size() > 0) { var finalRect = visionProcess.SortTargetsToOne(GroupedContours, currentPipeline.sort_mode); - if (!currentPipeline.is_calibrated){ + if (!currentPipeline.is_calibrated) { CalibratedX = camVals.CenterX; CalibratedY = camVals.CenterY; - } else{ - CalibratedX = (finalRect.center.y - currentPipeline.B) / currentPipeline.M; - CalibratedY = finalRect.center.x * currentPipeline.M + currentPipeline.B; - Pitch = camVals.CalculatePitch(finalRect.center.y, CalibratedY); - Yaw = camVals.CalculateYaw(finalRect.center.x, CalibratedX); + } else { + CalibratedX = (finalRect.center.y - currentPipeline.B) / currentPipeline.M; + CalibratedY = finalRect.center.x * currentPipeline.M + currentPipeline.B; + Pitch = camVals.CalculatePitch(finalRect.center.y, CalibratedY); + Yaw = camVals.CalculateYaw(finalRect.center.x, CalibratedX); } isValid = true; // Send calc using networktables @@ -148,7 +151,7 @@ public class CameraProcess implements Runnable { Imgproc.drawContours(outputMat, a, 0, contourColor, 3); } - } else{ + } else { isValid = false; } } @@ -158,7 +161,7 @@ public class CameraProcess implements Runnable { // calculate FPS after publishing output frame processTimeMs = (System.nanoTime() - startTime) * 1e-6; fps = 1000 / processTimeMs; - System.out.printf("%s Process time: %fms, FPS: %.2f, FoundContours: %d, FilteredContours: %d, GroupedContours: %d\n",CameraName ,processTimeMs, fps, FoundContours.size(), FilteredContours.size(), GroupedContours.size()); +// System.out.printf("%s Process time: %fms, FPS: %.2f, FoundContours: %d, FilteredContours: %d, GroupedContours: %d\n",CameraName ,processTimeMs, fps, FoundContours.size(), FilteredContours.size(), GroupedContours.size()); inputMat.release(); hsvThreshMat.release(); diff --git a/Main/src/main/java/com/chameleonvision/web/Server.java b/Main/src/main/java/com/chameleonvision/web/Server.java index 37dbcd88d..fef7c6bcf 100644 --- a/Main/src/main/java/com/chameleonvision/web/Server.java +++ b/Main/src/main/java/com/chameleonvision/web/Server.java @@ -2,9 +2,7 @@ package com.chameleonvision.web; import com.chameleonvision.NoCameraException; import com.chameleonvision.settings.SettingsManager; -import com.chameleonvision.vision.GeneralSettings; -import com.chameleonvision.vision.Pipeline; -import com.google.gson.JsonObject; +import edu.wpi.cscore.VideoException; import io.javalin.Javalin; import io.javalin.websocket.WsContext; @@ -34,8 +32,7 @@ public class Server { SettingsManager.getInstance().SaveSettings(); }); ws.onMessage(ctx -> { -// System.out.println(SettingsManager.getInstance().GetCurrentPipeline().); - broadcastMessage(ctx, ctx.message()); + broadcastMessage(ctx.message(), ctx); JSONObject jsonObject = new JSONObject(ctx.message()); String key = null; var jsonKeySetArray = jsonObject.keySet().toArray(); @@ -47,7 +44,7 @@ public class Server { if (key == null) return; Object value = jsonObject.get(key); // System.out.printf("Got websocket json data: [%s, %s]\n", key, value); - if (!setField(SettingsManager.getInstance().GetCurrentPipeline(), key, value)) { + if (!allFieldsToMap(SettingsManager.getInstance().GetCurrentPipeline()).containsKey(key)) { //If field not in pipeline switch (key) { case "change_general_settings_values": @@ -59,13 +56,14 @@ public class Server { System.out.printf("Changing camera to %s\n", newCamera); SettingsManager.getInstance().SetCurrentCamera(newCamera); //broadcastMessage((Map) new HashMap(){}.put("port",SettingsManager.CameraPorts.get(SettingsManager.GeneralSettings.curr_camera))); - //broadcastMessage(ctx, SettingsManager.getInstance().GetCurrentCamera()); //TODO CHECK JSON FOR CAMERA CHANGE + broadcastMessage(SettingsManager.getInstance().GetCurrentCamera()); //TODO CHECK JSON FOR CAMERA CHANGE break; case "curr_pipeline": String newPipeline = (String) value; System.out.printf("Changing pipeline to %s\n", newPipeline); SettingsManager.getInstance().SetCurrentPipeline(newPipeline); SettingsManager.CamerasCurrentPipeline.put(SettingsManager.GeneralSettings.curr_camera, newPipeline); + broadcastMessage(allFieldsToMap(SettingsManager.getInstance().GetCurrentPipeline())); break; case "resolution": int newResolution = (int) value; @@ -76,7 +74,7 @@ public class Server { break; case "fov": double newFov = (double) value; - System.out.printf("Changing FOV to %d\n", newFov); + System.out.printf("Changing FOV to %f\n", newFov); SettingsManager.getInstance().GetCurrentCamera().FOV = newFov; SettingsManager.getInstance().SaveSettings(); break; @@ -84,21 +82,29 @@ public class Server { System.out.printf("Unexpected value from websocket: [%s, %s]\n", key, value); break; } - } else { // + } else { + setField(SettingsManager.getInstance().GetCurrentPipeline(), key, value); + //Special cases for exposure and brightness + //TODO maybe add listener for value changes instead of this special case switch (key) { case "exposure": int newExposure = (int) value; System.out.printf("Changing exposure to %d\n", newExposure); SettingsManager.getInstance().GetCurrentPipeline().exposure = newExposure; - SettingsManager.getInstance().GetCurrentUsbCamera().setExposureManual(newExposure); - SettingsManager.getInstance().SaveSettings(); + try { + SettingsManager.getInstance().GetCurrentUsbCamera().setExposureManual(newExposure); + } + catch ( VideoException e) + { + System.out.println("Exposure changes is not supported on your webcam/webcam's driver"); + } + //TODO check if this crash occurs on linux break; case "brightness": int newBrightness = (int) value; System.out.printf("Changing brightness to %d\n", newBrightness); SettingsManager.getInstance().GetCurrentPipeline().brightness = newBrightness; SettingsManager.getInstance().GetCurrentUsbCamera().setBrightness(newBrightness); - SettingsManager.getInstance().SaveSettings(); break; } } @@ -107,14 +113,11 @@ public class Server { app.start(port); } - - public static boolean setField(Object obj, String fieldName, Object value) { - boolean successful = false; + private static void setField(Object obj, String fieldName, Object value) { try { Field[] fields = obj.getClass().getFields(); for (Field f : fields) { if (f.getName().equals(fieldName)) { - successful = true; if (BeanUtils.isSimpleValueType(value.getClass())) { f.set(obj, value); } else if (value.getClass() == JSONArray.class) { @@ -123,33 +126,20 @@ public class Server { } } } catch (IllegalAccessException e) { - return false; + System.out.println("IllegalAccessException "); + e.printStackTrace(); } - return successful; } - public static boolean setFields(Object obj, JSONObject data) { - boolean successful = false; - try { - Field[] fields = obj.getClass().getFields(); - for (Field f : fields) { - if (data.has(f.getName())) { - Object value = data.get(f.getName()); - if (BeanUtils.isSimpleValueType(value.getClass())) { - successful = true; - f.set(obj, value); - } - } - } - } catch (IllegalAccessException e) { - return false; - } - return successful; + private static void setFields(Object obj, JSONObject data) { + Map map = data.toMap(); + map.forEach((s, o) -> setField(obj,s,o)); } - public static void broadcastMessage(WsContext sendingUser, Object obj) {//TODO chekc if session id is a good way to differentiate users + + private static void broadcastMessage(Object obj, WsContext userToSkip) {//TODO chekc if session id is a good way to differentiate users for (var user : users) { - if (sendingUser!=null&& user.getSessionId().equals(sendingUser.getSessionId())) { + if (userToSkip != null && user.getSessionId().equals(userToSkip.getSessionId())) { continue; } if (obj.getClass() == String.class) @@ -161,7 +151,12 @@ public class Server { } } - private static void addAllFieldsToMap(Map map, Object obj) { + private static void broadcastMessage(Object obj) { + broadcastMessage(obj, null);//Broadcasts the message to ever user + } + + private static Map allFieldsToMap(Object obj) { + Map map = new HashMap<>(); try { Field[] fields = obj.getClass().getFields(); for (Field field : fields) @@ -169,15 +164,16 @@ public class Server { } catch (IllegalAccessException e) { System.err.println("Illegal Access error:" + e.getStackTrace().toString()); } + return map; } private static void sendFullSettings() { Map fullSettings = new HashMap<>(); //General settings - addAllFieldsToMap(fullSettings, SettingsManager.GeneralSettings); + fullSettings.putAll(allFieldsToMap(SettingsManager.GeneralSettings)); fullSettings.put("cameraList", SettingsManager.Cameras.keySet()); try { - addAllFieldsToMap(fullSettings, SettingsManager.getInstance().GetCurrentPipeline()); + fullSettings.putAll(allFieldsToMap(SettingsManager.getInstance().GetCurrentPipeline())); fullSettings.put("pipelineList", SettingsManager.getInstance().GetCurrentCamera().pipelines.keySet()); fullSettings.put("resolutionList", SettingsManager.getInstance().GetResolutionList()); fullSettings.put("resolution", SettingsManager.getInstance().GetCurrentCamera().resolution); @@ -187,7 +183,7 @@ public class Server { System.err.println("No camera found!"); //TODO: add message to ui to inform that there are no cameras } - broadcastMessage(null, fullSettings); + broadcastMessage(fullSettings); }