mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-19 00:41:41 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72717cecf0 | ||
|
|
971ff3ac40 | ||
|
|
b80e436f02 | ||
|
|
be1a053cbe | ||
|
|
f4555dc545 | ||
|
|
54fdd1db51 | ||
|
|
1805785cc6 |
@@ -19,6 +19,8 @@ export default new Vuex.Store({
|
||||
connected: false,
|
||||
address: "",
|
||||
clients: 0,
|
||||
},
|
||||
networkInfo: {
|
||||
possibleRios: ["Loading..."],
|
||||
deviceips: ["Loading..."],
|
||||
},
|
||||
@@ -155,6 +157,7 @@ export default new Vuex.Store({
|
||||
calibrationData: set('calibrationData'),
|
||||
metrics: set('metrics'),
|
||||
ntConnectionInfo: set('ntConnectionInfo'),
|
||||
networkInfo: set('networkInfo'),
|
||||
backendConnected: set('backendConnected'),
|
||||
logString: (state, newStr) => {
|
||||
const str = state.logMessages;
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
step="0.1"
|
||||
@input="handlePipelineData('contourRatio')"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="contourTargetOrientation"
|
||||
name="Target Orientation"
|
||||
tooltip="Used to determine how to calculate target landmarks, as well as aspect ratio"
|
||||
:list="['Portrait', 'Landscape']"
|
||||
@input="handlePipelineData('contourTargetOrientation')"
|
||||
@rollback="e=> rollback('contourTargetOrientation', e)"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-if="currentPipelineType() !== 3"
|
||||
v-model="contourFullness"
|
||||
@@ -203,6 +211,14 @@ export default {
|
||||
this.$store.commit("mutatePipeline", {"contourRatio": val});
|
||||
}
|
||||
},
|
||||
contourTargetOrientation: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourTargetOrientation
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourTargetOrientation": val});
|
||||
}
|
||||
},
|
||||
contourFullness: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourFullness
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(value, index) in $store.state.ntConnectionInfo.deviceips"
|
||||
v-for="(value, index) in $store.state.networkInfo.deviceips"
|
||||
:key="index"
|
||||
>
|
||||
<td>{{ value }}</td>
|
||||
@@ -115,7 +115,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(value, index) in $store.state.ntConnectionInfo.possibleRios"
|
||||
v-for="(value, index) in $store.state.networkInfo.possibleRios"
|
||||
:key="index"
|
||||
>
|
||||
<td>{{ value }}</td>
|
||||
|
||||
@@ -442,4 +442,8 @@ public class ConfigManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadCameraConfigs() {
|
||||
this.config.getCameraConfigurations().clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,20 +17,12 @@
|
||||
|
||||
package org.photonvision.common.dataflow.networktables;
|
||||
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import edu.wpi.first.networktables.LogMessage;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.photonvision.PhotonVersion;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
import org.photonvision.common.configuration.NetworkConfig;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
@@ -87,6 +79,7 @@ public class NetworkTablesManager {
|
||||
private void broadcastConnectedStatusImpl() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
var subMap = new HashMap<String, Object>();
|
||||
|
||||
subMap.put("connected", ntInstance.isConnected());
|
||||
if (ntInstance.isConnected()) {
|
||||
var connections = getInstance().ntInstance.getConnections();
|
||||
@@ -99,73 +92,6 @@ public class NetworkTablesManager {
|
||||
map.put("ntConnectionInfo", subMap);
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(new OutgoingUIEvent<>("networkTablesConnected", map));
|
||||
|
||||
// Seperate from the above so we don't hold stuff up
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
subMap.put(
|
||||
"deviceips",
|
||||
Arrays.stream(CameraServerJNI.getNetworkInterfaces())
|
||||
.filter(it -> !it.equals("0.0.0.0"))
|
||||
.toArray());
|
||||
logger.info("Searching for rios");
|
||||
List<String> possibleRioList = new ArrayList<>();
|
||||
for (var ip : CameraServerJNI.getNetworkInterfaces()) {
|
||||
logger.info("Trying " + ip);
|
||||
var possibleRioAddr = getPossibleRioAddress(ip);
|
||||
if (possibleRioAddr != null) {
|
||||
logger.info("Maybe found " + ip);
|
||||
searchForHost(possibleRioList, possibleRioAddr);
|
||||
} else {
|
||||
logger.info("Didn't match RIO IP");
|
||||
}
|
||||
}
|
||||
String name =
|
||||
"roboRIO-"
|
||||
+ ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
+ "-FRC.local";
|
||||
searchForHost(possibleRioList, name);
|
||||
name =
|
||||
"roboRIO-"
|
||||
+ ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
+ "-FRC.lan";
|
||||
searchForHost(possibleRioList, name);
|
||||
name =
|
||||
"roboRIO-"
|
||||
+ ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
+ "-FRC.frc-field.local";
|
||||
searchForHost(possibleRioList, name);
|
||||
subMap.put("possibleRios", possibleRioList.toArray());
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(new OutgoingUIEvent<>("networkTablesConnected", map));
|
||||
}
|
||||
|
||||
String getPossibleRioAddress(String ip) {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(ip);
|
||||
var address = addr.getAddress();
|
||||
if (address[0] != (byte) (10 & 0xff)) return null;
|
||||
address[3] = (byte) (2 & 0xff);
|
||||
return InetAddress.getByAddress(address).getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void searchForHost(List<String> list, String hostname) {
|
||||
try {
|
||||
logger.info("Looking up " + hostname);
|
||||
InetAddress testAddr = InetAddress.getByName(hostname);
|
||||
logger.info("Pinging " + hostname);
|
||||
var canContact = testAddr.isReachable(500);
|
||||
if (canContact) {
|
||||
logger.info("Was able to connect to " + hostname);
|
||||
if (!list.contains(hostname)) list.add(hostname);
|
||||
} else {
|
||||
logger.info("Unable to reach " + hostname);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastVersion() {
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.networking;
|
||||
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
|
||||
public class RoborioFinder {
|
||||
private static RoborioFinder instance;
|
||||
private static final Logger logger = new Logger(RoborioFinder.class, LogGroup.General);
|
||||
|
||||
public static RoborioFinder getInstance() {
|
||||
if (instance == null) instance = new RoborioFinder();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void findRios() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
var subMap = new HashMap<String, Object>();
|
||||
// Seperate from the above so we don't hold stuff up
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
subMap.put(
|
||||
"deviceips",
|
||||
Arrays.stream(CameraServerJNI.getNetworkInterfaces())
|
||||
.filter(it -> !it.equals("0.0.0.0"))
|
||||
.toArray());
|
||||
logger.info("Searching for rios");
|
||||
List<String> possibleRioList = new ArrayList<>();
|
||||
for (var ip : CameraServerJNI.getNetworkInterfaces()) {
|
||||
logger.info("Trying " + ip);
|
||||
var possibleRioAddr = getPossibleRioAddress(ip);
|
||||
if (possibleRioAddr != null) {
|
||||
logger.info("Maybe found " + ip);
|
||||
searchForHost(possibleRioList, possibleRioAddr);
|
||||
} else {
|
||||
logger.info("Didn't match RIO IP");
|
||||
}
|
||||
}
|
||||
|
||||
// String name =
|
||||
// "roboRIO-"
|
||||
// +
|
||||
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
// + "-FRC.local";
|
||||
// searchForHost(possibleRioList, name);
|
||||
// name =
|
||||
// "roboRIO-"
|
||||
// +
|
||||
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
// + "-FRC.lan";
|
||||
// searchForHost(possibleRioList, name);
|
||||
// name =
|
||||
// "roboRIO-"
|
||||
// +
|
||||
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
// + "-FRC.frc-field.local";
|
||||
// searchForHost(possibleRioList, name);
|
||||
// subMap.put("possibleRios", possibleRioList.toArray());
|
||||
|
||||
subMap.put("possibleRios", possibleRioList.toArray());
|
||||
map.put("networkInfo", subMap);
|
||||
DataChangeService.getInstance().publishEvent(new OutgoingUIEvent<>("deviceIpInfo", map));
|
||||
}
|
||||
|
||||
String getPossibleRioAddress(String ip) {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(ip);
|
||||
var address = addr.getAddress();
|
||||
if (address[0] != (byte) (10 & 0xff)) return null;
|
||||
address[3] = (byte) (2 & 0xff);
|
||||
return InetAddress.getByAddress(address).getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void searchForHost(List<String> list, String hostname) {
|
||||
try {
|
||||
logger.info("Looking up " + hostname);
|
||||
InetAddress testAddr = InetAddress.getByName(hostname);
|
||||
logger.info("Pinging " + hostname);
|
||||
var canContact = testAddr.isReachable(500);
|
||||
if (canContact) {
|
||||
logger.info("Was able to connect to " + hostname);
|
||||
if (!list.contains(hostname)) list.add(hostname);
|
||||
} else {
|
||||
logger.info("Unable to reach " + hostname);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import java.nio.file.Path;
|
||||
|
||||
public class JacksonUtils {
|
||||
public static <T> void serialize(Path path, T object) throws IOException {
|
||||
serialize(path, object, false);
|
||||
serialize(path, object, true);
|
||||
}
|
||||
|
||||
public static <T> void serialize(Path path, T object, boolean forceSync) throws IOException {
|
||||
@@ -80,7 +80,7 @@ public class JacksonUtils {
|
||||
|
||||
public static <T> void serialize(Path path, T object, Class<T> ref, StdSerializer<T> serializer)
|
||||
throws IOException {
|
||||
serialize(path, object, ref, serializer, false);
|
||||
serialize(path, object, ref, serializer, true);
|
||||
}
|
||||
|
||||
public static <T> void serialize(
|
||||
|
||||
@@ -18,16 +18,14 @@
|
||||
package org.photonvision.vision.pipe.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opencv.core.Rect;
|
||||
|
||||
import org.opencv.core.RotatedRect;
|
||||
import org.photonvision.common.util.math.MathUtils;
|
||||
import org.photonvision.common.util.numbers.DoubleCouple;
|
||||
import org.photonvision.vision.frame.FrameStaticProperties;
|
||||
import org.photonvision.vision.opencv.Contour;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.target.TargetCalculations;
|
||||
|
||||
public class FilterContoursPipe
|
||||
extends CVPipe<List<Contour>, List<Contour>, FilterContoursPipe.FilterContoursParams> {
|
||||
@@ -114,8 +112,7 @@ public class FilterContoursPipe
|
||||
if (contourArea <= minFullness || contourArea >= maxFullness) return;
|
||||
|
||||
// Aspect Ratio Filtering.
|
||||
Rect boundingRect = contour.getBoundingRect();
|
||||
double aspectRatio = (double) boundingRect.width / boundingRect.height;
|
||||
double aspectRatio = TargetCalculations.getAspectRatio(contour.getMinAreaRect(), params.isLandscape);
|
||||
if (aspectRatio < params.getRatio().getFirst() || aspectRatio > params.getRatio().getSecond())
|
||||
return;
|
||||
|
||||
@@ -129,6 +126,7 @@ public class FilterContoursPipe
|
||||
private final FrameStaticProperties m_frameStaticProperties;
|
||||
private final double xTol; // IQR tolerance for x
|
||||
private final double yTol; // IQR tolerance for x
|
||||
public final boolean isLandscape;
|
||||
|
||||
public FilterContoursParams(
|
||||
DoubleCouple area,
|
||||
@@ -136,13 +134,14 @@ public class FilterContoursPipe
|
||||
DoubleCouple extent,
|
||||
FrameStaticProperties camProperties,
|
||||
double xTol,
|
||||
double yTol) {
|
||||
double yTol, boolean isLandscape) {
|
||||
this.m_area = area;
|
||||
this.m_ratio = ratio;
|
||||
this.m_fullness = extent;
|
||||
this.m_frameStaticProperties = camProperties;
|
||||
this.xTol = xTol;
|
||||
this.yTol = yTol;
|
||||
this.isLandscape = isLandscape;
|
||||
}
|
||||
|
||||
public DoubleCouple getArea() {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.photonvision.vision.pipe.CVPipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.impl.*;
|
||||
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||
import org.photonvision.vision.target.PotentialTarget;
|
||||
import org.photonvision.vision.target.TargetOrientation;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
/** Represents a pipeline for tracking retro-reflective targets. */
|
||||
@@ -102,7 +103,8 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
settings.contourFullness,
|
||||
frameStaticProperties,
|
||||
settings.contourFilterRangeX,
|
||||
settings.contourFilterRangeY);
|
||||
settings.contourFilterRangeY,
|
||||
settings.contourTargetOrientation == TargetOrientation.Landscape);
|
||||
filterContoursPipe.setParams(filterContoursParams);
|
||||
|
||||
var groupContoursParams =
|
||||
|
||||
@@ -54,26 +54,27 @@ public class TargetCalculations {
|
||||
|
||||
minAreaRect.points(vertices);
|
||||
|
||||
Point bl = getMiddle(vertices[0], vertices[1]);
|
||||
Point tl = getMiddle(vertices[1], vertices[2]);
|
||||
Point tr = getMiddle(vertices[2], vertices[3]);
|
||||
Point br = getMiddle(vertices[3], vertices[0]);
|
||||
boolean orientation;
|
||||
if (isLandscape) {
|
||||
orientation = minAreaRect.size.width > minAreaRect.size.height;
|
||||
} else {
|
||||
orientation = minAreaRect.size.width < minAreaRect.size.height;
|
||||
}
|
||||
Point bottom = getMiddle(vertices[0], vertices[1]);
|
||||
Point left = getMiddle(vertices[1], vertices[2]);
|
||||
Point top = getMiddle(vertices[2], vertices[3]);
|
||||
Point right = getMiddle(vertices[3], vertices[0]);
|
||||
|
||||
boolean orientationCorrect = minAreaRect.size.width > minAreaRect.size.height;
|
||||
if (!isLandscape) orientationCorrect = !orientationCorrect;
|
||||
|
||||
switch (offsetRegion) {
|
||||
case Top:
|
||||
return orientation ? tl : tr;
|
||||
if (orientationCorrect) return (left.y < right.y) ? left : right;
|
||||
else return (top.y < bottom.y) ? top : bottom;
|
||||
case Bottom:
|
||||
return orientation ? br : bl;
|
||||
if (orientationCorrect) return (left.y > right.y) ? left : right;
|
||||
else return (top.y > bottom.y) ? top : bottom;
|
||||
case Left:
|
||||
return orientation ? bl : tl;
|
||||
if (orientationCorrect) return (top.x < bottom.x) ? top : bottom;
|
||||
else return (left.x < right.x) ? left : right;
|
||||
case Right:
|
||||
return orientation ? tr : br;
|
||||
if (orientationCorrect) return (top.x > bottom.x) ? top : bottom;
|
||||
else return (left.x > right.x) ? left : right;
|
||||
default:
|
||||
return minAreaRect.center;
|
||||
}
|
||||
@@ -110,6 +111,23 @@ public class TargetCalculations {
|
||||
}
|
||||
}
|
||||
|
||||
public static double getAspectRatio(RotatedRect rect, boolean isLandscape) {
|
||||
if (rect.size.width == 0 || rect.size.height == 0) return 0;
|
||||
double ratio = rect.size.width / rect.size.height;
|
||||
|
||||
// In landscape, we should be shorter than we are wide (that is, aspect ratio should be >1)
|
||||
if (isLandscape && ratio < 1) {
|
||||
ratio = 1.0 / ratio;
|
||||
}
|
||||
|
||||
// If portrait, should always be taller than wide (ratio < 1)
|
||||
else if (!isLandscape && ratio > 1) {
|
||||
ratio = 1.0 / ratio;
|
||||
}
|
||||
|
||||
return ratio;
|
||||
}
|
||||
|
||||
public static Point calculateDualOffsetCrosshair(
|
||||
DualOffsetValues dualOffsetValues, double currentArea) {
|
||||
boolean firstLarger = dualOffsetValues.firstPointArea >= dualOffsetValues.secondPointArea;
|
||||
|
||||
@@ -92,10 +92,21 @@ public class TargetCalculationsTest {
|
||||
Size rectSize = new Size(10, 5);
|
||||
double angle = 30;
|
||||
RotatedRect rect = new RotatedRect(center, rectSize, angle);
|
||||
Point result =
|
||||
TargetCalculations.calculateTargetOffsetPoint(false, TargetOffsetPointEdge.Top, rect);
|
||||
assertEquals(4.3, result.x, 0.33, "Target offset x not as expected");
|
||||
assertEquals(2.5, result.y, 0.05, "Target offset Y not as expected");
|
||||
|
||||
// We pretend like x/y are in pixels, so the "top" is actually the bottom
|
||||
var result =
|
||||
TargetCalculations.calculateTargetOffsetPoint(true, TargetOffsetPointEdge.Top, rect);
|
||||
assertEquals(1.25, result.x, 0.1, "Target offset x not as expected");
|
||||
assertEquals(-2.17, result.y, 0.1, "Target offset Y not as expected");
|
||||
result =
|
||||
TargetCalculations.calculateTargetOffsetPoint(true, TargetOffsetPointEdge.Bottom, rect);
|
||||
assertEquals(-1.25, result.x, 0.1, "Target offset x not as expected");
|
||||
assertEquals(2.17, result.y, 0.1, "Target offset Y not as expected");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestUtils.loadLibraries();
|
||||
new TargetCalculationsTest().targetOffsetTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
package org.photonvision;
|
||||
|
||||
import edu.wpi.first.cscore.CameraServerCvJNI;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
@@ -54,6 +60,7 @@ public class Main {
|
||||
private static final boolean isRelease = PhotonVersion.isRelease;
|
||||
|
||||
private static boolean isTestMode;
|
||||
private static Path testModeFolder = null;
|
||||
private static boolean printDebugLogs;
|
||||
|
||||
private static boolean handleArgs(String[] args) throws ParseException {
|
||||
@@ -66,6 +73,8 @@ public class Main {
|
||||
false,
|
||||
"Run in test mode with 2019 and 2020 WPI field images in place of cameras");
|
||||
|
||||
options.addOption("p", "path", true, "Point test mode to a specific folder");
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
CommandLine cmd = parser.parse(options, args);
|
||||
|
||||
@@ -82,11 +91,70 @@ public class Main {
|
||||
if (cmd.hasOption("test-mode")) {
|
||||
isTestMode = true;
|
||||
logger.info("Running in test mode - Cameras will not be used");
|
||||
|
||||
if (cmd.hasOption("path")) {
|
||||
Path p = Path.of(cmd.getOptionValue("path"));
|
||||
logger.info("Loading from Path " + p.toAbsolutePath().toString());
|
||||
testModeFolder = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void addTestModeFromFolder() {
|
||||
ConfigManager.getInstance().load();
|
||||
|
||||
try {
|
||||
var reflective = new ReflectivePipelineSettings();
|
||||
var shape = new ColoredShapePipelineSettings();
|
||||
List<VisionSource> collectedSources =
|
||||
Files.list(testModeFolder)
|
||||
.filter(p -> p.toFile().isFile())
|
||||
.map(
|
||||
p -> {
|
||||
try {
|
||||
var camConf =
|
||||
ConfigManager.getInstance()
|
||||
.getConfig()
|
||||
.getCameraConfigurations()
|
||||
.get(p.getFileName().toString());
|
||||
if (camConf == null) {
|
||||
camConf =
|
||||
new CameraConfiguration(
|
||||
p.getFileName().toString(), p.toAbsolutePath().toString());
|
||||
camConf.FOV = TestUtils.WPI2019Image.FOV; // Good guess?
|
||||
|
||||
var pipeSettings = new ReflectivePipelineSettings();
|
||||
pipeSettings.pipelineNickname = p.getFileName().toString();
|
||||
pipeSettings.outputShowMultipleTargets = true;
|
||||
pipeSettings.inputShouldShow = true;
|
||||
pipeSettings.outputShouldShow = true;
|
||||
|
||||
var psList = new ArrayList<CVPipelineSettings>();
|
||||
psList.add(reflective);
|
||||
psList.add(shape);
|
||||
camConf.pipelineSettings = psList;
|
||||
}
|
||||
|
||||
return new FileVisionSource(camConf);
|
||||
} catch (Exception e) {
|
||||
logger.error("Couldn't load image " + p.getFileName().toString());
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ConfigManager.getInstance().unloadCameraConfigs();
|
||||
VisionModuleManager.getInstance().addSources(collectedSources).forEach(VisionModule::start);
|
||||
ConfigManager.getInstance().addCameraConfigurations(collectedSources);
|
||||
} catch (IOException e) {
|
||||
logger.error("Path does not exist!");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTestModeSources() {
|
||||
ConfigManager.getInstance().load();
|
||||
|
||||
@@ -182,13 +250,16 @@ public class Main {
|
||||
collectedSources.add(fvs2020);
|
||||
collectedSources.add(fvs2019);
|
||||
|
||||
ConfigManager.getInstance().unloadCameraConfigs();
|
||||
VisionModuleManager.getInstance().addSources(collectedSources).forEach(VisionModule::start);
|
||||
ConfigManager.getInstance().addCameraConfigurations(collectedSources);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
if (!handleArgs(args)) return;
|
||||
if (!handleArgs(args)) {
|
||||
System.exit(0);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
logger.error("Failed to parse command-line options!", e);
|
||||
}
|
||||
@@ -235,9 +306,14 @@ public class Main {
|
||||
VisionSourceManager.getInstance()
|
||||
.registerLoadedConfigs(
|
||||
ConfigManager.getInstance().getConfig().getCameraConfigurations().values());
|
||||
|
||||
VisionSourceManager.getInstance().registerTimedTask();
|
||||
} else {
|
||||
addTestModeSources();
|
||||
if (testModeFolder == null) {
|
||||
addTestModeSources();
|
||||
} else {
|
||||
addTestModeFromFolder();
|
||||
}
|
||||
}
|
||||
|
||||
Server.main(DEFAULT_WEBPORT);
|
||||
|
||||
@@ -280,6 +280,8 @@ public class RequestHandler {
|
||||
|
||||
public static void sendMetrics(Context ctx) {
|
||||
MetricsPublisher.getInstance().publish();
|
||||
// TimedTaskManager.getInstance().addOneShotTask(() -> RoborioFinder.getInstance().findRios(),
|
||||
// 0);
|
||||
ctx.status(200);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
namespace photonlib {
|
||||
namespace PhotonVersion {
|
||||
const std::string versionString = "dev-v2022.1.4-2-ga22f8af0";
|
||||
const std::string buildDate = "2022-1-20 10:10:04";
|
||||
const std::string versionString = "${version}";
|
||||
const std::string buildDate = "${date}";
|
||||
const bool isRelease = !(versionString.rfind("dev", 0) == 0);
|
||||
}
|
||||
|
||||
|
||||
BIN
test-resources/testimages/2022/WPI/2022balls.png
Normal file
BIN
test-resources/testimages/2022/WPI/2022balls.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 536 KiB |
Reference in New Issue
Block a user