Continue plumbing ServerHandler

This commit is contained in:
Banks Troutman
2019-11-23 04:05:37 -05:00
parent b19ae1f43b
commit 9b3e611eaa
21 changed files with 362 additions and 280 deletions

View File

@@ -115,7 +115,6 @@ public class Main {
if (!CurrentPlatform.isRoot()) {
if (ignoreRoot) {
// TODO: should we do this?
// manageNetwork = false;
System.out.println("Ignoring root, network will not be managed!");
} else {

View File

@@ -1,29 +1,27 @@
package com.chameleonvision.classabstraction;
import com.chameleonvision.classabstraction.camera.CameraProcess;
import com.chameleonvision.classabstraction.camera.USBCameraProcess;
import com.chameleonvision.classabstraction.config.CameraConfig;
import com.chameleonvision.classabstraction.config.ConfigManager;
import com.chameleonvision.settings.Platform;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.util.FileHelper;
import com.chameleonvision.vision.camera.CameraException;
import com.chameleonvision.vision.camera.USBCamera;
import edu.wpi.cscore.UsbCamera;
import edu.wpi.cscore.UsbCameraInfo;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.videoio.VideoCapture;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
public class VisionManager {
private VisionManager() {}
private static final Path CamConfigPath = Paths.get(SettingsManager.SettingsPath.toString(), "cameras");
public static final LinkedHashMap<String, UsbCameraInfo> UsbCameraInfosByCameraName = new LinkedHashMap<>();
private static final LinkedHashMap<String, UsbCameraInfo> UsbCameraInfosByCameraName = new LinkedHashMap<>();
private static final LinkedList<CameraConfig> LoadedCameraConfigs = new LinkedList<>();
public static final LinkedHashMap<String, VisionProcess> VisionProcessesByCameraName = new LinkedHashMap<>();
private static final LinkedHashMap<Integer, Pair<VisionProcess, String>> VisionProcessesByIndex = new LinkedHashMap<>();
private static VisionProcess currentUIVisionProcess;
public static boolean initializeSources() {
int suffix = 0;
@@ -44,8 +42,6 @@ public class VisionManager {
return false;
}
FileHelper.CheckPath(CamConfigPath);
// load the config
List<CameraConfig> preliminaryConfigs = new ArrayList<>();
@@ -62,6 +58,8 @@ public class VisionManager {
});
LoadedCameraConfigs.addAll(ConfigManager.initializeCameraConfig(preliminaryConfigs));
// TODO: (HIGH) Load pipelines from json
// UsbCameraInfosByCameraName.forEach((cameraName, cameraInfo) -> {
// Path cameraConfigFolder = Paths.get(CamConfigPath.toString(), String.format("%s\\", cameraName));
// Path cameraConfigPath = Paths.get(cameraConfigFolder.toString(), String.format("%s.json", cameraName));
@@ -72,23 +70,43 @@ public class VisionManager {
}
public static boolean initializeProcesses() {
LoadedCameraConfigs.forEach(config -> {
var camera = new USBCameraProcess(config);
VisionProcessesByCameraName.put(config.name, new VisionProcess(camera, config.name));
});
for (int i = 0; i < LoadedCameraConfigs.size(); i++) {
CameraConfig config = LoadedCameraConfigs.get(i);
CameraProcess camera = new USBCameraProcess(config);
VisionProcess process = new VisionProcess(camera, config.name);
VisionProcessesByIndex.put(i, Pair.of(process, config.name));
}
currentUIVisionProcess = VisionProcessesByIndex.get(0).getLeft();
return true;
}
public static void startProcesses() {
VisionProcessesByCameraName.forEach((name, process) -> {
process.start();
VisionProcessesByIndex.forEach((index, processNamePair) -> {
processNamePair.getLeft().start();
});
}
public static VisionProcess getCurrentCamera() throws CameraException {
if (VisionProcessesByCameraName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
var curCam = VisionProcessesByCameraName.get(SettingsManager.generalSettings.currentCamera);
if (curCam == null) throw new CameraException(CameraException.CameraExceptionType.BAD_CAMERA);
return curCam;
public static VisionProcess getCurrentUIVisionProcess() {
return currentUIVisionProcess;
}
public static void setCurrentProcessByIndex(int processIndex) {
if (processIndex > VisionProcessesByIndex.size() - 1) {
return;
}
currentUIVisionProcess = VisionProcessesByIndex.get(processIndex).getLeft();
}
public static VisionProcess getVisionProcessByIndex(int processIndex) {
if (processIndex > VisionProcessesByIndex.size() - 1) {
return null;
}
return VisionProcessesByIndex.get(0).getLeft();
}
public static List<String> getAllCameraNicknames() {
return VisionProcessesByIndex.values().stream().map(processNamePair -> processNamePair.getLeft().getCamera().getProperties().getNickname()).collect(Collectors.toList());
}
}

View File

@@ -5,6 +5,7 @@ import com.chameleonvision.classabstraction.camera.CameraStreamer;
import com.chameleonvision.classabstraction.config.ConfigManager;
import com.chameleonvision.classabstraction.pipeline.*;
import com.chameleonvision.classabstraction.util.LoopingRunnable;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.web.ServerHandler;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -26,11 +27,13 @@ public class VisionProcess {
private final CameraFrameRunnable cameraRunnable;
private final CameraStreamerRunnable streamRunnable;
private final VisionProcessRunnable visionRunnable;
private final CameraStreamer cameraStreamer;
public final CameraStreamer cameraStreamer;
private CVPipeline currentPipeline;
private int currentPipelineIndex = 0;
private final CVPipelineSettings driverVisionSettings = new CVPipelineSettings();
private final CVPipelineSettings driverModeSettings = new CVPipelineSettings();
private CVPipeline driverModePipeline = new DriverVisionPipeline(driverModeSettings);
// shitty stuff
private volatile Mat lastCameraFrame = new Mat();
@@ -38,27 +41,27 @@ public class VisionProcess {
private volatile CVPipelineResult lastPipelineResult;
// network table stuff
public NetworkTableEntry ntPipelineEntry;
public NetworkTableEntry ntDriverModeEntry;
private NetworkTableEntry ntPipelineEntry;
private NetworkTableEntry ntDriverModeEntry;
private int ntDriveModeListenerID;
private int ntPipelineListenerID;
private NetworkTableEntry ntYawEntry;
private NetworkTableEntry ntPitchEntry;
private NetworkTableEntry ntAuxListEntry;
private NetworkTableEntry ntDistanceEntry;
private NetworkTableEntry ntAreaEntry;
private NetworkTableEntry ntTimeStampEntry;
private NetworkTableEntry ntValidEntry;
Gson gson = new GsonBuilder().setPrettyPrinting().create();
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
public VisionProcess(CameraProcess cameraProcess, String name) {
VisionProcess(CameraProcess cameraProcess, String name) {
this.cameraProcess = cameraProcess;
pipelines.add(new DriverVisionPipeline(() -> driverVisionSettings));
pipelines.add(new CVPipeline2d("New Pipeline"));
setPipeline(0);
// Thread to grab frames from the camera
// TODO: fix video modes!!!
// TODO: FIX FPS!!!!!!!
// TODO: (HIGH) fix video modes!!!
// TODO: (HIGH) FIX FPS!!!!!!!
this.cameraRunnable = new CameraFrameRunnable(cameraProcess.getProperties().videoModes.get(0).fps);
lastPipelineResult = new DriverVisionPipeline.DriverPipelineResult(
@@ -106,7 +109,7 @@ public class VisionProcess {
ntDriverModeEntry = newTable.getEntry("driver_mode");
ntPitchEntry = newTable.getEntry("pitch");
ntYawEntry = newTable.getEntry("yaw");
ntDistanceEntry = newTable.getEntry("distance");
ntAreaEntry = newTable.getEntry("area");
ntTimeStampEntry = newTable.getEntry("timestamp");
ntValidEntry = newTable.getEntry("is_valid");
ntDriveModeListenerID = ntDriverModeEntry.addListener(this::setDriverMode, EntryListenerFlags.kUpdate);
@@ -115,8 +118,16 @@ public class VisionProcess {
ntPipelineEntry.setNumber(0);
}
private void setDriverMode(EntryNotification ignored) {
setPipeline(0);
private void setDriverMode(EntryNotification driverModeEntryNotification) {
setDriverMode(driverModeEntryNotification.value.getBoolean());
}
public void setDriverMode(boolean driverMode) {
if (driverMode) {
setPipelineInternal(driverModePipeline);
} else {
setPipeline(currentPipelineIndex);
}
}
/**
@@ -135,25 +146,23 @@ public class VisionProcess {
}
public void setPipeline(int pipelineIndex) {
CVPipeline newPipeline = pipelines.get(pipelineIndex);
if (newPipeline != null) {
setPipelineInternal(newPipeline);
}
currentPipelineIndex = pipelineIndex;
// update the configManager
if(ConfigManager.settings.currentCamera.equals(cameraProcess.getProperties().name)) {
ConfigManager.settings.currentPipeline = pipelineIndex;
HashMap<String, Object> pipeChange = new HashMap<>();
pipeChange.put("currentPipeline", pipelineIndex);
ServerHandler.broadcastMessage(pipeChange);
ServerHandler.sendFullSettings();
// update the configManager
if(ConfigManager.settings.currentCamera.equals(cameraProcess.getProperties().name)) {
ConfigManager.settings.currentPipeline = pipelineIndex;
HashMap<String, Object> pipeChange = new HashMap<>();
pipeChange.put("currentPipeline", pipelineIndex);
ServerHandler.broadcastMessage(pipeChange);
ServerHandler.sendFullSettings();
}
}
}
private void setPipelineInternal(CVPipeline pipeline) {
pipelines.add(pipeline);
currentPipeline = pipeline;
currentPipeline.initPipeline(cameraProcess);
}
@@ -165,14 +174,15 @@ public class VisionProcess {
HashMap<String, Object> calculated = new HashMap<>();
List<Double> center = new ArrayList<>();
if (data.hasTarget) {
if(data instanceof CVPipeline2d.CVPipeline2dResult) {
CVPipeline2d.CVPipeline2dResult result = (CVPipeline2d.CVPipeline2dResult) data;
CVPipeline2d.Target bestTarget = result.targets.get(0);
CVPipeline2d.Target2d bestTarget = result.targets.get(0);
center.add(bestTarget.rawPoint.center.x);
center.add(bestTarget.rawPoint.center.y);
calculated.put("pitch", bestTarget.pitch);
calculated.put("yaw", bestTarget.yaw);
} else if (data instanceof CVPipeline3d.CVPipeline3dResult) {
// TODO: (2.1) 3d stuff in UI
} else {
center.add(0.0);
center.add(0.0);
@@ -200,19 +210,19 @@ public class VisionProcess {
ntTimeStampEntry.setDouble(data.processTime);
//noinspection unchecked
List<CVPipeline2d.Target> targets = (List<CVPipeline2d.Target>) data.targets;
List<CVPipeline2d.Target2d> targets = (List<CVPipeline2d.Target2d>) data.targets;
ntPitchEntry.setDouble(targets.get(0).pitch);
ntYawEntry.setDouble(targets.get(0).yaw);
ntDistanceEntry.setDouble(targets.get(0).area);
ntAreaEntry.setDouble(targets.get(0).area);
ntAuxListEntry.setString(gson.toJson(targets));
} else if(data instanceof CVPipeline3d.CVPipeline3dResult) {
// TODO implement
} else if (data instanceof CVPipeline3d.CVPipeline3dResult) {
// TODO: (2.1) 3d stuff...
}
} else {
ntPitchEntry.setDouble(0.0);
ntYawEntry.setDouble(0.0);
ntDistanceEntry.setDouble(0.0);
ntAreaEntry.setDouble(0.0);
ntTimeStampEntry.setDouble(0.0);
}
}
@@ -222,10 +232,43 @@ public class VisionProcess {
cameraStreamer.setNewVideoMode(newMode);
}
public List<CVPipeline> getPipelines() {
return pipelines;
}
public CVPipeline getCurrentPipeline() {
return currentPipeline;
}
public int getCurrentPipelineIndex() {
return currentPipelineIndex;
}
public void addPipeline() {
// TODO: (2.1) add to UI option between 2d and 3d pipeline
pipelines.add(new CVPipeline2d());
}
public void addPipeline(CVPipeline pipeline) {
pipelines.add(pipeline);
}
public CameraProcess getCamera() {
return cameraProcess;
}
public boolean getDriverMode() {
return (currentPipeline == driverModePipeline);
}
public CVPipelineSettings getDriverModeSettings() {
return driverModePipeline.settings;
}
public CVPipeline getPipelineByIndex(int pipelineIndex) {
return pipelines.get(pipelineIndex);
}
/**
* CameraFrameRunnable grabs images from the cameraProcess
* at a specified loopTime
@@ -243,7 +286,7 @@ public class VisionProcess {
*/
CameraFrameRunnable(int cameraFPS) {
// add 2 FPS to allow for a bit of overhead
// TODO: test the affect of this
// TODO: (low) test the effect of this
super(1000L/(cameraFPS + 2));
}
@@ -281,7 +324,7 @@ public class VisionProcess {
*/
private class VisionProcessRunnable implements Runnable {
public Double fps = 0.0; // TODO update or average or something
public Double fps = 0.0; // TODO: (HIGH) update or average or something
private CVPipelineResult result;
private Mat streamBuffer = new Mat();
@@ -311,19 +354,19 @@ public class VisionProcess {
} else {
// System.err.println("Bad streambuffer mat");
}
// TODO do something with the result
// TODO: (HIGH) do something with the result
}
}
}
private class CameraStreamerRunnable extends LoopingRunnable {
private final CameraStreamer streamer;
public final CameraStreamer streamer;
private Mat streamBuffer = new Mat();
private CameraStreamerRunnable(int cameraFPS, CameraStreamer streamer) {
// add 2 FPS to allow for a bit of overhead
// TODO: test the affect of this
// TODO: (low) test the effect of this
super(1000L/(cameraFPS + 2));
this.streamer = streamer;
}

View File

@@ -5,7 +5,7 @@ import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Mat;
public interface CameraProcess {
CameraProperties getProperties();
USBCameraProperties getProperties();
/**
* Get the next camera frame

View File

@@ -1,6 +1,7 @@
package com.chameleonvision.classabstraction.camera;
import com.chameleonvision.vision.camera.StreamDivisor;
import com.chameleonvision.web.ServerHandler;
import edu.wpi.cscore.CvSource;
import edu.wpi.cscore.VideoMode;
import edu.wpi.first.cameraserver.CameraServer;
@@ -35,7 +36,11 @@ public class CameraStreamer {
cameraProcess.getProperties().staticProperties.imageWidth / divisor.value,
cameraProcess.getProperties().staticProperties.imageHeight / divisor.value);
}
// ServerHandler.sendFullSettings();
ServerHandler.sendFullSettings();
}
public StreamDivisor getDivisor() {
return divisor;
}
public void setNewVideoMode(VideoMode newVideoMode) {
@@ -57,5 +62,4 @@ public class CameraStreamer {
// }
cvSource.putFrame(streamBuffer);
}
}

View File

@@ -13,18 +13,18 @@ public class USBCameraProcess implements CameraProcess {
private final UsbCamera baseCamera;
private final CvSink cvSink;
private Mat imageBuffer = new Mat();
private CameraProperties properties;
private USBCameraProperties properties;
public USBCameraProcess(CameraConfig config) {
baseCamera = new UsbCamera(config.name, config.path);
cvSink = CameraServer.getInstance().getVideo(baseCamera);
properties = new CameraProperties(baseCamera, config);
properties = new USBCameraProperties(baseCamera, config);
setVideoMode(properties.videoModes.get(0));
}
@Override
public CameraProperties getProperties() {
public USBCameraProperties getProperties() {
return properties;
}

View File

@@ -1,101 +1,101 @@
package com.chameleonvision.classabstraction.camera;
import com.chameleonvision.classabstraction.config.CameraConfig;
import com.chameleonvision.settings.Platform;
import edu.wpi.cscore.UsbCamera;
import edu.wpi.cscore.VideoMode;
import org.apache.commons.math3.util.FastMath;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CameraProperties {
public static final double DEFAULT_FOV = 70;
private static final int DEFAULT_EXPOSURE = 50;
private static final int DEFAULT_BRIGHTNESS = 50;
private static final int MINIMUM_FPS = 30;
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<VideoMode.PixelFormat> ALLOWED_PIXEL_FORMATS = Arrays.asList(VideoMode.PixelFormat.kYUYV, VideoMode.PixelFormat.kMJPEG);
private static final Predicate<VideoMode> kMinFPSPredicate = (videoMode -> videoMode.fps >= MINIMUM_FPS);
private static final Predicate<VideoMode> kMinSizePredicate = (videoMode -> videoMode.width >= MINIMUM_WIDTH && videoMode.height >= MINIMUM_HEIGHT);
private static final Predicate<VideoMode> kPixelFormatPredicate = (videoMode -> ALLOWED_PIXEL_FORMATS.contains(videoMode.pixelFormat));
public CameraStaticProperties staticProperties;
public final String name;
public final String path;
public final double FOV;
public final List<VideoMode> videoModes;
private final UsbCamera baseCamera;
private String nickname;
public final boolean hasGain;
public CameraProperties(UsbCamera baseCamera, CameraConfig config) {
FOV = config.fov;
name = config.name;
path = config.path;
nickname = config.nickname;
this.baseCamera = baseCamera;
// wait for camera USB init on Windows, Windows USB is slow...
if (Platform.CurrentPlatform == Platform.WINDOWS_64 && !baseCamera.isConnected()) {
System.out.print("Waiting on camera... ");
long initTimeout = System.nanoTime();
while (!baseCamera.isConnected()) {
if (((System.nanoTime() - initTimeout) / 1e6) >= MAX_INIT_MS) {
break;
}
}
var initTimeMs = (System.nanoTime() - initTimeout) / 1e6;
System.out.printf("USBCameraProcess initialized in %.2fms\n", initTimeMs);
}
// TODO: find way to determine if camera is a PS3Eye
hasGain = false;
// var props = baseCamera.enumerateProperties();
// for (var prop : props) {
// var name = prop.getName();
// var min = prop.getMin();
// var max = prop.getMax();
// var _default = prop.getDefault();
// var kind = prop.getKind();
// }
videoModes = filterVideoModes(baseCamera.enumerateVideoModes());
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getNickname() {
return nickname;
}
private List<VideoMode> filterVideoModes(VideoMode[] videoModes) {
Predicate<VideoMode> fullPredicate = kMinFPSPredicate.and(kMinSizePredicate).and(kPixelFormatPredicate);
Stream<VideoMode> validModes = Arrays.stream(videoModes).filter(fullPredicate);
return validModes.collect(Collectors.toList());
}
public void updateVideoMode(VideoMode videoMode) {
staticProperties = new CameraStaticProperties(videoMode.width, videoMode.height, FOV);
}
public double calculatePitch(double PixelY, double centerY) {
double pitch = FastMath.toDegrees(FastMath.atan((PixelY - centerY) / staticProperties.verticalFocalLength));
return (pitch * -1);
}
public double calculateYaw(double PixelX, double centerX) {
return FastMath.toDegrees(FastMath.atan((PixelX - centerX) / staticProperties.horizontalFocalLength));
}
}
package com.chameleonvision.classabstraction.camera;
import com.chameleonvision.classabstraction.config.CameraConfig;
import com.chameleonvision.settings.Platform;
import edu.wpi.cscore.UsbCamera;
import edu.wpi.cscore.VideoMode;
import org.apache.commons.math3.util.FastMath;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class USBCameraProperties {
public static final double DEFAULT_FOV = 70;
private static final int DEFAULT_EXPOSURE = 50;
private static final int DEFAULT_BRIGHTNESS = 50;
private static final int MINIMUM_FPS = 30;
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<VideoMode.PixelFormat> ALLOWED_PIXEL_FORMATS = Arrays.asList(VideoMode.PixelFormat.kYUYV, VideoMode.PixelFormat.kMJPEG);
private static final Predicate<VideoMode> kMinFPSPredicate = (videoMode -> videoMode.fps >= MINIMUM_FPS);
private static final Predicate<VideoMode> kMinSizePredicate = (videoMode -> videoMode.width >= MINIMUM_WIDTH && videoMode.height >= MINIMUM_HEIGHT);
private static final Predicate<VideoMode> kPixelFormatPredicate = (videoMode -> ALLOWED_PIXEL_FORMATS.contains(videoMode.pixelFormat));
public CameraStaticProperties staticProperties;
public final String name;
public final String path;
public final List<VideoMode> videoModes;
private final UsbCamera baseCamera;
private String nickname;
public double FOV;
public final boolean hasGain;
public USBCameraProperties(UsbCamera baseCamera, CameraConfig config) {
FOV = config.fov;
name = config.name;
path = config.path;
nickname = config.nickname;
this.baseCamera = baseCamera;
// wait for camera USB init on Windows, Windows USB is slow...
if (Platform.CurrentPlatform == Platform.WINDOWS_64 && !baseCamera.isConnected()) {
System.out.print("Waiting on camera... ");
long initTimeout = System.nanoTime();
while (!baseCamera.isConnected()) {
if (((System.nanoTime() - initTimeout) / 1e6) >= MAX_INIT_MS) {
break;
}
}
var initTimeMs = (System.nanoTime() - initTimeout) / 1e6;
System.out.printf("USBCameraProcess initialized in %.2fms\n", initTimeMs);
}
// TODO: (low) find way to determine if camera is a PS3Eye
hasGain = false;
// var props = baseCamera.enumerateProperties();
// for (var prop : props) {
// var name = prop.getName();
// var min = prop.getMin();
// var max = prop.getMax();
// var _default = prop.getDefault();
// var kind = prop.getKind();
// }
videoModes = filterVideoModes(baseCamera.enumerateVideoModes());
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getNickname() {
return nickname;
}
private List<VideoMode> filterVideoModes(VideoMode[] videoModes) {
Predicate<VideoMode> fullPredicate = kMinFPSPredicate.and(kMinSizePredicate).and(kPixelFormatPredicate);
Stream<VideoMode> validModes = Arrays.stream(videoModes).filter(fullPredicate);
return validModes.collect(Collectors.toList());
}
public void updateVideoMode(VideoMode videoMode) {
staticProperties = new CameraStaticProperties(videoMode.width, videoMode.height, FOV);
}
public double calculatePitch(double PixelY, double centerY) {
double pitch = FastMath.toDegrees(FastMath.atan((PixelY - centerY) / staticProperties.verticalFocalLength));
return (pitch * -1);
}
public double calculateYaw(double PixelX, double centerX) {
return FastMath.toDegrees(FastMath.atan((PixelX - centerX) / staticProperties.horizontalFocalLength));
}
}

View File

@@ -1,6 +1,6 @@
package com.chameleonvision.classabstraction.config;
import com.chameleonvision.classabstraction.camera.CameraProperties;
import com.chameleonvision.classabstraction.camera.USBCameraProperties;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -23,7 +23,7 @@ public class CameraConfig {
}
public CameraConfig(String path, String name) {
this.fov = CameraProperties.DEFAULT_FOV;
this.fov = USBCameraProperties.DEFAULT_FOV;
this.path = path;
this.name = name;
this.nickname = name;

View File

@@ -1,6 +1,6 @@
package com.chameleonvision.classabstraction.config;
import com.chameleonvision.classabstraction.camera.CameraProperties;
import com.chameleonvision.classabstraction.camera.USBCameraProperties;
import com.chameleonvision.classabstraction.camera.USBCameraProcess;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
@@ -16,7 +16,7 @@ public class CameraSerializer extends StdSerializer<USBCameraProcess> {
@Override
public void serialize(USBCameraProcess value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
CameraProperties camProps = value.getProperties();
USBCameraProperties camProps = value.getProperties();
gen.writeNumberField("FOV", camProps.FOV);
gen.writeStringField("Name", camProps.name);
gen.writeStringField("Path", camProps.path);

View File

@@ -1,8 +0,0 @@
package com.chameleonvision.classabstraction.config;
import com.chameleonvision.classabstraction.pipeline.PipelineType;
public class PipelineConfig {
public PipelineType type;
// TODO: config stuff
}

View File

@@ -3,6 +3,7 @@ package com.chameleonvision.classabstraction.pipeline;
import com.chameleonvision.classabstraction.camera.CameraProcess;
import org.opencv.core.Mat;
import java.lang.reflect.Type;
import java.util.function.Supplier;
/**
@@ -12,20 +13,21 @@ import java.util.function.Supplier;
public abstract class CVPipeline<R extends CVPipelineResult, S extends CVPipelineSettings> {
protected Mat outputMat = new Mat();
CameraProcess cameraProcess;
final Supplier<S> settingsSupplier;
public final S settings;
public CVPipeline(Supplier<S> settingsSupplier) {
this.settingsSupplier = settingsSupplier;
protected CVPipeline(S settings) {
this.settings = settings;
}
public S getSettings() {
return settingsSupplier.get();
protected CVPipeline(String pipelineName, S settings) {
this.settings = settings;
settings.nickname = pipelineName;
}
public void initPipeline(CameraProcess camera) {
cameraProcess = camera;
cameraProcess.setExposure((int) getSettings().exposure);
cameraProcess.setBrightness((int) getSettings().brightness);
cameraProcess.setExposure((int) settings.exposure);
cameraProcess.setBrightness((int) settings.brightness);
}
abstract public R runPipeline(Mat inputMat);
}

View File

@@ -8,7 +8,6 @@ import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import java.util.List;
import java.util.function.Supplier;
import static com.chameleonvision.classabstraction.pipeline.CVPipeline2d.*;
@@ -18,8 +17,16 @@ public class CVPipeline2d extends CVPipeline<CVPipeline2dResult, CVPipeline2dSet
private Mat rawCameraMat = new Mat();
private Mat hsvOutputMat = new Mat();
public CVPipeline2d(Supplier<CVPipeline2dSettings> settingsSupplier) {
super(settingsSupplier);
public CVPipeline2d() {
super(new CVPipeline2dSettings());
}
public CVPipeline2d(String name) {
super(name, new CVPipeline2dSettings());
}
public CVPipeline2d(CVPipeline2dSettings settings) {
super(settings);
}
@Override
@@ -32,7 +39,6 @@ public class CVPipeline2d extends CVPipeline<CVPipeline2dResult, CVPipeline2dSet
long totalProcessTimeNanos = 0;
StringBuilder procTimeStringBuilder = new StringBuilder();
var settings = settingsSupplier.get();
CameraStaticProperties camProps = cameraProcess.getProperties().staticProperties;
rawCameraMat = inputMat;
@@ -104,7 +110,7 @@ public class CVPipeline2d extends CVPipeline<CVPipeline2dResult, CVPipeline2dSet
totalProcessTimeNanos += sortContoursResult.getRight();
procTimeStringBuilder.append(String.format("SortContours: %.2fms, ", sortContoursResult.getRight() / 1000.0));
Pair<List<Target>, Long> collect2dTargetsResult = collect2dTargetsPipe.run(sortContoursResult.getLeft());
Pair<List<Target2d>, Long> collect2dTargetsResult = collect2dTargetsPipe.run(sortContoursResult.getLeft());
totalProcessTimeNanos += collect2dTargetsResult.getRight();
procTimeStringBuilder.append(String.format("SortContours: %.2fms, ", sortContoursResult.getRight() / 1000.0));
@@ -124,13 +130,13 @@ public class CVPipeline2d extends CVPipeline<CVPipeline2dResult, CVPipeline2dSet
return new CVPipeline2dResult(collect2dTargetsResult.getLeft(), draw2dContoursResult.getLeft(), totalProcessTimeNanos / 1000);
}
public static class CVPipeline2dResult extends CVPipelineResult<Target> {
public CVPipeline2dResult(List<Target> targets, Mat outputMat, long processTime) {
public static class CVPipeline2dResult extends CVPipelineResult<Target2d> {
public CVPipeline2dResult(List<Target2d> targets, Mat outputMat, long processTime) {
super(targets, outputMat, processTime);
}
}
public static class Target {
public static class Target2d {
public double calibratedX = 0.0;
public double calibratedY = 0.0;
public double pitch = 0.0;

View File

@@ -10,8 +10,9 @@ import static com.chameleonvision.classabstraction.pipeline.CVPipeline3d.*;
public class CVPipeline3d extends CVPipeline<CVPipeline3dResult, CVPipeline3dSettings> {
public CVPipeline3d(Supplier<CVPipeline3dSettings> settingsSupplier) {
super(settingsSupplier);
protected CVPipeline3d(CVPipeline3dSettings settings) {
super(settings);
}
@Override
@@ -27,7 +28,6 @@ public class CVPipeline3d extends CVPipeline<CVPipeline3dResult, CVPipeline3dSet
}
public static class Target3d {
// TODO: Define 3d-specific target data
// TODO: (2.1) Define 3d-specific target data
}
}

View File

@@ -1,5 +1,5 @@
package com.chameleonvision.classabstraction.pipeline;
public class CVPipeline3dSettings extends CVPipeline2dSettings {
// TODO:
// TODO: (2.1) define 3d-specific pipeline settings
}

View File

@@ -5,7 +5,7 @@ import com.chameleonvision.vision.*;
@SuppressWarnings("ALL")
public class CVPipelineSettings {
public ImageFlipMode flipMode = ImageFlipMode.NONE;
public String nickname = "";
public String nickname = "New Pipeline";
public double exposure = 50.0;
public double brightness = 50.0;
}

View File

@@ -11,8 +11,8 @@ import static com.chameleonvision.classabstraction.pipeline.DriverVisionPipeline
public class DriverVisionPipeline extends CVPipeline<DriverPipelineResult, CVPipelineSettings> {
public DriverVisionPipeline(Supplier<CVPipelineSettings> settingsSupplier) {
super(settingsSupplier);
public DriverVisionPipeline(CVPipelineSettings settings) {
super(settings);
}
@Override

View File

@@ -10,14 +10,14 @@ import org.opencv.core.RotatedRect;
import java.util.ArrayList;
import java.util.List;
public class Collect2dTargetsPipe implements Pipe<List<RotatedRect>, List<CVPipeline2d.Target>> {
public class Collect2dTargetsPipe implements Pipe<List<RotatedRect>, List<CVPipeline2d.Target2d>> {
private final CalibrationMode calibrationMode;
private final CameraStaticProperties camProps;
private final List<Number> calibrationPoint;
private final double calibrationM, calibrationB;
private List<CVPipeline2d.Target> targets = new ArrayList<>();
private List<CVPipeline2d.Target2d> targets = new ArrayList<>();
public Collect2dTargetsPipe(CalibrationMode calibrationMode, List<Number> calibrationPoint, double calibrationM, double calibrationB, CameraStaticProperties camProps) {
this.calibrationMode = calibrationMode;
@@ -28,11 +28,11 @@ public class Collect2dTargetsPipe implements Pipe<List<RotatedRect>, List<CVPipe
}
@Override
public Pair<List<CVPipeline2d.Target>, Long> run(List<RotatedRect> input) {
public Pair<List<CVPipeline2d.Target2d>, Long> run(List<RotatedRect> input) {
long processStartNanos = System.nanoTime();
input.forEach(r -> {
CVPipeline2d.Target t = new CVPipeline2d.Target();
CVPipeline2d.Target2d t = new CVPipeline2d.Target2d();
t.rawPoint = r;
switch (calibrationMode) {
case None:

View File

@@ -19,7 +19,7 @@ public class NetworkInterface {
IPAddress = inetAddress.getHostAddress();
Netmask = getIPv4LocalNetMask(ifaceAddress);
// TODO: hack to "get" gateway, this is gross and bad, pls fix
// TODO: (low) hack to "get" gateway, this is gross and bad, pls fix
var splitIPAddr = IPAddress.split("\\.");
splitIPAddr[3] = "1";
Gateway = String.join(".", splitIPAddr);

View File

@@ -1,5 +1,7 @@
package com.chameleonvision.vision;
public enum Orientation {
Normal,Inverted//TODO add 90 and 270 deg rotation?
//TODO: (low) add 90 and 270 deg rotation?
Normal,
Inverted;
}

View File

@@ -4,7 +4,6 @@ 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;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.web.ServerHandler;
import edu.wpi.cscore.VideoException;
@@ -131,7 +130,7 @@ public class VisionProcess implements Runnable {
private PipelineResult runVisionProcess(Mat inputImage, Mat outputImage) {
if (cvPipeline2d == null) {
cvPipeline2d = new CVPipeline2d(() -> pipelineTo2dSettings(currentPipeline));
cvPipeline2d = new CVPipeline2d(pipelineTo2dSettings(currentPipeline));
}
CVPipeline2dResult result = cvPipeline2d.runPipeline(inputImage);
result.outputMat.copyTo(outputImage);
@@ -145,7 +144,7 @@ public class VisionProcess implements Runnable {
pipeResult.Yaw = 0;
pipeResult.Area = 0;
} else {
Target t = result.targets.get(0);
Target2d t = result.targets.get(0);
pipeResult.CalibratedX = t.calibratedX;
pipeResult.CalibratedY = t.calibratedY;
pipeResult.Pitch = t.pitch;

View File

@@ -1,8 +1,13 @@
package com.chameleonvision.web;
import com.chameleonvision.classabstraction.VisionManager;
import com.chameleonvision.classabstraction.VisionProcess;
import com.chameleonvision.classabstraction.camera.CameraProcess;
import com.chameleonvision.classabstraction.config.ConfigManager;
import com.chameleonvision.classabstraction.pipeline.CVPipeline;
import com.chameleonvision.classabstraction.pipeline.CVPipelineSettings;
import com.chameleonvision.vision.*;
import com.chameleonvision.vision.camera.StreamDivisor;
import com.chameleonvision.vision.camera.USBCamera;
import com.chameleonvision.vision.camera.CameraException;
import com.chameleonvision.settings.SettingsManager;
@@ -43,9 +48,14 @@ public class ServerHandler {
});
for (Map.Entry<String, Object> entry : deserialized.entrySet()) {
try {
var data = (HashMap<String, Object>) entry.getValue();
VisionProcess currentProcess = VisionManager.getCurrentUIVisionProcess();
CameraProcess currentCamera = currentProcess.getCamera();
CVPipeline currentPipeline = currentProcess.getCurrentPipeline();
switch (entry.getKey()) {
case "generalSettings": {
for (HashMap.Entry<String, Object> e : ((HashMap<String, Object>) entry.getValue()).entrySet()) {
for (HashMap.Entry<String, Object> e : data.entrySet()) {
setField(ConfigManager.settings, e.getKey(), e.getValue());
}
SettingsManager.saveSettings();
@@ -53,45 +63,47 @@ public class ServerHandler {
break;
}
case "driverMode": {
for (HashMap.Entry<String, Object> e : ((HashMap<String, Object>) entry.getValue()).entrySet()) {
setField(VisionManager.getCurrentCamera(), e.getKey(), e.getValue());
for (HashMap.Entry<String, Object> e : data.entrySet()) {
setField(VisionManager.getCurrentUIVisionProcess(), e.getKey(), e.getValue());
}
VisionManager.getCurrentCamera().setDriverMode((Boolean) ((HashMap<String, Object>) entry.getValue()).get("isDriver"));
VisionManager.saveCameras();
VisionManager.getCurrentUIVisionProcess().setDriverMode((Boolean) data.get("isDriver"));
// TODO: (HIGH) create saveCameras() function in VisionManager
// VisionManager.saveCameras();
break;
}
case "cameraSettings": {
HashMap camSettings = (HashMap) entry.getValue();
var curCam = VisionManager.getCurrentCamera();
Number newFOV = (Number) camSettings.get("fov");
Integer newStreamDivisor = (Integer) camSettings.get("streamDivisor");
StreamDivisor newStreamDivisor = StreamDivisor.values()[(Integer) camSettings.get("streamDivisor")];
Integer newResolution = (Integer) camSettings.get("resolution");
curCam.setFOV(newFOV);
currentCamera.getProperties().FOV = (double) newFOV;
var currentStreamDivisorOrdinal = curCam.getStreamDivisor().ordinal();
if (currentStreamDivisorOrdinal != newStreamDivisor) {
curCam.setStreamDivisor(newStreamDivisor, true);
if (currentProcess.cameraStreamer.getDivisor() != newStreamDivisor) {
currentProcess.cameraStreamer.setDivisor(newStreamDivisor);
}
var currentResolutionIndex = curCam.getVideoModeIndex();
if (currentResolutionIndex != newResolution) {
curCam.setCamVideoMode(newResolution, true);
}
// TODO (HIGH) get and set video modes!
// var currentResolutionIndex = currentPipeline.getVideoModeIndex();
// if (currentResolutionIndex != newResolution) {
// currentCamera.getProperties().setCamVideoMode(newResolution, true);
// }
VisionManager.saveCameras();
// TODO: (HIGH) create saveCameras() function in VisionManager
// VisionManager.saveCameras();
sendFullSettings();
break;
}
case "changeCameraName": {
VisionManager.getCurrentCamera().setNickname((String) entry.getValue());
currentCamera.getProperties().setNickname((String) entry.getValue());
sendFullSettings();
SettingsManager.saveSettings();
break;
}
case "changePipelineName": {
VisionManager.getCurrentPipeline().nickname = (String) entry.getValue();
currentPipeline.settings.nickname = ((String) entry.getValue());
sendFullSettings();
SettingsManager.saveSettings();
break;
@@ -101,38 +113,44 @@ public class ServerHandler {
int pipelineIndex = (int) pipelineVals.get("pipeline");
int cameraIndex = (int) pipelineVals.get("camera");
Pipeline origPipeline = VisionManager.getCurrentCamera().getPipelineByIndex(pipelineIndex);
CVPipeline origPipeline = currentProcess.getPipelineByIndex(pipelineIndex);
if (cameraIndex != -1) {
VisionManager.getCameraByIndex(cameraIndex).addPipeline(origPipeline);
VisionProcess newProcess = VisionManager.getVisionProcessByIndex(cameraIndex);
if(newProcess != null) {
newProcess.addPipeline(origPipeline);
}
} else {
VisionManager.getCurrentCamera().addPipeline(origPipeline);
currentProcess.addPipeline(origPipeline);
}
// TODO: (HIGH) switch to ConfigManager
SettingsManager.saveSettings();
break;
}
case "command": {
var cam = VisionManager.getCurrentCamera();
switch ((String) entry.getValue()) {
case "addNewPipeline":
cam.addPipeline();
currentProcess.addPipeline();
sendFullSettings();
// TODO: (HIGH) switch to ConfigManager
SettingsManager.saveSettings();
break;
// TODO: (HIGH) this never worked before, re-visit now that VisionProcess is written sanely
case "deleteCurrentPipeline":
int currentIndex = cam.getCurrentPipelineIndex();
int nextIndex;
if (currentIndex == cam.getPipelines().size() - 1) {
nextIndex = currentIndex - 1;
} else {
nextIndex = currentIndex;
}
cam.deletePipeline();
cam.setCurrentPipelineIndex(nextIndex);
sendFullSettings();
SettingsManager.saveSettings();
// int currentIndex = currentProcess.getCurrentPipelineIndex();
// int nextIndex;
// if (currentIndex == currentProcess.getPipelines().size() - 1) {
// nextIndex = currentIndex - 1;
// } else {
// nextIndex = currentIndex;
// }
// cam.deletePipeline();
// cam.setCurrentPipelineIndex(nextIndex);
// sendFullSettings();
// SettingsManager.saveSettings();
break;
case "save":
// TODO: (HIGH) switch to ConfigManager
SettingsManager.saveSettings();
System.out.println("saved Settings");
break;
@@ -141,30 +159,31 @@ public class ServerHandler {
break;
}
case "currentCamera": {
VisionManager.setCurrentCamera((Integer) entry.getValue());
// TODO: (HIGH) find way to map cameras to indexes
VisionManager.setCurrentProcessByIndex((Integer) entry.getValue());
sendFullSettings();
break;
}
case "currentPipeline": {
var cam = VisionManager.getCurrentCamera();
cam.setCurrentPipelineIndex((Integer) entry.getValue());
currentProcess.setPipeline((Integer) entry.getValue());
sendFullSettings();
try {
cam.setBrightness(cam.getCurrentPipeline().brightness);
cam.setExposure(cam.getCurrentPipeline().exposure);
currentCamera.setBrightness((int) currentPipeline.settings.brightness);
currentCamera.setExposure((int) currentPipeline.settings.exposure);
} catch (Exception e) {
continue;
}
break;
}
default: {
setField(VisionManager.getCurrentCamera().getCurrentPipeline(), entry.getKey(), entry.getValue());
setField(currentPipeline.settings, entry.getKey(), entry.getValue());
switch (entry.getKey()) {
case "exposure": {
VisionManager.getCurrentCamera().setExposure((Integer) entry.getValue());
currentCamera.setExposure((Integer) entry.getValue());
}
case "brightness": {
VisionManager.getCurrentCamera().setBrightness((Integer) entry.getValue());
currentCamera.setBrightness((Integer) entry.getValue());
}
}
break;
@@ -180,7 +199,9 @@ public class ServerHandler {
private void setField(Object obj, String fieldName, Object value) {
try {
if (obj instanceof USBCamera) {
var cam = (USBCamera)obj;
// TODO: (HIGH) FIXXX!!!! this won't work anymore
// the UI should instead understand that DriverMode is a pipeline (?)
USBCamera cam = (USBCamera)obj;
if (fieldName.equals("driverBrightness")) {
cam.setDriverBrightness((Integer)value);
} else if (fieldName.equals("driverExposure")) {
@@ -199,7 +220,7 @@ public class ServerHandler {
private static void broadcastMessage(Object obj, WsContext userToSkip) {
if (users != null)
for (var user : users) {
for (WsContext user : users) {
if (userToSkip != null && user.getSessionId().equals(userToSkip.getSessionId())) {
continue;
}
@@ -220,9 +241,9 @@ public class ServerHandler {
HashMap<String, Object> tmp = new HashMap<>();
for (Field f : Pipeline.class.getFields()) {
if (!f.getType().isEnum()) {
tmp.put(f.getName(), f.get(VisionManager.getCurrentCamera().getCurrentPipeline()));
tmp.put(f.getName(), f.get(VisionManager.getCurrentUIVisionProcess().getCurrentPipeline()));
} else {
var i = (Enum) f.get(VisionManager.getCurrentCamera().getCurrentPipeline());
var i = (Enum) f.get(VisionManager.getCurrentUIVisionProcess().getCurrentPipeline());
tmp.put(f.getName(), i.ordinal());
}
}
@@ -242,27 +263,22 @@ public class ServerHandler {
private static HashMap<String, Object> getOrdinalCameraSettings() {
HashMap<String, Object> tmp = new HashMap<>();
try {
var currentCamera = VisionManager.getCurrentCamera();
tmp.put("fov", currentCamera.getFOV());
tmp.put("streamDivisor", currentCamera.getStreamDivisor().ordinal());
tmp.put("resolution", currentCamera.getVideoModeIndex());
} catch (CameraException e) {
e.printStackTrace();
}
VisionProcess currentVisionProcess = VisionManager.getCurrentUIVisionProcess();
CameraProcess currentCamera = VisionManager.getCurrentUIVisionProcess().getCamera();
tmp.put("fov", currentCamera.getProperties().FOV);
tmp.put("streamDivisor", currentVisionProcess.cameraStreamer.getDivisor().ordinal());
// TODO: (HIGH) get videomode index!
// tmp.put("resolution", currentCamera.getVideoModeIndex());
return tmp;
}
private static HashMap<String, Object> getOrdinalDriver() {
HashMap<String, Object> tmp = new HashMap<>();
try {
var currentCamera = VisionManager.getCurrentCamera();
tmp.put("isDriver", currentCamera.getDriverMode());
tmp.put("driverBrightness", currentCamera.getDriverBrightness());
tmp.put("driverExposure", currentCamera.getDriverExposure());
} catch (CameraException e) {
e.printStackTrace();
}
VisionProcess currentProcess = VisionManager.getCurrentUIVisionProcess();
CVPipelineSettings driverModeSettings = currentProcess.getDriverModeSettings();
tmp.put("isDriver", currentProcess.getDriverMode());
tmp.put("driverBrightness", driverModeSettings.brightness);
tmp.put("driverExposure", driverModeSettings.exposure);
return tmp;
}
@@ -272,15 +288,16 @@ public class ServerHandler {
try {
fullSettings.put("settings", getOrdinalSettings());
fullSettings.put("cameraSettings", getOrdinalCameraSettings());
fullSettings.put("cameraList", VisionManager.getAllCameraByNickname());
fullSettings.put("cameraList", VisionManager.getAllCameraNicknames());
fullSettings.put("pipeline", getOrdinalPipeline());
var currentCamera = VisionManager.getCurrentCamera();
var currentVisionProcess = VisionManager.getCurrentUIVisionProcess();
fullSettings.put("driverMode",getOrdinalDriver());
fullSettings.put("pipelineList", currentCamera.getPipelinesNickname());
fullSettings.put("resolutionList", currentCamera.getResolutionList());
fullSettings.put("port", currentCamera.getStreamPort());
fullSettings.put("currentPipelineIndex", VisionManager.getCurrentCamera().getCurrentPipelineIndex());
fullSettings.put("currentCameraIndex", VisionManager.getCurrentCameraIndex());
// TODO (HIGH) all of these settings!
// fullSettings.put("pipelineList", currentVisionProcess.getPipelinesNickname());
// fullSettings.put("resolutionList", currentVisionProcess.getResolutionList());
// fullSettings.put("port", currentVisionProcess.getStreamPort());
fullSettings.put("currentPipelineIndex", VisionManager.getCurrentUIVisionProcess().getCurrentPipelineIndex());
// fullSettings.put("currentCameraIndex", VisionManager.getCurrentCameraIndex());
} catch (CameraException | IllegalAccessException e) {
System.err.println("No camera found!");
}