mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-26 01:51:40 +00:00
Source manager (#99)
* Add some config stuff, run format * Create JacksonUtils.java * Fix deserialization, run wpiformat * initial work on source manager * work on USB camera class * wip USB Camera * rename root folder * added USB Camera Source * Fix some errors, run spotless * finished VIsion source manager * bugfix unversioned git files and added default cam config constructor * Apply spotless, add simpler CameraConfiguration ctor * [WIP] unit tests * Fixed camera mocking * added equal test for class * finalized test * added another cam to test & rebase * test bugfix * Better handle nonexistant files * removed camera validation and mockito * Update WPI maven repo to dev, change to version with VideoCapture fix * added Quirky camera class * remove name check for cam quirk , apply spotless * added quirk test Co-authored-by: Matt <matthew.morley.ca@gmail.com> Co-authored-by: Banks Troutman <btrout.dhrs@gmail.com>
This commit is contained in:
2
chameleon-server/.gitignore
vendored
2
chameleon-server/.gitignore
vendored
@@ -3,4 +3,4 @@ bin/*
|
||||
.project
|
||||
.classpath
|
||||
*.prefs
|
||||
chameleonVision
|
||||
chameleon-vision
|
||||
@@ -15,13 +15,14 @@ shadowJar {
|
||||
sourceCompatibility = 11
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = 'https://frcmaven.wpi.edu:443/artifactory/release'
|
||||
url = 'https://frcmaven.wpi.edu:443/artifactory/development'
|
||||
}
|
||||
}
|
||||
ext {
|
||||
wpilibVersion = '2020.2.2'
|
||||
wpilibVersion = '2020.3.2-75-g1557a4c'
|
||||
openCVVersion = '3.4.7-2'
|
||||
}
|
||||
|
||||
@@ -68,35 +69,6 @@ dependencies {
|
||||
|
||||
testCompile "ch.qos.logback:logback-classic:0.9.26"
|
||||
|
||||
// javacv (ew)
|
||||
// def withoutJunk = {
|
||||
// exclude group: 'org.bytedeco', module: 'artoolkitplus'
|
||||
// exclude group: 'org.bytedeco', module: 'artoolkitplus-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'flandmark'
|
||||
// exclude group: 'org.bytedeco', module: 'flandmark-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'flycapture'
|
||||
// exclude group: 'org.bytedeco', module: 'flycapture-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'leptonica'
|
||||
// exclude group: 'org.bytedeco', module: 'leptonica-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'libdc1394'
|
||||
// exclude group: 'org.bytedeco', module: 'libdc1394-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'libfreenect'
|
||||
// exclude group: 'org.bytedeco', module: 'libfreenect-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'libfreenect2'
|
||||
// exclude group: 'org.bytedeco', module: 'libfreenect2-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'librealsense'
|
||||
// exclude group: 'org.bytedeco', module: 'librealsense-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'librealsense2'
|
||||
// exclude group: 'org.bytedeco', module: 'librealsense2-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'openblas'
|
||||
// exclude group: 'org.bytedeco', module: 'openblas-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'tesseract'
|
||||
// exclude group: 'org.bytedeco', module: 'tesseract-platform'
|
||||
// exclude group: 'org.bytedeco', module: 'ffmpeg'
|
||||
// exclude group: 'org.bytedeco', module: 'ffmpeg-platform'
|
||||
// }
|
||||
// compile 'org.bytedeco:javacv-platform:1.5.2', withoutJunk
|
||||
|
||||
// test stuff
|
||||
testImplementation('org.junit.jupiter:junit-jupiter:5.6.0')
|
||||
}
|
||||
|
||||
@@ -3,20 +3,58 @@ package com.chameleonvision.common.configuration;
|
||||
import com.chameleonvision.common.calibration.CameraCalibrationCoefficients;
|
||||
import com.chameleonvision.common.logging.LogGroup;
|
||||
import com.chameleonvision.common.logging.Logger;
|
||||
import com.chameleonvision.common.vision.camera.CameraType;
|
||||
import com.chameleonvision.common.vision.pipeline.CVPipelineSettings;
|
||||
import com.chameleonvision.common.vision.pipeline.DriverModePipelineSettings;
|
||||
import com.chameleonvision.common.vision.processes.PipelineManager;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CameraConfiguration {
|
||||
private static final Logger logger = new Logger(CameraConfiguration.class, LogGroup.Camera);
|
||||
|
||||
public String name = "";
|
||||
public String baseName = "";
|
||||
public String uniqueName = "";
|
||||
public String nickname = "";
|
||||
public double FOV = 70;
|
||||
public String path = "";
|
||||
public CameraType cameraType = CameraType.UsbCamera;
|
||||
public CameraCalibrationCoefficients calibration;
|
||||
public List<Integer> CameraLEDs = new ArrayList<>();
|
||||
|
||||
public CameraConfiguration(String baseName, String path) {
|
||||
this(baseName, baseName, baseName, path);
|
||||
}
|
||||
|
||||
public CameraConfiguration(String baseName, String uniqueName, String nickname, String path) {
|
||||
this.baseName = baseName;
|
||||
this.uniqueName = uniqueName;
|
||||
this.nickname = nickname;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public CameraConfiguration(
|
||||
@JsonProperty("baseName") String baseName,
|
||||
@JsonProperty("uniqueName") String uniqueName,
|
||||
@JsonProperty("nickname") String nickname,
|
||||
@JsonProperty("FOV") double FOV,
|
||||
@JsonProperty("path") String path,
|
||||
@JsonProperty("cameraType") CameraType cameraType,
|
||||
@JsonProperty("calibration") CameraCalibrationCoefficients calibration,
|
||||
@JsonProperty("CameraLEDs") List<Integer> cameraLEDs) {
|
||||
this.baseName = baseName;
|
||||
this.uniqueName = uniqueName;
|
||||
this.nickname = nickname;
|
||||
this.FOV = FOV;
|
||||
this.path = path;
|
||||
this.cameraType = cameraType;
|
||||
this.calibration = calibration;
|
||||
this.CameraLEDs = cameraLEDs;
|
||||
}
|
||||
|
||||
@JsonIgnore // this ignores the pipes as we serialize them to their own subfolder
|
||||
public final List<CVPipelineSettings> pipelineSettings = new ArrayList<>();
|
||||
|
||||
@@ -16,7 +16,7 @@ public class ChameleonConfiguration {
|
||||
}
|
||||
|
||||
public void addCameraConfig(CameraConfiguration config) {
|
||||
addCameraConfig(config.name, config);
|
||||
addCameraConfig(config.uniqueName, config);
|
||||
}
|
||||
|
||||
public void addCameraConfig(String name, CameraConfiguration config) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ConfigManager {
|
||||
}
|
||||
|
||||
protected static Path getRootFolder() {
|
||||
return Path.of("chameleon-vision"); // TODO change root folder?
|
||||
return Path.of("chameleon-vision");
|
||||
}
|
||||
|
||||
private ConfigManager(Path rootFolder) {
|
||||
@@ -64,25 +64,36 @@ public class ConfigManager {
|
||||
HardwareConfig hardwareConfig;
|
||||
NetworkConfig networkConfig;
|
||||
|
||||
try {
|
||||
hardwareConfig = JacksonUtils.deserialize(hardwareConfigFile.toPath(), HardwareConfig.class);
|
||||
if (hardwareConfig == null) {
|
||||
if (hardwareConfigFile.exists()) {
|
||||
try {
|
||||
hardwareConfig =
|
||||
JacksonUtils.deserialize(hardwareConfigFile.toPath(), HardwareConfig.class);
|
||||
if (hardwareConfig == null) {
|
||||
logger.error("Could not deserialize hardware config! Loading defaults");
|
||||
hardwareConfig = new HardwareConfig();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not deserialize hardware config! Loading defaults");
|
||||
hardwareConfig = new HardwareConfig();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not deserialize hardware config! Loading defaults");
|
||||
} else {
|
||||
logger.info("Hardware config does not exist! Loading defaults");
|
||||
hardwareConfig = new HardwareConfig();
|
||||
}
|
||||
|
||||
try {
|
||||
networkConfig = JacksonUtils.deserialize(networkConfigFile.toPath(), NetworkConfig.class);
|
||||
if (networkConfig == null) {
|
||||
if (networkConfigFile.exists()) {
|
||||
try {
|
||||
networkConfig = JacksonUtils.deserialize(networkConfigFile.toPath(), NetworkConfig.class);
|
||||
if (networkConfig == null) {
|
||||
logger.error("Could not deserialize network config! Loading defaults");
|
||||
networkConfig = new NetworkConfig();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not deserialize network config! Loading defaults");
|
||||
networkConfig = new NetworkConfig();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not deserialize network config! Loading defaults");
|
||||
} else {
|
||||
logger.info("Network config file does not exist! Loading defaults");
|
||||
networkConfig = new NetworkConfig();
|
||||
}
|
||||
|
||||
@@ -164,11 +175,17 @@ public class ConfigManager {
|
||||
|
||||
for (var subdir : subdirectories) {
|
||||
var cameraConfigPath = Path.of(subdir.toString(), "config.json");
|
||||
CameraConfiguration loadedConfig =
|
||||
JacksonUtils.deserialize(cameraConfigPath.toAbsolutePath(), CameraConfiguration.class);
|
||||
if (loadedConfig == null) {
|
||||
CameraConfiguration loadedConfig = null;
|
||||
try {
|
||||
loadedConfig =
|
||||
JacksonUtils.deserialize(
|
||||
cameraConfigPath.toAbsolutePath(), CameraConfiguration.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (loadedConfig == null) { // If the file could not be deserialized
|
||||
logger.warn("Could not load camera " + subdir + "'s config.json! Loading " + "default");
|
||||
loadedConfig = new CameraConfiguration();
|
||||
continue; // TODO how do we later try to load this camera if it gets reconnected?
|
||||
}
|
||||
|
||||
// At this point we have only loaded the base stuff
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.chameleonvision.common.configuration;
|
||||
|
||||
public enum StreamDivisor {
|
||||
NONE(1),
|
||||
HALF(2),
|
||||
QUARTER(4),
|
||||
SIXTH(6);
|
||||
|
||||
public final Integer value;
|
||||
|
||||
StreamDivisor(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.chameleonvision.common.vision.camera;
|
||||
|
||||
public enum CameraQuirks {
|
||||
Gain
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.chameleonvision.common.vision.camera;
|
||||
|
||||
public enum CameraType {
|
||||
UsbCamera,
|
||||
HttpCamera
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.chameleonvision.common.vision.camera;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class QuirkyCamera {
|
||||
public static final List<QuirkyCamera> quirkyCameras =
|
||||
List.of(
|
||||
// ps3 eye
|
||||
new QuirkyCamera(0x1415, 0x2000, "PS3Eye", List.of(CameraQuirks.Gain)));
|
||||
|
||||
public final int usbVid;
|
||||
public final int usbPid;
|
||||
public final String name;
|
||||
public List<CameraQuirks> quirks;
|
||||
|
||||
public QuirkyCamera(int usbVid, int usbPid, String baseName, List<CameraQuirks> quirks) {
|
||||
this.usbVid = usbVid;
|
||||
this.usbPid = usbPid;
|
||||
this.name = baseName;
|
||||
this.quirks = quirks;
|
||||
}
|
||||
|
||||
public QuirkyCamera(int usbVid, int usbPid, String baseName) {
|
||||
this(usbVid, usbPid, baseName, new ArrayList<>());
|
||||
QuirkyCamera quirky =
|
||||
quirkyCameras.stream()
|
||||
.filter(quirkyCamera -> quirkyCamera.usbPid == usbPid && quirkyCamera.usbVid == usbVid)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (quirky != null) {
|
||||
this.quirks = quirky.quirks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.chameleonvision.common.vision.camera;
|
||||
|
||||
import com.chameleonvision.common.vision.frame.provider.USBFrameProvider;
|
||||
|
||||
public class USBCamera extends USBFrameProvider {}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.chameleonvision.common.vision.camera;
|
||||
|
||||
import com.chameleonvision.common.configuration.CameraConfiguration;
|
||||
import com.chameleonvision.common.vision.frame.FrameProvider;
|
||||
import com.chameleonvision.common.vision.frame.provider.USBFrameProvider;
|
||||
import com.chameleonvision.common.vision.processes.VisionSource;
|
||||
import com.chameleonvision.common.vision.processes.VisionSourceSettables;
|
||||
import edu.wpi.cscore.CvSink;
|
||||
import edu.wpi.cscore.UsbCamera;
|
||||
import edu.wpi.cscore.VideoMode;
|
||||
import edu.wpi.first.cameraserver.CameraServer;
|
||||
import java.util.*;
|
||||
|
||||
public class USBCameraSource implements VisionSource {
|
||||
private final UsbCamera camera;
|
||||
private final USBCameraSettables usbCameraSettables;
|
||||
private final USBFrameProvider usbFrameProvider;
|
||||
private final CameraConfiguration configuration;
|
||||
|
||||
private final QuirkyCamera cameraQuirks;
|
||||
|
||||
public USBCameraSource(CameraConfiguration config) {
|
||||
this.configuration = config;
|
||||
this.camera = new UsbCamera(config.nickname, config.path);
|
||||
this.cameraQuirks =
|
||||
new QuirkyCamera(camera.getInfo().productId, camera.getInfo().vendorId, config.baseName);
|
||||
CvSink cvSink = CameraServer.getInstance().getVideo(this.camera);
|
||||
this.usbCameraSettables = new USBCameraSettables(config);
|
||||
this.usbFrameProvider =
|
||||
new USBFrameProvider(cvSink, usbCameraSettables.getFrameStaticProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj.getClass() != USBCameraSource.class) {
|
||||
return false;
|
||||
}
|
||||
USBCameraSource tmp = (USBCameraSource) obj;
|
||||
boolean i = this.cameraQuirks.quirks.equals(tmp.cameraQuirks.quirks);
|
||||
|
||||
boolean r = this.configuration.uniqueName.equals(tmp.configuration.uniqueName);
|
||||
boolean c = this.configuration.baseName.equals(tmp.configuration.baseName);
|
||||
boolean j = this.configuration.nickname.equals(tmp.configuration.nickname);
|
||||
|
||||
boolean k = this.camera.getInfo().name.equals(tmp.camera.getInfo().name);
|
||||
boolean x = this.camera.getInfo().productId == tmp.camera.getInfo().productId;
|
||||
boolean y = this.camera.getInfo().vendorId == tmp.camera.getInfo().vendorId;
|
||||
var t = i && r && c && j && k && x && y;
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameProvider getFrameProvider() {
|
||||
return usbFrameProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisionSourceSettables getSettables() {
|
||||
return this.usbCameraSettables;
|
||||
}
|
||||
|
||||
public class USBCameraSettables extends VisionSourceSettables {
|
||||
protected USBCameraSettables(CameraConfiguration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExposure() {
|
||||
return camera.getProperty("exposure").get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExposure(int exposure) {
|
||||
camera.setExposureManual(exposure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness() {
|
||||
return camera.getBrightness();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBrightness(int brightness) {
|
||||
camera.setBrightness(brightness);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGain() {
|
||||
return camera.getProperty("gain").get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGain(int gain) {
|
||||
if (cameraQuirks.quirks.contains(CameraQuirks.Gain)) {
|
||||
camera.getProperty("gain_automatic").set(0);
|
||||
camera.getProperty("gain").set(gain);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoMode getCurrentVideoMode() {
|
||||
return camera.getVideoMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentVideoMode(VideoMode videoMode) {
|
||||
camera.setVideoMode(videoMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, VideoMode> getAllVideoModes() {
|
||||
if (videoModes == null) {
|
||||
videoModes = new HashMap<>();
|
||||
List<VideoMode> videoModesList = Arrays.asList(camera.enumerateVideoModes());
|
||||
for (VideoMode videoMode : videoModesList) {
|
||||
videoModes.put(videoModesList.indexOf(videoMode), videoMode);
|
||||
}
|
||||
}
|
||||
return videoModes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,29 @@ package com.chameleonvision.common.vision.frame.provider;
|
||||
|
||||
import com.chameleonvision.common.vision.frame.Frame;
|
||||
import com.chameleonvision.common.vision.frame.FrameProvider;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import com.chameleonvision.common.vision.frame.FrameStaticProperties;
|
||||
import com.chameleonvision.common.vision.opencv.CVMat;
|
||||
import edu.wpi.cscore.CvSink;
|
||||
|
||||
public class USBFrameProvider implements FrameProvider {
|
||||
private static int count = 0;
|
||||
private CvSink cvSink;
|
||||
private FrameStaticProperties frameStaticProperties;
|
||||
private CVMat mat;
|
||||
|
||||
public USBFrameProvider(CvSink sink, FrameStaticProperties frameStaticProperties) {
|
||||
cvSink = sink;
|
||||
this.frameStaticProperties = frameStaticProperties;
|
||||
mat = new CVMat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame get() {
|
||||
throw new NotImplementedException("");
|
||||
if (mat != null && mat.getMat() != null) {
|
||||
mat.release();
|
||||
}
|
||||
long time = cvSink.grabFrame(mat.getMat());
|
||||
return new Frame(mat, time, frameStaticProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.chameleonvision.common.vision.processes;
|
||||
import com.chameleonvision.common.vision.frame.FrameProvider;
|
||||
|
||||
public interface VisionSource {
|
||||
|
||||
FrameProvider getFrameProvider();
|
||||
|
||||
VisionSourceSettables getSettables();
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.chameleonvision.common.vision.processes;
|
||||
|
||||
import com.chameleonvision.common.configuration.CameraConfiguration;
|
||||
import com.chameleonvision.common.vision.camera.CameraType;
|
||||
import com.chameleonvision.common.vision.camera.USBCameraSource;
|
||||
import com.chameleonvision.common.vision.frame.provider.NetworkFrameProvider;
|
||||
import edu.wpi.cscore.UsbCamera;
|
||||
import edu.wpi.cscore.UsbCameraInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class VisionSourceManager {
|
||||
public List<VisionSource> LoadAllSources(List<CameraConfiguration> camerasConfiguration) {
|
||||
return LoadAllSources(camerasConfiguration, Arrays.asList(UsbCamera.enumerateUsbCameras()));
|
||||
}
|
||||
|
||||
public List<VisionSource> LoadAllSources(
|
||||
List<CameraConfiguration> camerasConfiguration, List<UsbCameraInfo> usbCameraInfos) {
|
||||
var UsbCamerasConfiguration =
|
||||
camerasConfiguration.stream()
|
||||
.filter(configuration -> configuration.cameraType == CameraType.UsbCamera)
|
||||
.collect(Collectors.toList());
|
||||
// var HttpCamerasConfiguration = camerasConfiguration.stream().filter(configuration ->
|
||||
// configuration.cameraType == CameraType.HttpCamera);
|
||||
var matchedCameras = matchUSBCameras(usbCameraInfos, UsbCamerasConfiguration);
|
||||
return loadUSBCameraSources(matchedCameras);
|
||||
}
|
||||
|
||||
private NetworkFrameProvider loadHTTPCamera(CameraConfiguration config) {
|
||||
throw new NotImplementedException("");
|
||||
}
|
||||
|
||||
private List<CameraConfiguration> matchUSBCameras(
|
||||
List<UsbCameraInfo> infos, List<CameraConfiguration> cameraConfigurationList) {
|
||||
ArrayList<UsbCameraInfo> loopableInfo = new ArrayList<>(infos);
|
||||
List<CameraConfiguration> cameraConfigurations = new ArrayList<>();
|
||||
|
||||
for (CameraConfiguration config : cameraConfigurationList) {
|
||||
UsbCameraInfo cameraInfo;
|
||||
if (!StringUtils.isNumeric(config.path)) {
|
||||
// matching by path
|
||||
cameraInfo =
|
||||
loopableInfo.stream()
|
||||
.filter(usbCameraInfo -> usbCameraInfo.path.equals(config.path))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
} else {
|
||||
// match by index
|
||||
cameraInfo =
|
||||
loopableInfo.stream()
|
||||
.filter(usbCameraInfo -> usbCameraInfo.dev == Integer.parseInt(config.path))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (cameraInfo != null) {
|
||||
loopableInfo.remove(cameraInfo);
|
||||
cameraConfigurations.add(config);
|
||||
}
|
||||
}
|
||||
for (UsbCameraInfo info : loopableInfo) {
|
||||
// create new camera config for all new cameras
|
||||
String name = info.name.replaceAll("[^\\x00-\\x7F]", "");
|
||||
String uniqueName = name;
|
||||
int suffix = 0;
|
||||
|
||||
while (containsName(cameraConfigurations, uniqueName)) {
|
||||
suffix++;
|
||||
uniqueName = String.format("%s (%d)", uniqueName, suffix);
|
||||
}
|
||||
|
||||
CameraConfiguration configuration =
|
||||
new CameraConfiguration(name, uniqueName, uniqueName, ((Integer) info.dev).toString());
|
||||
cameraConfigurations.add(configuration);
|
||||
}
|
||||
|
||||
return cameraConfigurations;
|
||||
}
|
||||
|
||||
private List<VisionSource> loadUSBCameraSources(List<CameraConfiguration> configurations) {
|
||||
List<VisionSource> usbCameraSources = new ArrayList<>();
|
||||
configurations.forEach(
|
||||
configuration -> usbCameraSources.add(new USBCameraSource(configuration)));
|
||||
return usbCameraSources;
|
||||
}
|
||||
|
||||
private boolean containsName(final List<CameraConfiguration> list, final String name) {
|
||||
return list.stream().anyMatch(configuration -> configuration.uniqueName.equals(name));
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,47 @@
|
||||
package com.chameleonvision.common.vision.processes;
|
||||
|
||||
import com.chameleonvision.common.configuration.CameraConfiguration;
|
||||
import com.chameleonvision.common.vision.frame.FrameStaticProperties;
|
||||
import edu.wpi.cscore.VideoMode;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface VisionSourceSettables {
|
||||
int getExposure();
|
||||
public abstract class VisionSourceSettables {
|
||||
private CameraConfiguration configuration;
|
||||
|
||||
void setExposure(int exposure);
|
||||
protected VisionSourceSettables(CameraConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
int getBrightness();
|
||||
FrameStaticProperties frameStaticProperties;
|
||||
protected HashMap<Integer, VideoMode> videoModes;
|
||||
|
||||
void setBrightness(int brightness);
|
||||
public abstract int getExposure();
|
||||
|
||||
int getGain();
|
||||
public abstract void setExposure(int exposure);
|
||||
|
||||
void setGain(int gain);
|
||||
public abstract int getBrightness();
|
||||
|
||||
VideoMode getCurrentVideoMode();
|
||||
public abstract void setBrightness(int brightness);
|
||||
|
||||
void setCurrentVideoMode(VideoMode videoMode);
|
||||
public abstract int getGain();
|
||||
|
||||
Dictionary<Integer, VideoMode> getAllVideoModes();
|
||||
public abstract void setGain(int gain);
|
||||
|
||||
public abstract VideoMode getCurrentVideoMode();
|
||||
|
||||
public abstract void setCurrentVideoMode(VideoMode videoMode);
|
||||
|
||||
public abstract HashMap<Integer, VideoMode> getAllVideoModes();
|
||||
|
||||
public double getFOV() {
|
||||
return configuration.FOV;
|
||||
}
|
||||
|
||||
public void setFOV(double fov) {
|
||||
configuration.FOV = fov;
|
||||
}
|
||||
|
||||
public FrameStaticProperties getFrameStaticProperties() {
|
||||
return frameStaticProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ import org.junit.jupiter.api.*;
|
||||
public class ConfigTest {
|
||||
|
||||
private static final ConfigManager configMgr;
|
||||
private static final CameraConfiguration cameraConfig = new CameraConfiguration();
|
||||
private static final CameraConfiguration cameraConfig =
|
||||
new CameraConfiguration("TestCamera", "/dev/video420");
|
||||
private static final ReflectivePipelineSettings REFLECTIVE_PIPELINE_SETTINGS =
|
||||
new ReflectivePipelineSettings();
|
||||
private static final ColoredShapePipelineSettings COLORED_SHAPE_PIPELINE_SETTINGS =
|
||||
@@ -34,8 +35,6 @@ public class ConfigTest {
|
||||
TestUtils.loadLibraries();
|
||||
Logger.setLevel(LogGroup.General, Level.DE_PEST);
|
||||
|
||||
cameraConfig.name = "TestCamera";
|
||||
|
||||
REFLECTIVE_PIPELINE_SETTINGS.pipelineNickname = "2019Tape";
|
||||
REFLECTIVE_PIPELINE_SETTINGS.targetModel = TargetModel.get2019Target();
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.chameleonvision.common.vision;
|
||||
|
||||
import com.chameleonvision.common.vision.camera.CameraQuirks;
|
||||
import com.chameleonvision.common.vision.camera.QuirkyCamera;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class QuirkyCameraTest {
|
||||
@Test
|
||||
public void ps3EyeTest() {
|
||||
QuirkyCamera psEye = new QuirkyCamera(0x1415, 0x2000, "psEye");
|
||||
Assertions.assertEquals(psEye.quirks, List.of(CameraQuirks.Gain));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quirklessCameraTest() {
|
||||
QuirkyCamera noQuirk = new QuirkyCamera(1234, 888, "empty");
|
||||
Assertions.assertEquals(noQuirk.quirks, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.chameleonvision.common.vision.processes;
|
||||
|
||||
import com.chameleonvision.common.configuration.CameraConfiguration;
|
||||
import com.chameleonvision.common.datatransfer.DataConsumer;
|
||||
import com.chameleonvision.common.util.TestUtils;
|
||||
import com.chameleonvision.common.vision.frame.FrameProvider;
|
||||
@@ -7,7 +8,7 @@ import com.chameleonvision.common.vision.frame.provider.FileFrameProvider;
|
||||
import com.chameleonvision.common.vision.pipeline.CVPipelineResult;
|
||||
import edu.wpi.cscore.VideoMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
public class VisionModuleManagerTest {
|
||||
@@ -33,11 +34,15 @@ public class VisionModuleManagerTest {
|
||||
|
||||
@Override
|
||||
public VisionSourceSettables getSettables() {
|
||||
return new TestSettables();
|
||||
return new TestSettables(new CameraConfiguration("", "", "", ""));
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestSettables implements VisionSourceSettables {
|
||||
private static class TestSettables extends VisionSourceSettables {
|
||||
|
||||
protected TestSettables(CameraConfiguration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExposure() {
|
||||
@@ -72,7 +77,7 @@ public class VisionModuleManagerTest {
|
||||
public void setCurrentVideoMode(VideoMode videoMode) {}
|
||||
|
||||
@Override
|
||||
public Dictionary<Integer, VideoMode> getAllVideoModes() {
|
||||
public HashMap<Integer, VideoMode> getAllVideoModes() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.chameleonvision.common.vision.processes;
|
||||
|
||||
import com.chameleonvision.common.configuration.CameraConfiguration;
|
||||
import com.chameleonvision.common.util.TestUtils;
|
||||
import com.chameleonvision.common.vision.camera.USBCameraSource;
|
||||
import edu.wpi.cscore.UsbCameraInfo;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class VisionSourceManagerTest {
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
TestUtils.loadLibraries();
|
||||
}
|
||||
|
||||
final List<UsbCameraInfo> usbCameraInfos =
|
||||
List.of(
|
||||
new UsbCameraInfo(0, "/this-is-a-real-path", "cameraByPath", new String[] {""}, 1, 1),
|
||||
new UsbCameraInfo(2, "/this-is-a-fake-path1", "cameraById", new String[] {""}, 420, 1),
|
||||
new UsbCameraInfo(1, "/this-is-a-real-path2", "cameraByPath", new String[] {""}, 1, 1),
|
||||
new UsbCameraInfo(3, "/this-is-a-fake-path2", "cameraById", new String[] {""}, 420, 1),
|
||||
new UsbCameraInfo(4, "/fake-path420", "notExisting", new String[] {""}, 420, 1),
|
||||
new UsbCameraInfo(5, "/fake-path421", "notExisting", new String[] {""}, 420, 1));
|
||||
|
||||
final List<CameraConfiguration> camConfig =
|
||||
List.of(
|
||||
new CameraConfiguration("cameraByPath", "dank meme", "good name", "/this-is-a-real-path"),
|
||||
new CameraConfiguration(
|
||||
"cameraByPath", "dank meme2", "very original", "/this-is-a-real-path2"),
|
||||
new CameraConfiguration("cameraById", "camera", "my camera", "2"),
|
||||
new CameraConfiguration("cameraById", "camera2", "my camera", "3"));
|
||||
|
||||
final List<USBCameraSource> usbCameraSources =
|
||||
List.of(
|
||||
new USBCameraSource(camConfig.get(0)),
|
||||
new USBCameraSource(camConfig.get(1)),
|
||||
new USBCameraSource(camConfig.get(2)),
|
||||
new USBCameraSource(camConfig.get(3)),
|
||||
new USBCameraSource(
|
||||
new CameraConfiguration("notExisting", "notExisting", "notExisting", "4")),
|
||||
new USBCameraSource(
|
||||
new CameraConfiguration("notExisting", "notExisting (1)", "notExisting (1)", "5")));
|
||||
|
||||
@Test
|
||||
public void visionSourceTest() {
|
||||
VisionSourceManager visionSourceManager = new VisionSourceManager();
|
||||
List<VisionSource> i = visionSourceManager.LoadAllSources(camConfig, usbCameraInfos);
|
||||
for (var source : i) {
|
||||
Assertions.assertEquals(source, usbCameraSources.get(i.indexOf(source)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user