mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-03 03:01:40 +00:00
Added enums, msgpack - new ui intergration
This commit is contained in:
@@ -91,9 +91,14 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.msgpack</groupId>
|
<groupId>org.msgpack</groupId>
|
||||||
<artifactId>msgpack</artifactId>
|
<artifactId>msgpack-core</artifactId>
|
||||||
<version>0.6.12</version>
|
<version>0.8.18</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.msgpack</groupId>-->
|
||||||
|
<!-- <artifactId>msgpack</artifactId>-->
|
||||||
|
<!-- <version>0.6.12</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-beans</artifactId>
|
<artifactId>spring-beans</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.chameleonvision.vision;
|
||||||
|
|
||||||
|
public enum Orientation {
|
||||||
|
Normal,Inverted//TODO add 90 and 270 deg rotation?
|
||||||
|
}
|
||||||
@@ -6,20 +6,20 @@ import java.util.List;
|
|||||||
public class Pipeline {
|
public class Pipeline {
|
||||||
public int exposure = 50;
|
public int exposure = 50;
|
||||||
public int brightness = 50;
|
public int brightness = 50;
|
||||||
public String orientation = "Normal";
|
public Orientation orientation = Orientation.Normal;
|
||||||
public List<Integer> hue = Arrays.asList(50, 180);
|
public List<Integer> hue = Arrays.asList(50, 180);
|
||||||
public List<Integer> saturation = Arrays.asList(50, 255);
|
public List<Integer> saturation = Arrays.asList(50, 255);
|
||||||
public List<Integer> value = Arrays.asList(50, 255);
|
public List<Integer> value = Arrays.asList(50, 255);
|
||||||
public boolean erode = false;
|
public boolean erode = false;
|
||||||
public boolean dilate = false;
|
public boolean dilate = false;
|
||||||
public List<Integer> area = Arrays.asList(0, 100);
|
public List<Float> area = Arrays.asList(0f, 100f);
|
||||||
public List<Double> ratio = Arrays.asList(0D, 20D);
|
public List<Float> ratio = Arrays.asList(0f, 20f);
|
||||||
public List<Integer> extent = Arrays.asList(0, 100);
|
public List<Integer> extent = Arrays.asList(0, 100);
|
||||||
public int is_binary = 0;
|
public boolean isBinary = false;
|
||||||
public String sort_mode = "Largest";
|
public SortMode sortMode = SortMode.Largest;
|
||||||
public String target_group = "Single";
|
public TargetGroup targetGroup = TargetGroup.Single;
|
||||||
public String target_intersection = "Up";
|
public TargetIntersection targetIntersection = TargetIntersection.Up;
|
||||||
public double M = 1;
|
public double M = 1;
|
||||||
public double B = 0;
|
public double B = 0;
|
||||||
public boolean is_calibrated = false;
|
public boolean isCalibrated = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.chameleonvision.vision;
|
||||||
|
|
||||||
|
public enum SortMode {
|
||||||
|
Largest,Smallest,Highest,Lowest,Rightmost,Leftmost,Centermost
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.chameleonvision.vision;
|
||||||
|
|
||||||
|
public enum TargetGroup {
|
||||||
|
Single,Dual,Triple,Quadruple,Quintuple
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.chameleonvision.vision;
|
||||||
|
|
||||||
|
public enum TargetIntersection {
|
||||||
|
None,Up,Down,Left,Right
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ import java.util.stream.IntStream;
|
|||||||
|
|
||||||
public class Camera {
|
public class Camera {
|
||||||
|
|
||||||
private static final double DEFAULT_FOV = 60.8;
|
private static final float DEFAULT_FOV = 60.8f;
|
||||||
private static final int MINIMUM_FPS = 30;
|
private static final int MINIMUM_FPS = 30;
|
||||||
private static final int MINIMUM_WIDTH = 320;
|
private static final int MINIMUM_WIDTH = 320;
|
||||||
private static final int MINIMUM_HEIGHT = 200;
|
private static final int MINIMUM_HEIGHT = 200;
|
||||||
@@ -29,7 +29,7 @@ public class Camera {
|
|||||||
private final CvSink cvSink;
|
private final CvSink cvSink;
|
||||||
private final Object cvSourceLock = new Object();
|
private final Object cvSourceLock = new Object();
|
||||||
private CvSource cvSource;
|
private CvSource cvSource;
|
||||||
private double FOV;
|
private float FOV;
|
||||||
private CameraValues camVals;
|
private CameraValues camVals;
|
||||||
private CamVideoMode camVideoMode;
|
private CamVideoMode camVideoMode;
|
||||||
private int currentPipelineIndex;
|
private int currentPipelineIndex;
|
||||||
@@ -39,23 +39,23 @@ public class Camera {
|
|||||||
this(cameraName, DEFAULT_FOV);
|
this(cameraName, DEFAULT_FOV);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Camera(String cameraName, double fov) {
|
public Camera(String cameraName, float fov) {
|
||||||
this(cameraName,CameraManager.AllUsbCameraInfosByName.get(cameraName), fov);
|
this(cameraName,CameraManager.AllUsbCameraInfosByName.get(cameraName), fov);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Camera(String cameraName, UsbCameraInfo usbCamInfo, double fov) {
|
public Camera(String cameraName, UsbCameraInfo usbCamInfo, float fov) {
|
||||||
this(cameraName ,usbCamInfo, fov, new HashMap<>(), 0);
|
this(cameraName ,usbCamInfo, fov, new HashMap<>(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Camera(String cameraName, double fov, int videoModeIndex) {
|
public Camera(String cameraName, float fov, int videoModeIndex) {
|
||||||
this(cameraName, fov, new HashMap<>(), videoModeIndex);
|
this(cameraName, fov, new HashMap<>(), videoModeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Camera(String cameraName, double fov, HashMap<Integer, Pipeline> pipelines, int videoModeIndex) {
|
public Camera(String cameraName, float fov, HashMap<Integer, Pipeline> pipelines, int videoModeIndex) {
|
||||||
this(cameraName, CameraManager.AllUsbCameraInfosByName.get(cameraName), fov, pipelines, videoModeIndex);
|
this(cameraName, CameraManager.AllUsbCameraInfosByName.get(cameraName), fov, pipelines, videoModeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Camera(String cameraName, UsbCameraInfo usbCamInfo, double fov, HashMap<Integer, Pipeline> pipelines, int videoModeIndex) {
|
public Camera(String cameraName, UsbCameraInfo usbCamInfo, float fov, HashMap<Integer, Pipeline> pipelines, int videoModeIndex) {
|
||||||
FOV = fov;
|
FOV = fov;
|
||||||
name = cameraName;
|
name = cameraName;
|
||||||
path = usbCamInfo.path;
|
path = usbCamInfo.path;
|
||||||
@@ -158,11 +158,11 @@ public class Camera {
|
|||||||
.orElse(-1);
|
.orElse(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getFOV() {
|
public float getFOV() {
|
||||||
return FOV;
|
return FOV;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFOV(double fov) {
|
public void setFOV(float fov) {
|
||||||
FOV = fov;
|
FOV = fov;
|
||||||
camVals = new CameraValues(this);
|
camVals = new CameraValues(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class CameraDeserializer implements JsonDeserializer<Camera> {
|
|||||||
@Override
|
@Override
|
||||||
public Camera deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
|
public Camera deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
var jsonObj = jsonElement.getAsJsonObject();
|
var jsonObj = jsonElement.getAsJsonObject();
|
||||||
var camFOV = jsonObj.get("FOV").getAsDouble();
|
var camFOV = jsonObj.get("FOV").getAsFloat();
|
||||||
var camName = jsonObj.get("name").getAsString();
|
var camName = jsonObj.get("name").getAsString();
|
||||||
var videoModeIndex = jsonObj.get("resolution").getAsInt();
|
var videoModeIndex = jsonObj.get("resolution").getAsInt();
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import org.apache.commons.math3.util.FastMath;
|
|||||||
public class CameraValues {
|
public class CameraValues {
|
||||||
public final int ImageWidth;
|
public final int ImageWidth;
|
||||||
public final int ImageHeight;
|
public final int ImageHeight;
|
||||||
public final double FOV;
|
public final float FOV;
|
||||||
public final double ImageArea;
|
public final double ImageArea;
|
||||||
public final double CenterX;
|
public final double CenterX;
|
||||||
public final double CenterY;
|
public final double CenterY;
|
||||||
@@ -24,7 +24,7 @@ public class CameraValues {
|
|||||||
this(camera.getVideoMode().width, camera.getVideoMode().height, camera.getFOV());
|
this(camera.getVideoMode().width, camera.getVideoMode().height, camera.getFOV());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CameraValues(int imageWidth, int imageHeight, double fov) {
|
public CameraValues(int imageWidth, int imageHeight, float fov) {
|
||||||
ImageWidth = imageWidth;
|
ImageWidth = imageWidth;
|
||||||
ImageHeight = imageHeight;
|
ImageHeight = imageHeight;
|
||||||
FOV = fov;
|
FOV = fov;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.chameleonvision.vision.process;
|
package com.chameleonvision.vision.process;
|
||||||
|
|
||||||
|
import com.chameleonvision.vision.SortMode;
|
||||||
|
import com.chameleonvision.vision.TargetGroup;
|
||||||
|
import com.chameleonvision.vision.TargetIntersection;
|
||||||
import com.chameleonvision.vision.camera.CameraValues;
|
import com.chameleonvision.vision.camera.CameraValues;
|
||||||
import com.chameleonvision.util.MathHandler;
|
import com.chameleonvision.util.MathHandler;
|
||||||
import org.apache.commons.math3.util.FastMath;
|
import org.apache.commons.math3.util.FastMath;
|
||||||
@@ -14,13 +17,6 @@ import java.util.*;
|
|||||||
public class CVProcess {
|
public class CVProcess {
|
||||||
|
|
||||||
private final CameraValues cameraValues;
|
private final CameraValues cameraValues;
|
||||||
private HashMap<String, Integer> targetGrouping = new HashMap<>() {{
|
|
||||||
put("Single", 1);
|
|
||||||
put("Dual", 2);
|
|
||||||
put("Triple", 3);
|
|
||||||
put("Quadruple", 4);
|
|
||||||
put("Quintuple", 5);
|
|
||||||
}};
|
|
||||||
private Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
|
private Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
|
||||||
private Size blur = new Size(1,1);
|
private Size blur = new Size(1,1);
|
||||||
private Mat hsvImage = new Mat();
|
private Mat hsvImage = new Mat();
|
||||||
@@ -58,7 +54,7 @@ public class CVProcess {
|
|||||||
return foundContours;
|
return foundContours;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MatOfPoint> filterContours(List<MatOfPoint> inputContours, List<Integer> area, List<Double> ratio, List<Integer> extent) {
|
List<MatOfPoint> filterContours(List<MatOfPoint> inputContours, List<Float> area, List<Float> ratio, List<Integer> extent) {
|
||||||
for (MatOfPoint Contour : inputContours) {
|
for (MatOfPoint Contour : inputContours) {
|
||||||
try {
|
try {
|
||||||
double contourArea = Imgproc.contourArea(Contour);
|
double contourArea = Imgproc.contourArea(Contour);
|
||||||
@@ -97,34 +93,34 @@ public class CVProcess {
|
|||||||
Moments m = Imgproc.moments(c);
|
Moments m = Imgproc.moments(c);
|
||||||
return (m.get_m10()/m.get_m00());
|
return (m.get_m10()/m.get_m00());
|
||||||
}
|
}
|
||||||
RotatedRect sortTargetsToOne(List<RotatedRect> inputRects, String sortMode) {
|
RotatedRect sortTargetsToOne(List<RotatedRect> inputRects, SortMode sortMode) {
|
||||||
switch (sortMode) {
|
switch (sortMode) {
|
||||||
case "Largest":
|
case Largest:
|
||||||
return Collections.max(inputRects, Comparator.comparing(rect -> rect.size.area()));
|
return Collections.max(inputRects, Comparator.comparing(rect -> rect.size.area()));
|
||||||
case "Smallest":
|
case Smallest:
|
||||||
return Collections.min(inputRects, Comparator.comparing(rect -> rect.size.area()));
|
return Collections.min(inputRects, Comparator.comparing(rect -> rect.size.area()));
|
||||||
case "Highest":
|
case Highest:
|
||||||
return Collections.min(inputRects, Comparator.comparing(rect -> rect.center.y));
|
return Collections.min(inputRects, Comparator.comparing(rect -> rect.center.y));
|
||||||
case "Lowest":
|
case Lowest:
|
||||||
return Collections.max(inputRects, Comparator.comparing(rect -> rect.center.y));
|
return Collections.max(inputRects, Comparator.comparing(rect -> rect.center.y));
|
||||||
case "Leftmost":
|
case Leftmost:
|
||||||
return Collections.min(inputRects, Comparator.comparing(rect -> rect.center.x));
|
return Collections.min(inputRects, Comparator.comparing(rect -> rect.center.x));
|
||||||
case "Rightmost":
|
case Rightmost:
|
||||||
return Collections.max(inputRects, Comparator.comparing(rect -> rect.center.x));
|
return Collections.max(inputRects, Comparator.comparing(rect -> rect.center.x));
|
||||||
case "Centermost":
|
case Centermost:
|
||||||
return Collections.min(inputRects, sortByCentermostComparator);
|
return Collections.min(inputRects, sortByCentermostComparator);
|
||||||
default:
|
default:
|
||||||
return inputRects.get(0); // default to whatever the first contour is, but this should never happen
|
return inputRects.get(0); // default to whatever the first contour is, but this should never happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RotatedRect> groupTargets(List<MatOfPoint> inputContours, String intersectionPoint, String targetGroup) {
|
List<RotatedRect> groupTargets(List<MatOfPoint> inputContours, TargetIntersection intersectionPoint, TargetGroup targetGroup) {
|
||||||
finalCountours.clear();
|
finalCountours.clear();
|
||||||
if (!targetGroup.equals("Single")) {
|
if (!targetGroup.equals(TargetGroup.Single)) {
|
||||||
inputContours.sort(sortByMomentsX);
|
inputContours.sort(sortByMomentsX);
|
||||||
for (var i = 0; i < inputContours.size(); i++) {
|
for (var i = 0; i < inputContours.size(); i++) {
|
||||||
List<Point> FinalContourList = new ArrayList<>(inputContours.get(i).toList());
|
List<Point> FinalContourList = new ArrayList<>(inputContours.get(i).toList());
|
||||||
for (var c = 0; c < (targetGrouping.get(targetGroup) - 1); c++) {
|
for (var c = 0; c < targetGroup.ordinal(); c++) {
|
||||||
try {
|
try {
|
||||||
MatOfPoint firstContour = inputContours.get(i + c);
|
MatOfPoint firstContour = inputContours.get(i + c);
|
||||||
MatOfPoint secondContour = inputContours.get(i + c + 1);
|
MatOfPoint secondContour = inputContours.get(i + c + 1);
|
||||||
@@ -163,8 +159,8 @@ public class CVProcess {
|
|||||||
return finalCountours;
|
return finalCountours;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIntersecting(MatOfPoint ContourOne, MatOfPoint ContourTwo, String IntersectionPoint) {
|
private boolean isIntersecting(MatOfPoint ContourOne, MatOfPoint ContourTwo, TargetIntersection intersectionPoint) {
|
||||||
if (IntersectionPoint.equals("None")) {
|
if (intersectionPoint.equals(TargetIntersection.None)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -182,26 +178,26 @@ public class CVProcess {
|
|||||||
double intersectionY = (mA * (intersectionX - x0A)) + y0A;
|
double intersectionY = (mA * (intersectionX - x0A)) + y0A;
|
||||||
double massX = (x0A + x0B) / 2;
|
double massX = (x0A + x0B) / 2;
|
||||||
double massY = (y0A + y0B) / 2;
|
double massY = (y0A + y0B) / 2;
|
||||||
switch (IntersectionPoint) {
|
switch (intersectionPoint) {
|
||||||
case "Up": {
|
case Up: {
|
||||||
if (intersectionY < massY) {
|
if (intersectionY < massY) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Down": {
|
case Down: {
|
||||||
if (intersectionY > massY) {
|
if (intersectionY > massY) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Left": {
|
case Left: {
|
||||||
if (intersectionX < massX) {
|
if (intersectionX < massX) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Right": {
|
case Right: {
|
||||||
if (intersectionX > massX) {
|
if (intersectionX > massX) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.chameleonvision.vision.process;
|
package com.chameleonvision.vision.process;
|
||||||
|
|
||||||
import com.chameleonvision.settings.SettingsManager;
|
import com.chameleonvision.settings.SettingsManager;
|
||||||
|
import com.chameleonvision.vision.Orientation;
|
||||||
import com.chameleonvision.vision.Pipeline;
|
import com.chameleonvision.vision.Pipeline;
|
||||||
import com.chameleonvision.vision.camera.Camera;
|
import com.chameleonvision.vision.camera.Camera;
|
||||||
import com.chameleonvision.web.ServerHandler;
|
import com.chameleonvision.web.ServerHandler;
|
||||||
@@ -135,7 +136,7 @@ public class VisionProcess implements Runnable {
|
|||||||
if (currentPipeline == null) {
|
if (currentPipeline == null) {
|
||||||
return pipelineResult;
|
return pipelineResult;
|
||||||
}
|
}
|
||||||
if (!currentPipeline.orientation.equals("Normal")) {
|
if (currentPipeline.orientation.equals(Orientation.Inverted)) {
|
||||||
Core.flip(inputImage, inputImage, -1);
|
Core.flip(inputImage, inputImage, -1);
|
||||||
}
|
}
|
||||||
if (ntDriverModeEntry.getBoolean(false)) {
|
if (ntDriverModeEntry.getBoolean(false)) {
|
||||||
@@ -147,7 +148,7 @@ public class VisionProcess implements Runnable {
|
|||||||
|
|
||||||
cvProcess.hsvThreshold(inputImage, hsvThreshMat, hsvLower, hsvUpper, currentPipeline.erode, currentPipeline.dilate);
|
cvProcess.hsvThreshold(inputImage, hsvThreshMat, hsvLower, hsvUpper, currentPipeline.erode, currentPipeline.dilate);
|
||||||
|
|
||||||
if (currentPipeline.is_binary == 1) {
|
if (currentPipeline.isBinary == true) {
|
||||||
Imgproc.cvtColor(hsvThreshMat, outputImage, Imgproc.COLOR_GRAY2BGR, 3);
|
Imgproc.cvtColor(hsvThreshMat, outputImage, Imgproc.COLOR_GRAY2BGR, 3);
|
||||||
} else {
|
} else {
|
||||||
inputImage.copyTo(outputImage);
|
inputImage.copyTo(outputImage);
|
||||||
@@ -156,13 +157,13 @@ public class VisionProcess implements Runnable {
|
|||||||
if (foundContours.size() > 0) {
|
if (foundContours.size() > 0) {
|
||||||
filteredContours = cvProcess.filterContours(foundContours, currentPipeline.area, currentPipeline.ratio, currentPipeline.extent);
|
filteredContours = cvProcess.filterContours(foundContours, currentPipeline.area, currentPipeline.ratio, currentPipeline.extent);
|
||||||
if (filteredContours.size() > 0) {
|
if (filteredContours.size() > 0) {
|
||||||
groupedContours = cvProcess.groupTargets(filteredContours, currentPipeline.target_intersection, currentPipeline.target_group);
|
groupedContours = cvProcess.groupTargets(filteredContours, currentPipeline.targetIntersection, currentPipeline.targetGroup);
|
||||||
if (groupedContours.size() > 0) {
|
if (groupedContours.size() > 0) {
|
||||||
var finalRect = cvProcess.sortTargetsToOne(groupedContours, currentPipeline.sort_mode);
|
var finalRect = cvProcess.sortTargetsToOne(groupedContours, currentPipeline.sortMode);
|
||||||
// System.out.printf("Largest Contour Area: %.2f\n", finalRect.size.area());
|
// System.out.printf("Largest Contour Area: %.2f\n", finalRect.size.area());
|
||||||
pipelineResult.RawPoint = finalRect;
|
pipelineResult.RawPoint = finalRect;
|
||||||
pipelineResult.IsValid = true;
|
pipelineResult.IsValid = true;
|
||||||
if (!currentPipeline.is_calibrated) {
|
if (!currentPipeline.isCalibrated) {
|
||||||
pipelineResult.CalibratedX = camera.getCamVals().CenterX;
|
pipelineResult.CalibratedX = camera.getCamVals().CenterX;
|
||||||
pipelineResult.CalibratedY = camera.getCamVals().CenterY;
|
pipelineResult.CalibratedY = camera.getCamVals().CenterY;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -22,11 +22,10 @@ public class Server {
|
|||||||
System.out.println("Socket Disconnected");
|
System.out.println("Socket Disconnected");
|
||||||
SettingsManager.saveSettings();
|
SettingsManager.saveSettings();
|
||||||
});
|
});
|
||||||
ws.onMessage(ctx -> {
|
ws.onBinaryMessage(ctx -> {
|
||||||
// handler.onMessage(ctx);
|
handler.onBinaryMessage(ctx);
|
||||||
});
|
});
|
||||||
ws.onBinaryMessage(ctx->handler.onMessage(ctx));
|
app.start(port);
|
||||||
});
|
});
|
||||||
app.start(port);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,33 +1,33 @@
|
|||||||
package com.chameleonvision.web;
|
package com.chameleonvision.web;
|
||||||
|
|
||||||
|
import com.chameleonvision.vision.Orientation;
|
||||||
|
import com.chameleonvision.vision.SortMode;
|
||||||
|
import com.chameleonvision.vision.TargetGroup;
|
||||||
|
import com.chameleonvision.vision.TargetIntersection;
|
||||||
import com.chameleonvision.vision.camera.CameraException;
|
import com.chameleonvision.vision.camera.CameraException;
|
||||||
import com.chameleonvision.settings.SettingsManager;
|
import com.chameleonvision.settings.SettingsManager;
|
||||||
import com.chameleonvision.vision.camera.CameraManager;
|
import com.chameleonvision.vision.camera.CameraManager;
|
||||||
import edu.wpi.cscore.VideoException;
|
import edu.wpi.cscore.VideoException;
|
||||||
import io.javalin.websocket.*;
|
import io.javalin.websocket.*;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.json.JSONArray;
|
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
|
||||||
import org.json.JSONObject;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.msgpack.MessagePack;
|
import org.msgpack.core.MessagePack;
|
||||||
import org.msgpack.template.Templates;
|
import org.msgpack.core.MessageUnpacker;
|
||||||
import org.msgpack.type.ArrayValue;
|
import org.msgpack.value.ImmutableArrayValue;
|
||||||
import org.msgpack.type.BooleanValue;
|
import org.msgpack.value.ImmutableValue;
|
||||||
import org.msgpack.type.IntegerValue;
|
import org.msgpack.value.Value;
|
||||||
import org.msgpack.type.MapValue;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
public class ServerHandler {
|
public class ServerHandler {
|
||||||
|
|
||||||
private static List<WsContext> users;
|
private static List<WsContext> users;
|
||||||
private MessagePack msgpack;
|
|
||||||
|
|
||||||
ServerHandler() {
|
ServerHandler() {
|
||||||
users = new ArrayList<>();
|
users = new ArrayList<>();
|
||||||
msgpack = new MessagePack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConnect(WsConnectContext context) {
|
void onConnect(WsConnectContext context) {
|
||||||
@@ -39,103 +39,97 @@ public class ServerHandler {
|
|||||||
users.remove(context);
|
users.remove(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onMessage(WsBinaryMessageContext data) throws IOException {
|
void onBinaryMessage(WsBinaryMessageContext data) throws Exception {
|
||||||
byte[] b = ArrayUtils.toPrimitive(data.data());
|
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(ArrayUtils.toPrimitive(data.data()));
|
||||||
System.out.println(msgpack.read(b).isMapValue());
|
int length = unpacker.unpackMapHeader();
|
||||||
Map entries = msgpack.read(b,Templates.tMap(Templates.TString,Templates.TValue));
|
for (int mapIndex = 0; mapIndex < length; mapIndex++) {
|
||||||
System.out.println(Arrays.toString(entries.entrySet().toArray()));
|
String key = unpacker.unpackString(); // key
|
||||||
entries.forEach((k, value) -> {
|
Object value = get(unpacker.unpackValue());
|
||||||
/*
|
try {
|
||||||
To get int from value
|
if (hasField(CameraManager.getCurrentPipeline(), key)) {
|
||||||
((IntegerValue)value).getInt();
|
//Special cases for exposure and brightness and aspect ratio
|
||||||
|
switch (key) {
|
||||||
To get boolean from value
|
case "exposure":
|
||||||
((BooleanValue)value).getBoolean();
|
int newExposure = (int) value;
|
||||||
|
System.out.printf("Changing exposure to %d\n", newExposure);
|
||||||
To get Array from value
|
try {
|
||||||
((ArrayValue) value).toArray();
|
;
|
||||||
|
CameraManager.getCurrentCamera().setExposure(newExposure);
|
||||||
*/
|
} catch (VideoException e) {
|
||||||
String key = k.toString();
|
System.out.println("Exposure changes is not supported on your webcam/webcam's driver");
|
||||||
System.out.printf("Got websocket msgpack data: [%s, %s]\n", key, value);
|
}
|
||||||
|
break;
|
||||||
|
case "brightness":
|
||||||
try{
|
int newBrightness = (int) value;
|
||||||
if (hasField(CameraManager.getCurrentPipeline(), key)) {
|
System.out.printf("Changing brightness to %d\n", newBrightness);
|
||||||
//Special cases for exposure and brightness and aspect ratio
|
CameraManager.getCurrentCamera().setBrightness(newBrightness);
|
||||||
switch (key) {
|
break;
|
||||||
case "exposure":
|
case "ratio":
|
||||||
int newExposure = ((IntegerValue)value).getInt();
|
CameraManager.getCurrentPipeline().ratio=getFloatList((ImmutableArrayValue) value);
|
||||||
System.out.printf("Changing exposure to %d\n", newExposure);
|
break;
|
||||||
try {
|
case "area":
|
||||||
CameraManager.getCurrentCamera().setExposure(newExposure);
|
CameraManager.getCurrentPipeline().area=getFloatList((ImmutableArrayValue) value);
|
||||||
} catch (VideoException e) {
|
break;
|
||||||
System.out.println("Exposure changes is not supported on your webcam/webcam's driver");
|
//Enums
|
||||||
}
|
case "targetIntersection":
|
||||||
break;
|
setField(CameraManager.getCurrentPipeline(), key, TargetIntersection.values()[(int) value]);
|
||||||
case "brightness":
|
break;
|
||||||
int newBrightness = (int) value;
|
case "targetGroup":
|
||||||
System.out.printf("Changing brightness to %d\n", newBrightness);
|
setField(CameraManager.getCurrentPipeline(), key, TargetGroup.values()[(int) value]);
|
||||||
CameraManager.getCurrentCamera().setBrightness(newBrightness);
|
break;
|
||||||
break;
|
case "sortMode":
|
||||||
case "ratio":
|
setField(CameraManager.getCurrentPipeline(), key, SortMode.values()[(int) value]);
|
||||||
//If there is any better to convert Integer to Double you're welcome to change it
|
break;
|
||||||
List<Double> doubleRatio = CameraManager.getCurrentPipeline().ratio;
|
case "orientation":
|
||||||
List<Object> newRatio = ((JSONArray) value).toList();
|
setField(CameraManager.getCurrentPipeline(), key, Orientation.values()[(int) value]);
|
||||||
for (int i = 0; i < newRatio.size(); i++) {
|
break;
|
||||||
doubleRatio.set(i, Double.parseDouble(newRatio.get(i).toString()));
|
default:
|
||||||
}
|
//Any other field in CameraManager that doesn't need anything special
|
||||||
break;
|
setField(CameraManager.getCurrentPipeline(), key, value);
|
||||||
default:
|
break;
|
||||||
//Any other field in CameraManager that doesn't need anything special
|
}
|
||||||
setField(CameraManager.getCurrentPipeline(), key, value);
|
} else {
|
||||||
System.out.println("CameraManager.getCurrentPipeline().hue = " + CameraManager.getCurrentPipeline().hue.get(0));
|
switch (key) {
|
||||||
break;
|
case "change_general_settings_values":
|
||||||
|
Map<String, Object> map = (Map<String, Object>) value;
|
||||||
|
map.forEach((s, o) -> setField(SettingsManager.GeneralSettings, s, o));
|
||||||
|
SettingsManager.saveSettings();
|
||||||
|
break;
|
||||||
|
case "curr_camera":
|
||||||
|
String newCamera = (String) value;
|
||||||
|
System.out.printf("Changing camera to %s\n", newCamera);
|
||||||
|
CameraManager.setCurrentCamera(newCamera);
|
||||||
|
HashMap<String, Integer> portMap = new HashMap<>();
|
||||||
|
portMap.put("port", CameraManager.getCurrentCamera().getStreamPort());
|
||||||
|
sendFullSettings();
|
||||||
|
break;
|
||||||
|
case "curr_pipeline":
|
||||||
|
int newPipeline = (int) value;
|
||||||
|
System.out.printf("Changing pipeline to %s\n", newPipeline);
|
||||||
|
CameraManager.setCurrentPipeline(newPipeline);
|
||||||
|
CameraManager.getCurrentCameraProcess().ntPipelineEntry.setNumber(newPipeline);
|
||||||
|
broadcastMessage(allFieldsToMap(CameraManager.getCurrentPipeline()));
|
||||||
|
break;
|
||||||
|
case "resolution":
|
||||||
|
int newVideoMode = (int) value;
|
||||||
|
System.out.printf("Changing video mode to %d\n", newVideoMode);
|
||||||
|
CameraManager.getCurrentCamera().setCamVideoMode(newVideoMode, true);
|
||||||
|
break;
|
||||||
|
case "FOV":
|
||||||
|
float newFov = ((Integer) value) * 1F;//TODO check this
|
||||||
|
System.out.printf("Changing FOV to %f\n", newFov);
|
||||||
|
CameraManager.getCurrentCamera().setFOV(newFov);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.printf("Unexpected value from websocket: [%s, %s]\n", key, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} catch (CameraException e) {
|
||||||
switch (key) {
|
|
||||||
case "change_general_settings_values":
|
|
||||||
Map<String, Object> map = (Map<String, Object>) value;
|
|
||||||
map.forEach((s, o) -> setField(SettingsManager.GeneralSettings, s, o));
|
|
||||||
SettingsManager.saveSettings();
|
|
||||||
break;
|
|
||||||
case "curr_camera":
|
|
||||||
String newCamera = (String) value;
|
|
||||||
System.out.printf("Changing camera to %s\n", newCamera);
|
|
||||||
CameraManager.setCurrentCamera(newCamera);
|
|
||||||
HashMap<String, Integer> portMap = new HashMap<>();
|
|
||||||
portMap.put("port", CameraManager.getCurrentCamera().getStreamPort());
|
|
||||||
sendFullSettings();
|
|
||||||
break;
|
|
||||||
case "curr_pipeline":
|
|
||||||
int newPipeline = (int) value;
|
|
||||||
System.out.printf("Changing pipeline to %s\n", newPipeline);
|
|
||||||
CameraManager.setCurrentPipeline(newPipeline);
|
|
||||||
CameraManager.getCurrentCameraProcess().ntPipelineEntry.setNumber(newPipeline);
|
|
||||||
broadcastMessage(allFieldsToMap(CameraManager.getCurrentPipeline()));
|
|
||||||
break;
|
|
||||||
case "resolution":
|
|
||||||
int newVideoMode = (int) value;
|
|
||||||
System.out.printf("Changing video mode to %d\n", newVideoMode);
|
|
||||||
CameraManager.getCurrentCamera().setCamVideoMode(newVideoMode, true);
|
|
||||||
break;
|
|
||||||
case "FOV":
|
|
||||||
double newFov = Double.parseDouble(value.toString());//TODO check this
|
|
||||||
System.out.printf("Changing FOV to %f\n", newFov);
|
|
||||||
CameraManager.getCurrentCamera().setFOV(newFov);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.out.printf("Unexpected value from websocket: [%s, %s]\n", key, value);
|
|
||||||
break;
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
catch (CameraException e)
|
|
||||||
{
|
|
||||||
System.err.println("Camera error");
|
System.err.println("Camera error");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
broadcastMessage(entries, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setField(Object obj, String fieldName, Object value) {
|
private void setField(Object obj, String fieldName, Object value) {
|
||||||
@@ -143,33 +137,64 @@ public class ServerHandler {
|
|||||||
Field[] fields = obj.getClass().getFields();
|
Field[] fields = obj.getClass().getFields();
|
||||||
for (Field f : fields) {
|
for (Field f : fields) {
|
||||||
if (f.getName().equals(fieldName)) {
|
if (f.getName().equals(fieldName)) {
|
||||||
if (BeanUtils.isSimpleValueType(value.getClass())) {
|
if (BeanUtils.isSimpleValueType(f.getType())) {
|
||||||
f.set(obj, value);
|
f.set(obj, value);
|
||||||
} else if (value.getClass() == ArrayValue.class) {
|
} else if (value instanceof ImmutableArrayValue) {
|
||||||
f.set(obj, ((ArrayValue) value).toArray());
|
List<Value> valLst = ((ImmutableArrayValue) value).list();
|
||||||
|
List<Object> lst = new ArrayList<>();
|
||||||
|
for (Value val : valLst) {
|
||||||
|
lst.add(get((ImmutableValue) val));
|
||||||
|
}
|
||||||
|
f.set(obj, lst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (Exception e) {
|
||||||
System.out.println("IllegalAccessException ");
|
System.out.println("Exception setting field ");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object get(ImmutableValue v) throws Exception {
|
||||||
private static void broadcastMessage(Object obj, WsContext userToSkip) {//TODO check if session id is a good way to differentiate users
|
//TODO find a smarter way to write this
|
||||||
for (var user : users) {
|
if (v.isIntegerValue())
|
||||||
if (userToSkip != null && user.getSessionId().equals(userToSkip.getSessionId())) {
|
return v.asIntegerValue().toInt();
|
||||||
continue;
|
if (v.isFloatValue())
|
||||||
}
|
return v.asFloatValue().toFloat();
|
||||||
user.send(obj);
|
if (v.isArrayValue()) {
|
||||||
// if (obj.getClass() == String.class)
|
return v.asArrayValue();
|
||||||
// user.send((String) obj);
|
|
||||||
// else if (obj.getClass() == HashMap.class)
|
|
||||||
// user.send(new JSONObject((HashMap<String, Object>) obj).toString());
|
|
||||||
// else
|
|
||||||
// user.send(new JSONObject(obj).toString());
|
|
||||||
}
|
}
|
||||||
|
if (v.isBinaryValue())
|
||||||
|
return v.asBinaryValue().asByteArray();
|
||||||
|
if (v.isBooleanValue())
|
||||||
|
return v.asBooleanValue().getBoolean();
|
||||||
|
if (v.isMapValue())
|
||||||
|
return v.asMapValue().map();
|
||||||
|
if (v.isStringValue())
|
||||||
|
return v.asStringValue().asString();
|
||||||
|
throw new Exception("Value not recognized");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Float> getFloatList(ImmutableArrayValue arrayValue) {
|
||||||
|
List<Float> output = new ArrayList<>();
|
||||||
|
List<Value> values = arrayValue.list();
|
||||||
|
for (Value v:values) {
|
||||||
|
if (v.isFloatValue())
|
||||||
|
output.add(v.asFloatValue().toFloat());
|
||||||
|
else
|
||||||
|
output.add((float) v.asIntegerValue().toInt());
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void broadcastMessage(Object obj, WsContext userToSkip) {
|
||||||
|
if (users != null)
|
||||||
|
for (var user : users) {
|
||||||
|
if (userToSkip != null && user.getSessionId().equals(userToSkip.getSessionId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
user.send(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void broadcastMessage(Object obj) {//TODO fix sending for msgpack
|
public static void broadcastMessage(Object obj) {//TODO fix sending for msgpack
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<CVrangeSlider v-model="value.Area" name="Area" :min="0" :max="100" :step="0.1" @input="handleInput('Area',value.Area)"></CVrangeSlider>
|
<CVrangeSlider v-model="value.Area" name="Area" :min="0" :max="100" :step="0.1" @input="handleInput('area',value.Area)"></CVrangeSlider>
|
||||||
<CVrangeSlider v-model="value.Ratio" name="Ratio (W/H)" :min="0" :max="100" :step="0.1" @input="handleInput('ratio',value.Ratio)"></CVrangeSlider>
|
<CVrangeSlider v-model="value.Ratio" name="Ratio (W/H)" :min="0" :max="100" :step="0.1" @input="handleInput('ratio',value.Ratio)"></CVrangeSlider>
|
||||||
<CVrangeSlider v-model="value.Extent" name="Extent" :min="0" :max="100" @input="handleInput('Extent',value.Extent)"></CVrangeSlider>
|
<CVrangeSlider v-model="value.Extent" name="Extent" :min="0" :max="100" @input="handleInput('extent',value.Extent)"></CVrangeSlider>
|
||||||
<CVselect name="Target Group" :list="['Single','Dual','Triple','Quadruple','Quintuple']" v-model="value.TargetGrouping" @input="handleInput('TargetGrouping',value.TargetGrouping)"></CVselect>
|
<CVselect name="Target Group" :list="['Single','Dual','Triple','Quadruple','Quintuple']" v-model="value.TargetGrouping" @input="handleInput('targetGroup',value.TargetGrouping)"></CVselect>
|
||||||
<CVselect name="Target Intersection" :list="['None','Up','Down','Left','Right']" :disabled="isDisabled" v-model="value.TargetIntersection" @input="handleInput('TargetIntersection',value.TargetIntersection)"></CVselect>
|
<CVselect name="Target Intersection" :list="['None','Up','Down','Left','Right']" :disabled="isDisabled" v-model="value.TargetIntersection" @input="handleInput('targetIntersection',value.TargetIntersection)"></CVselect>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<CVslider name="Exposure" v-model="value.Exposure" @input="handleInput('exposure',value.Exposure)" :min="0" :max="100"></CVslider>
|
<CVslider name="Exposure" v-model="value.Exposure" :min="0" :max="100" @input="handleInput('exposure',value.Exposure)"></CVslider>
|
||||||
<CVslider name="Brightness" v-model="value.Brightness" :min="0" :max="100" @input="handleInput('Brightness',value.Brightness)"></CVslider>
|
<CVslider name="Brightness" v-model="value.Brightness" :min="0" :max="100" @input="handleInput('brightness',value.Brightness)"></CVslider>
|
||||||
<CVselect name="Orientation" v-model="value.Orientation" :list="['Normal','Inverted']" @input="handleInput('Orientation',value.Orientation)"></CVselect>
|
<CVselect name="Orientation" v-model="value.Orientation" :list="['Normal','Inverted']" @input="handleInput('orientation',value.Orientation)"></CVselect>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<CVselect name="SortMode" v-model="value.SortMode" :list="['Largest','Smallest','Highest','Lowest','Rightmost','Leftmost','Closest']" @input="handleInput('SortMode',value.SortMode)"></CVselect>
|
<CVselect name="SortMode" v-model="value.SortMode" :list="['Largest','Smallest','Highest','Lowest','Rightmost','Leftmost','Centermost']" @input="handleInput('sortMode',value.SortMode)"></CVselect>
|
||||||
<span>Calibrate:</span><v-divider dark color="white"></v-divider>
|
<span>Calibrate:</span><v-divider dark color="white"></v-divider>
|
||||||
<v-row align="center" justify="start">
|
<v-row align="center" justify="start">
|
||||||
<v-col style="padding-right:0px" :cols="3">
|
<v-col style="padding-right:0px" :cols="3">
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<CVrangeSlider v-model="value.Hue" name="Hue" :min="0" :max="180" @input="handleInput('hue',value.Hue)"></CVrangeSlider>
|
<CVrangeSlider v-model="value.Hue" name="Hue" :min="0" :max="180" @input="handleInput('hue',value.Hue)"></CVrangeSlider>
|
||||||
<CVrangeSlider v-model="value.Saturation" name="Saturation" :min="0" :max="255" @input="handleInput('Saturation',value.Saturation)"></CVrangeSlider>
|
<CVrangeSlider v-model="value.Saturation" name="Saturation" :min="0" :max="255" @input="handleInput('saturation',value.Saturation)"></CVrangeSlider>
|
||||||
<CVrangeSlider v-model="value.Value" name="Value" :min="0" :max="255" @input="handleInput('Value',value.Value)"></CVrangeSlider>
|
<CVrangeSlider v-model="value.Value" name="Value" :min="0" :max="255" @input="handleInput('value',value.Value)"></CVrangeSlider>
|
||||||
<CVswitch v-model="value.Erode" name="Erode" @input="handleInput('Erode',value.Erode)"></CVswitch>
|
<CVswitch v-model="value.Erode" name="Erode" @input="handleInput('erode',value.Erode)"></CVswitch>
|
||||||
<CVswitch v-model="value.Dilate" name="Dilate" @input="handleInput('Dilate',value.Dilate)"></CVswitch>
|
<CVswitch v-model="value.Dilate" name="Dilate" @input="handleInput('dilate',value.Dilate)"></CVswitch>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user