diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/DatabaseSchema.java b/photon-core/src/main/java/org/photonvision/common/configuration/DatabaseSchema.java index d55c3494dc..ccb7e6d72b 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/DatabaseSchema.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/DatabaseSchema.java @@ -27,16 +27,19 @@ public final class DatabaseSchema { public static final String[] migrations = { // #1 - initial schema - "CREATE TABLE IF NOT EXISTS global (\n" - + " filename TINYTEXT PRIMARY KEY,\n" - + " contents mediumtext NOT NULL\n" - + ");" - + "CREATE TABLE IF NOT EXISTS cameras (\n" - + " unique_name TINYTEXT PRIMARY KEY,\n" - + " config_json text NOT NULL,\n" - + " drivermode_json text NOT NULL,\n" - + " pipeline_jsons mediumtext NOT NULL\n" - + ");", + // spotless:off + """ + CREATE TABLE IF NOT EXISTS global ( + filename TINYTEXT PRIMARY KEY, + contents mediumtext NOT NULL + ); + CREATE TABLE IF NOT EXISTS cameras ( + unique_name TINYTEXT PRIMARY KEY, + config_json text NOT NULL, + drivermode_json text NOT NULL, + pipeline_jsons mediumtext NOT NULL + );""", + // spotless:on // #2 - add column otherpaths_json "ALTER TABLE cameras ADD COLUMN otherpaths_json TEXT NOT NULL DEFAULT '[]';", // add future migrations here diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java b/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java index 2c8323f159..be053241a9 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java @@ -19,113 +19,59 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.ArrayList; -import java.util.Collections; -import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) -public class HardwareConfig { - public final String deviceName; - public final String deviceLogoPath; - public final String supportURL; +public record HardwareConfig( + String deviceName, + String deviceLogoPath, + String supportURL, + // LED control - // LED control - public final ArrayList ledPins; - public final String ledSetCommand; - public final boolean ledsCanDim; - public final ArrayList ledBrightnessRange; - public final String ledDimCommand; - public final String ledBlinkCommand; - public final ArrayList statusRGBPins; + ArrayList ledPins, + String ledSetCommand, + boolean ledsCanDim, + ArrayList ledBrightnessRange, + String ledDimCommand, + String ledBlinkCommand, + ArrayList statusRGBPins, + // Metrics - // Metrics - public final String cpuTempCommand; - public final String cpuMemoryCommand; - public final String cpuUtilCommand; - public final String cpuThrottleReasonCmd; - public final String cpuUptimeCommand; - public final String gpuMemoryCommand; - public final String ramUtilCommand; - public final String gpuMemUsageCommand; - public final String diskUsageCommand; - - // Device stuff - public final String restartHardwareCommand; - public final double vendorFOV; // -1 for unmanaged - public final List blacklistedResIndices; // this happens before the defaults are applied + String cpuTempCommand, + String cpuMemoryCommand, + String cpuUtilCommand, + String cpuThrottleReasonCmd, + String cpuUptimeCommand, + String gpuMemoryCommand, + String ramUtilCommand, + String gpuMemUsageCommand, + String diskUsageCommand, + // Device stuff + String restartHardwareCommand, + double vendorFOV) { // -1 for unmanaged public HardwareConfig() { - deviceName = ""; - deviceLogoPath = ""; - supportURL = ""; - ledPins = new ArrayList<>(); - ledSetCommand = ""; - ledsCanDim = false; - ledBrightnessRange = new ArrayList<>(); - statusRGBPins = new ArrayList<>(); - ledDimCommand = ""; - - cpuTempCommand = ""; - cpuMemoryCommand = ""; - cpuUtilCommand = ""; - cpuThrottleReasonCmd = ""; - cpuUptimeCommand = ""; - gpuMemoryCommand = ""; - ramUtilCommand = ""; - ledBlinkCommand = ""; - gpuMemUsageCommand = ""; - diskUsageCommand = ""; - - restartHardwareCommand = ""; - vendorFOV = -1; - blacklistedResIndices = Collections.emptyList(); - } - - @SuppressWarnings("unused") - public HardwareConfig( - String deviceName, - String deviceLogoPath, - String supportURL, - ArrayList ledPins, - String ledSetCommand, - boolean ledsCanDim, - ArrayList ledBrightnessRange, - String ledDimCommand, - String ledBlinkCommand, - ArrayList statusRGBPins, - String cpuTempCommand, - String cpuMemoryCommand, - String cpuUtilCommand, - String cpuThrottleReasonCmd, - String cpuUptimeCommand, - String gpuMemoryCommand, - String ramUtilCommand, - String gpuMemUsageCommand, - String diskUsageCommand, - String restartHardwareCommand, - double vendorFOV, - List blacklistedResIndices) { - this.deviceName = deviceName; - this.deviceLogoPath = deviceLogoPath; - this.supportURL = supportURL; - this.ledPins = ledPins; - this.ledSetCommand = ledSetCommand; - this.ledsCanDim = ledsCanDim; - this.ledBrightnessRange = ledBrightnessRange; - this.ledDimCommand = ledDimCommand; - this.ledBlinkCommand = ledBlinkCommand; - this.statusRGBPins = statusRGBPins; - this.cpuTempCommand = cpuTempCommand; - this.cpuMemoryCommand = cpuMemoryCommand; - this.cpuUtilCommand = cpuUtilCommand; - this.cpuThrottleReasonCmd = cpuThrottleReasonCmd; - this.cpuUptimeCommand = cpuUptimeCommand; - this.gpuMemoryCommand = gpuMemoryCommand; - this.ramUtilCommand = ramUtilCommand; - this.gpuMemUsageCommand = gpuMemUsageCommand; - this.diskUsageCommand = diskUsageCommand; - this.restartHardwareCommand = restartHardwareCommand; - this.vendorFOV = vendorFOV; - this.blacklistedResIndices = blacklistedResIndices; + this( + "", // deviceName + "", // deviceLogoPath + "", // supportURL + new ArrayList<>(), // ledPins + "", // ledSetCommand + false, // ledsCanDim + new ArrayList<>(), // ledBrightnessRange + "", // ledDimCommand + "", // ledBlinkCommand + new ArrayList<>(), // statusRGBPins + "", // cpuTempCommand + "", // cpuMemoryCommand + "", // cpuUtilCommand + "", // cpuThrottleReasonCmd + "", // cpuUptimeCommand + "", // gpuMemoryCommand + "", // ramUtilCommand + "", // gpuMemUsageCommand + "", // diskUsageCommand + "", // restartHardwareCommand + -1); // vendorFOV } /** @@ -150,53 +96,4 @@ public final boolean hasCommandsConfigured() { || gpuMemUsageCommand != "" || diskUsageCommand != ""; } - - @Override - public String toString() { - return "HardwareConfig [deviceName=" - + deviceName - + ", deviceLogoPath=" - + deviceLogoPath - + ", supportURL=" - + supportURL - + ", ledPins=" - + ledPins - + ", ledSetCommand=" - + ledSetCommand - + ", ledsCanDim=" - + ledsCanDim - + ", ledBrightnessRange=" - + ledBrightnessRange - + ", ledDimCommand=" - + ledDimCommand - + ", ledBlinkCommand=" - + ledBlinkCommand - + ", statusRGBPins=" - + statusRGBPins - + ", cpuTempCommand=" - + cpuTempCommand - + ", cpuMemoryCommand=" - + cpuMemoryCommand - + ", cpuUtilCommand=" - + cpuUtilCommand - + ", cpuThrottleReasonCmd=" - + cpuThrottleReasonCmd - + ", cpuUptimeCommand=" - + cpuUptimeCommand - + ", gpuMemoryCommand=" - + gpuMemoryCommand - + ", ramUtilCommand=" - + ramUtilCommand - + ", gpuMemUsageCommand=" - + gpuMemUsageCommand - + ", diskUsageCommand=" - + diskUsageCommand - + ", restartHardwareCommand=" - + restartHardwareCommand - + ", vendorFOV=" - + vendorFOV - + ", blacklistedResIndices=" - + blacklistedResIndices - + "]"; - } } diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/LegacyConfigProvider.java b/photon-core/src/main/java/org/photonvision/common/configuration/LegacyConfigProvider.java index 6c2dca8cc9..f82e6f914d 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/LegacyConfigProvider.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/LegacyConfigProvider.java @@ -32,7 +32,6 @@ import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.*; -import java.util.stream.Collectors; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; import org.photonvision.common.util.file.FileUtils; @@ -280,9 +279,7 @@ private HashMap loadCameraConfigs() { HashMap loadedConfigurations = new HashMap<>(); try { var subdirectories = - Files.list(camerasFolder.toPath()) - .filter(f -> f.toFile().isDirectory()) - .collect(Collectors.toList()); + Files.list(camerasFolder.toPath()).filter(f -> f.toFile().isDirectory()).toList(); for (var subdir : subdirectories) { var cameraConfigPath = Path.of(subdir.toString(), "config.json"); @@ -348,7 +345,7 @@ private HashMap loadCameraConfigs() { return null; }) .filter(Objects::nonNull) - .collect(Collectors.toList()) + .toList() : Collections.emptyList(); loadedConfig.driveModeSettings = driverMode; diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java b/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java index d2808bb3cc..bae7c4ced3 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java @@ -398,7 +398,7 @@ private void saveCameras(Connection conn) { } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .toList(); statement.setString(4, JacksonUtils.serializeToString(settings)); statement.executeUpdate(); diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/events/HTTPRequestEvent.java b/photon-core/src/main/java/org/photonvision/common/dataflow/events/HTTPRequestEvent.java deleted file mode 100644 index 5843ba1cca..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/events/HTTPRequestEvent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.dataflow.events; - -import org.photonvision.common.dataflow.DataChangeDestination; -import org.photonvision.common.dataflow.DataChangeSource; - -public class HTTPRequestEvent extends DataChangeEvent { - public HTTPRequestEvent( - DataChangeSource sourceType, - DataChangeDestination destType, - String propertyName, - T newValue) { - super(sourceType, destType, propertyName, newValue); - } -} diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NTDataPublisher.java b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NTDataPublisher.java index a3a8971f9b..92275a6437 100644 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NTDataPublisher.java +++ b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NTDataPublisher.java @@ -205,8 +205,8 @@ public void accept(CVPipelineResult result) { ts.cameraIntrinsicsPublisher.accept(fsp.cameraCalibration.getIntrinsicsArr()); ts.cameraDistortionPublisher.accept(fsp.cameraCalibration.getDistCoeffsArr()); } else { - ts.cameraIntrinsicsPublisher.accept(new double[] {}); - ts.cameraDistortionPublisher.accept(new double[] {}); + ts.cameraIntrinsicsPublisher.accept(new double[0]); + ts.cameraDistortionPublisher.accept(new double[0]); } ts.heartbeatPublisher.set(acceptedResult.sequenceID); diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIPhotonConfiguration.java b/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIPhotonConfiguration.java index 97b609f3dc..4d5758bf73 100644 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIPhotonConfiguration.java +++ b/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIPhotonConfiguration.java @@ -18,7 +18,6 @@ package org.photonvision.common.dataflow.websocket; import java.util.List; -import java.util.stream.Collectors; import org.photonvision.PhotonVersion; import org.photonvision.common.configuration.NeuralNetworkModelManager; import org.photonvision.common.configuration.PhotonConfiguration; @@ -49,7 +48,7 @@ public static UIPhotonConfiguration programStateToUi(PhotonConfiguration c) { NetworkManager.getInstance().networkingIsDisabled), new UILightingConfig( c.getHardwareSettings().ledBrightnessPercentage, - !c.getHardwareConfig().ledPins.isEmpty()), + !c.getHardwareConfig().ledPins().isEmpty()), new UIGeneralSettings( PhotonVersion.versionString, // TODO add support for other types of GPU accel @@ -57,13 +56,13 @@ public static UIPhotonConfiguration programStateToUi(PhotonConfiguration c) { MrCalJNILoader.getInstance().isLoaded(), NeuralNetworkModelManager.getInstance().getModels(), NeuralNetworkModelManager.getInstance().getSupportedBackends(), - c.getHardwareConfig().deviceName.isEmpty() + c.getHardwareConfig().deviceName().isEmpty() ? Platform.getHardwareModel() - : c.getHardwareConfig().deviceName, + : c.getHardwareConfig().deviceName(), Platform.getPlatformName()), c.getApriltagFieldLayout()), VisionSourceManager.getInstance().getVisionModules().stream() .map(VisionModule::toUICameraConfig) - .collect(Collectors.toList())); + .toList()); } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java b/photon-core/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java index f67beb97cc..36c9d28af3 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java @@ -92,8 +92,8 @@ public void setBrightnessImpl(int brightness) { public static void setConfig(HardwareConfig config) { if (Platform.isRaspberryPi()) return; - commands.replace("setState", config.ledSetCommand); - commands.replace("dim", config.ledDimCommand); - commands.replace("blink", config.ledBlinkCommand); + commands.replace("setState", config.ledSetCommand()); + commands.replace("dim", config.ledDimCommand()); + commands.replace("blink", config.ledBlinkCommand()); } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java b/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java index 2c9a95615b..e1a2170314 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java @@ -94,22 +94,22 @@ private HardwareManager(HardwareConfig hardwareConfig, HardwareSettings hardware } statusLED = - hardwareConfig.statusRGBPins.size() == 3 - ? new StatusLED(hardwareConfig.statusRGBPins) + hardwareConfig.statusRGBPins().size() == 3 + ? new StatusLED(hardwareConfig.statusRGBPins()) : null; if (statusLED != null) { TimedTaskManager.getInstance().addTask("StatusLEDUpdate", this::statusLEDUpdate, 150); } - var hasBrightnessRange = hardwareConfig.ledBrightnessRange.size() == 2; + var hasBrightnessRange = hardwareConfig.ledBrightnessRange().size() == 2; visionLED = - hardwareConfig.ledPins.isEmpty() + hardwareConfig.ledPins().isEmpty() ? null : new VisionLED( - hardwareConfig.ledPins, - hasBrightnessRange ? hardwareConfig.ledBrightnessRange.get(0) : 0, - hasBrightnessRange ? hardwareConfig.ledBrightnessRange.get(1) : 100, + hardwareConfig.ledPins(), + hasBrightnessRange ? hardwareConfig.ledBrightnessRange().get(0) : 0, + hasBrightnessRange ? hardwareConfig.ledBrightnessRange().get(1) : 100, pigpioSocket, ledModeState::set); @@ -158,7 +158,7 @@ public boolean restartDevice() { } } try { - return shellExec.executeBashCommand(hardwareConfig.restartHardwareCommand) == 0; + return shellExec.executeBashCommand(hardwareConfig.restartHardwareCommand()) == 0; } catch (IOException e) { logger.error("Could not restart device!", e); return false; diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/VisionLED.java b/photon-core/src/main/java/org/photonvision/common/hardware/VisionLED.java index 52fb48a97d..2a1af50868 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/VisionLED.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/VisionLED.java @@ -136,10 +136,10 @@ void onLedModeChange(NetworkTableEvent entryNotification) { if (newLedModeRaw != currentLedMode.value) { VisionLEDMode newLedMode = switch (newLedModeRaw) { - case -1 -> newLedMode = VisionLEDMode.kDefault; - case 0 -> newLedMode = VisionLEDMode.kOff; - case 1 -> newLedMode = VisionLEDMode.kOn; - case 2 -> newLedMode = VisionLEDMode.kBlink; + case -1 -> VisionLEDMode.kDefault; + case 0 -> VisionLEDMode.kOff; + case 1 -> VisionLEDMode.kOn; + case 2 -> VisionLEDMode.kBlink; default -> { logger.warn("User supplied invalid LED mode, falling back to Default"); yield VisionLEDMode.kDefault; diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java index 7a27469037..bda20e0afc 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java @@ -22,17 +22,17 @@ public class FileCmds extends CmdBase { @Override public void initCmds(HardwareConfig config) { - cpuMemoryCommand = config.cpuMemoryCommand; - cpuTemperatureCommand = config.cpuTempCommand; - cpuUtilizationCommand = config.cpuUtilCommand; - cpuThrottleReasonCmd = config.cpuThrottleReasonCmd; - cpuUptimeCommand = config.cpuUptimeCommand; + cpuMemoryCommand = config.cpuMemoryCommand(); + cpuTemperatureCommand = config.cpuTempCommand(); + cpuUtilizationCommand = config.cpuUtilCommand(); + cpuThrottleReasonCmd = config.cpuThrottleReasonCmd(); + cpuUptimeCommand = config.cpuUptimeCommand(); - gpuMemoryCommand = config.gpuMemoryCommand; - gpuMemUsageCommand = config.gpuMemUsageCommand; + gpuMemoryCommand = config.gpuMemoryCommand(); + gpuMemUsageCommand = config.gpuMemUsageCommand(); - diskUsageCommand = config.diskUsageCommand; + diskUsageCommand = config.diskUsageCommand(); - ramUsageCommand = config.ramUtilCommand; + ramUsageCommand = config.ramUtilCommand(); } } diff --git a/photon-core/src/main/java/org/photonvision/common/logging/Logger.java b/photon-core/src/main/java/org/photonvision/common/logging/Logger.java index 7bba651b53..8bad357969 100644 --- a/photon-core/src/main/java/org/photonvision/common/logging/Logger.java +++ b/photon-core/src/main/java/org/photonvision/common/logging/Logger.java @@ -17,14 +17,13 @@ package org.photonvision.common.logging; +import edu.wpi.first.math.Pair; import java.io.*; import java.nio.file.Path; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.function.Supplier; -import org.apache.commons.lang3.tuple.Pair; -// import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.configuration.PathManager; import org.photonvision.common.dataflow.DataChangeService; import org.photonvision.common.dataflow.events.OutgoingUIEvent; @@ -194,7 +193,7 @@ public static void sendConnectedBacklog() { connected = true; synchronized (uiBacklog) { for (var message : uiBacklog) { - uiLogAppender.log(message.getLeft(), message.getRight()); + uiLogAppender.log(message.getFirst(), message.getSecond()); } uiBacklog.clear(); } diff --git a/photon-core/src/main/java/org/photonvision/common/networking/NetworkManager.java b/photon-core/src/main/java/org/photonvision/common/networking/NetworkManager.java index f358c1cd85..0abf4c3e31 100644 --- a/photon-core/src/main/java/org/photonvision/common/networking/NetworkManager.java +++ b/photon-core/src/main/java/org/photonvision/common/networking/NetworkManager.java @@ -77,21 +77,22 @@ public void initialize(boolean shouldManage) { var ethernetDevices = NetworkUtils.getAllWiredInterfaces(); for (NMDeviceInfo deviceInfo : ethernetDevices) { activeConnections.put( - deviceInfo.devName, NetworkUtils.getActiveConnection(deviceInfo.devName)); - monitorDevice(deviceInfo.devName, 5000); + deviceInfo.devName(), NetworkUtils.getActiveConnection(deviceInfo.devName())); + monitorDevice(deviceInfo.devName(), 5000); } var physicalDevices = NetworkUtils.getAllActiveWiredInterfaces(); var config = ConfigManager.getInstance().getConfig().getNetworkConfig(); - if (physicalDevices.stream().noneMatch(it -> (it.devName.equals(config.networkManagerIface)))) { + if (physicalDevices.stream() + .noneMatch(it -> (it.devName().equals(config.networkManagerIface)))) { try { // if the configured interface isn't in the list of available ones, select one that is var iFace = physicalDevices.stream().findFirst().orElseThrow(); logger.warn( "The configured interface doesn't match any available interface. Applying configuration to " - + iFace.devName); + + iFace.devName()); // update NetworkConfig with found interface - config.networkManagerIface = iFace.devName; + config.networkManagerIface = iFace.devName(); ConfigManager.getInstance().requestSave(); } catch (NoSuchElementException e) { // if there are no available interfaces, go with the one from settings diff --git a/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java b/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java index fc7b31735f..fa24c4e66c 100644 --- a/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java +++ b/photon-core/src/main/java/org/photonvision/common/networking/NetworkUtils.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.photonvision.common.hardware.Platform; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; @@ -53,26 +52,16 @@ public static NMType typeForString(String s) { } } - public static class NMDeviceInfo { + /** + * Contains data about network devices retrieved from "nmcli device show" + * + * @param connName The human-readable name used by "nmcli con" + * @param devName The underlying device name, used by dhclient + * @param nmType The NetworkManager device type + */ + public static record NMDeviceInfo(String connName, String devName, NMType nmType) { public NMDeviceInfo(String c, String d, String type) { - connName = c; - devName = d; - nmType = NMType.typeForString(type); - } - - public final String connName; // Human-readable name used by "nmcli con" - public final String devName; // underlying device, used by dhclient - public final NMType nmType; - - @Override - public String toString() { - return "NMDeviceInfo [connName=" - + connName - + ", devName=" - + devName - + ", nmType=" - + nmType - + "]"; + this(c, d, NMType.typeForString(type)); } } @@ -118,24 +107,35 @@ public static List getAllInterfaces() { return ret; } + /** + * Returns an immutable list of active network interfaces. + * + * @return The list. + */ public static List getAllActiveInterfaces() { // Seems like if an interface exists but isn't actually connected, the connection name will be // an empty string. Check here and only return connections with non-empty names - return getAllInterfaces().stream() - .filter(it -> !it.connName.trim().isEmpty()) - .collect(Collectors.toList()); + return getAllInterfaces().stream().filter(it -> !it.connName.trim().isEmpty()).toList(); } + /** + * Returns an immutable list of all wired network interfaces. + * + * @return The list. + */ public static List getAllWiredInterfaces() { return getAllInterfaces().stream() .filter(it -> it.nmType.equals(NMType.NMTYPE_ETHERNET)) - .collect(Collectors.toList()); + .toList(); } + /** + * Returns an immutable list of all wired and active network interfaces. + * + * @return The list. + */ public static List getAllActiveWiredInterfaces() { - return getAllWiredInterfaces().stream() - .filter(it -> !it.connName.isBlank()) - .collect(Collectors.toList()); + return getAllWiredInterfaces().stream().filter(it -> !it.connName.isBlank()).toList(); } public static NMDeviceInfo getNMinfoForConnName(String connName) { diff --git a/photon-core/src/main/java/org/photonvision/common/networking/RoborioFinder.java b/photon-core/src/main/java/org/photonvision/common/networking/RoborioFinder.java deleted file mode 100644 index 605480e296..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/networking/RoborioFinder.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 . - */ - -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 map = new HashMap<>(); - var subMap = new HashMap(); - // Separate 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 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 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) { - } - } -} diff --git a/photon-core/src/main/java/org/photonvision/common/scripting/ScriptCommandType.java b/photon-core/src/main/java/org/photonvision/common/scripting/ScriptCommandType.java deleted file mode 100644 index debc05c1b8..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/scripting/ScriptCommandType.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.scripting; - -public enum ScriptCommandType { - kDefault(""), - kBashScript("bash"), - kPythonScript("python"), - kPython3Script("python3"); - - public final String value; - - ScriptCommandType(String value) { - this.value = value; - } -} diff --git a/photon-core/src/main/java/org/photonvision/common/util/MemoryManager.java b/photon-core/src/main/java/org/photonvision/common/util/MemoryManager.java deleted file mode 100644 index d84536e0a4..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/util/MemoryManager.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.util; - -public class MemoryManager { - private static final long MEGABYTE_FACTOR = 1024L * 1024L; - - private int collectionThreshold; - private long collectionPeriodMillis = -1; - - private double lastUsedMb = 0; - private long lastCollectionMillis = 0; - - public MemoryManager(int collectionThreshold) { - this.collectionThreshold = collectionThreshold; - } - - public MemoryManager(int collectionThreshold, long collectionPeriodMillis) { - this.collectionThreshold = collectionThreshold; - this.collectionPeriodMillis = collectionPeriodMillis; - } - - public void setCollectionThreshold(int collectionThreshold) { - this.collectionThreshold = collectionThreshold; - } - - public void setCollectionPeriodMillis(long collectionPeriodMillis) { - this.collectionPeriodMillis = collectionPeriodMillis; - } - - private static long getUsedMemory() { - return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); - } - - private static double getUsedMemoryMB() { - return ((double) getUsedMemory() / MEGABYTE_FACTOR); - } - - private void collect() { - System.gc(); - System.runFinalization(); - } - - public void run() { - run(false); - } - - public void run(boolean print) { - var usedMem = getUsedMemoryMB(); - - if (usedMem != lastUsedMb) { - lastUsedMb = usedMem; - if (print) System.out.printf("Memory usage: %.2fMB\n", usedMem); - } - - boolean collectionThresholdPassed = usedMem >= collectionThreshold; - boolean collectionPeriodPassed = - collectionPeriodMillis != -1 - && (System.currentTimeMillis() - lastCollectionMillis >= collectionPeriodMillis); - - if (collectionThresholdPassed || collectionPeriodPassed) { - collect(); - lastCollectionMillis = System.currentTimeMillis(); - if (print) { - System.out.printf("Garbage collected at %.2fMB\n", usedMem); - } - } - } -} diff --git a/photon-core/src/main/java/org/photonvision/common/util/NativeLibHelper.java b/photon-core/src/main/java/org/photonvision/common/util/NativeLibHelper.java deleted file mode 100644 index a8d7dd5ef0..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/util/NativeLibHelper.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.util; - -import java.nio.file.Path; -import java.nio.file.Paths; - -public class NativeLibHelper { - private static NativeLibHelper INSTANCE; - - public static NativeLibHelper getInstance() { - if (INSTANCE == null) { - INSTANCE = new NativeLibHelper(); - } - - return INSTANCE; - } - - public final Path NativeLibPath; - - private NativeLibHelper() { - String home = System.getProperty("user.home"); - NativeLibPath = Paths.get(home, ".pvlibs", "nativecache"); - } -} diff --git a/photon-core/src/main/java/org/photonvision/common/util/ReflectionUtils.java b/photon-core/src/main/java/org/photonvision/common/util/ReflectionUtils.java deleted file mode 100644 index cda97c3f8f..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/util/ReflectionUtils.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.util; - -public class ReflectionUtils { - public static StackTraceElement[] getFullStackTrace() { - return Thread.currentThread().getStackTrace(); - } - - public static StackTraceElement getNthCaller(int n) { - if (n < 0) n = 0; - return Thread.currentThread().getStackTrace()[n]; - } - - public static String getCallerClassName() { - StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); - for (int i = 1; i < stElements.length; i++) { - StackTraceElement ste = stElements[i]; - if (!ste.getClassName().equals(ReflectionUtils.class.getName()) - && ste.getClassName().indexOf("java.lang.Thread") != 0) { - return ste.getClassName(); - } - } - return null; - } - - public static String getCallerCallerClassName() { - StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); - String callerClassName = null; - for (int i = 1; i < stElements.length; i++) { - StackTraceElement ste = stElements[i]; - if (!ste.getClassName().equals(ReflectionUtils.class.getName()) - && ste.getClassName().indexOf("java.lang.Thread") != 0) { - if (callerClassName == null) { - callerClassName = ste.getClassName(); - } else if (!callerClassName.equals(ste.getClassName())) { - return ste.getClassName(); - } - } - } - return null; - } -} diff --git a/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java b/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java index ca12989052..cf29d613b1 100644 --- a/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java +++ b/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java @@ -28,6 +28,8 @@ import org.opencv.highgui.HighGui; import org.photonvision.jni.WpilibLoader; import org.photonvision.vision.calibration.CameraCalibrationCoefficients; +import org.photonvision.vision.pipeline.result.CVPipelineResult; +import org.photonvision.vision.target.TrackedTarget; public class TestUtils { public static boolean loadLibraries() { @@ -50,7 +52,7 @@ public enum WPI2019Image { kRocketPanelAngleDark48in(1.2192), kRocketPanelAngleDark60in(1.524); - public static double FOV = 68.5; + public static final double FOV = 68.5; public final double distanceMeters; public final Path path; @@ -88,7 +90,7 @@ public enum WPI2020Image { kRedLoading_084in(2.1336), kRedLoading_108in(2.7432); - public static double FOV = 68.5; + public static final double FOV = 68.5; public final double distanceMeters; public final Path path; @@ -108,7 +110,7 @@ public enum WPI2024Images { kBackAmpZone_117in, kSpeakerCenter_143in; - public static double FOV = 68.5; + public static final double FOV = 68.5; public final Path path; @@ -127,7 +129,7 @@ public enum WPI2023Apriltags { k162_36_Straight, k383_60_Angle2; - public static double FOV = 68.5; + public static final double FOV = 68.5; public final Translation2d approxPose; public final Path path; @@ -154,7 +156,7 @@ public enum WPI2022Image { kTerminal12ft6in(Units.feetToMeters(12.5)), kTerminal22ft6in(Units.feetToMeters(22.5)); - public static double FOV = 68.5; + public static final double FOV = 68.5; public final double distanceMeters; public final Path path; @@ -372,6 +374,20 @@ public static void showImage(Mat frame) { showImage(frame, DefaultTimeoutMillis); } + public static void printTestResults(CVPipelineResult pipelineResult) { + double fps = 1000 / pipelineResult.getLatencyMillis(); + System.out.print( + "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " fps), "); + System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); + } + + public static void printTestResultsWithLocation(CVPipelineResult pipelineResult) { + printTestResults(pipelineResult); + System.out.println( + "Found targets at " + + pipelineResult.targets.stream().map(TrackedTarget::getBestCameraToTarget3d).toList()); + } + public static Path getTestMode2023ImagePath() { return getResourcesFolderPath(true) .resolve("testimages") diff --git a/photon-core/src/main/java/org/photonvision/common/util/file/FileUtils.java b/photon-core/src/main/java/org/photonvision/common/util/file/FileUtils.java index 8dc72acbb7..cdf31cb2f0 100644 --- a/photon-core/src/main/java/org/photonvision/common/util/file/FileUtils.java +++ b/photon-core/src/main/java/org/photonvision/common/util/file/FileUtils.java @@ -17,19 +17,12 @@ package org.photonvision.common.util.file; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.PosixFilePermission; -import java.util.Arrays; import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import org.photonvision.common.hardware.Platform; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; @@ -37,8 +30,6 @@ public class FileUtils { private FileUtils() {} private static final Logger logger = new Logger(FileUtils.class, LogGroup.General); - private static final Set allReadWriteExecutePerms = - new HashSet<>(Arrays.asList(PosixFilePermission.values())); public static boolean deleteDirectory(Path path) { try { @@ -109,37 +100,4 @@ public static boolean replaceFile(Path src, Path dst) { boolean fileCopied = copyFile(src, dst); return fileDeleted && fileCopied; } - - public static void setFilePerms(Path path) throws IOException { - if (Platform.isLinux()) { - File thisFile = path.toFile(); - Set perms = - Files.readAttributes(path, PosixFileAttributes.class).permissions(); - if (!perms.equals(allReadWriteExecutePerms)) { - logger.info("Setting perms on" + path); - Files.setPosixFilePermissions(path, perms); - var theseFiles = thisFile.listFiles(); - if (thisFile.isDirectory() && theseFiles != null) { - for (File subfile : theseFiles) { - setFilePerms(subfile.toPath()); - } - } - } - } - } - - public static void setAllPerms(Path path) { - if (Platform.isLinux()) { - String command = String.format("chmod 777 -R %s", path.toString()); - try { - Process p = Runtime.getRuntime().exec(command); - p.waitFor(); - - } catch (Exception e) { - logger.error("Setting perms failed!", e); - } - } else { - logger.info("Cannot set directory permissions on Windows!"); - } - } } diff --git a/photon-core/src/main/java/org/photonvision/common/util/java/TriConsumer.java b/photon-core/src/main/java/org/photonvision/common/util/java/TriConsumer.java deleted file mode 100644 index 6f1dc67fbc..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/util/java/TriConsumer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.util.java; - -public interface TriConsumer { - void accept(T t, U u, V v); -} diff --git a/photon-core/src/main/java/org/photonvision/common/util/math/IPUtils.java b/photon-core/src/main/java/org/photonvision/common/util/math/IPUtils.java deleted file mode 100644 index f4127e782c..0000000000 --- a/photon-core/src/main/java/org/photonvision/common/util/math/IPUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.common.util.math; - -import java.util.ArrayList; -import java.util.List; - -public class IPUtils { - public static boolean isValidIPV4(final String ip) { - String PATTERN = - "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$"; - - return ip.matches(PATTERN); - } - - public static List getDigitBytes(int num) { - List digits = new ArrayList<>(); - collectDigitBytes(num, digits); - return digits; - } - - private static void collectDigitBytes(int num, List digits) { - if (num / 10 > 0) { - collectDigitBytes(num / 10, digits); - } - digits.add((byte) (num % 10)); - } - - public static List getDigits(int num) { - List digits = new ArrayList<>(); - collectDigits(num, digits); - return digits; - } - - private static void collectDigits(int num, List digits) { - if (num / 10 > 0) { - collectDigits(num / 10, digits); - } - digits.add(num % 10); - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/calibration/JsonImageMat.java b/photon-core/src/main/java/org/photonvision/vision/calibration/JsonImageMat.java deleted file mode 100644 index 241004cca6..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/calibration/JsonImageMat.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.calibration; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Base64; -import org.opencv.core.Mat; -import org.opencv.core.MatOfByte; -import org.opencv.imgcodecs.Imgcodecs; -import org.photonvision.vision.opencv.Releasable; - -/** JSON-serializable image. Data is stored as base64-encoded PNG data. */ -public class JsonImageMat implements Releasable { - public final int rows; - public final int cols; - public final int type; - - // We store image data as a base64-encoded PNG inside a Java string. This lets us serialize it - // without too much overhead and still use JSON. - public final String data; - - // Cached matrices to avoid object recreation - @JsonIgnore private Mat wrappedMat = null; - - public JsonImageMat(Mat mat) { - this.rows = mat.rows(); - this.cols = mat.cols(); - this.type = mat.type(); - - // Convert from Mat -> png byte array -> base64 - var buf = new MatOfByte(); - Imgcodecs.imencode(".png", mat, buf); - data = Base64.getEncoder().encodeToString(buf.toArray()); - buf.release(); - } - - public JsonImageMat( - @JsonProperty("rows") int rows, - @JsonProperty("cols") int cols, - @JsonProperty("type") int type, - @JsonProperty("data") String data) { - this.rows = rows; - this.cols = cols; - this.type = type; - this.data = data; - } - - @JsonIgnore - public Mat getAsMat() { - if (wrappedMat == null) { - // Convert back from base64 string -> png -> Mat - var bytes = Base64.getDecoder().decode(data); - var pngData = new MatOfByte(bytes); - this.wrappedMat = Imgcodecs.imdecode(pngData, Imgcodecs.IMREAD_COLOR); - } - return this.wrappedMat; - } - - @Override - public void release() { - if (wrappedMat != null) wrappedMat.release(); - } - - @Override - public String toString() { - return "JsonImageMat [rows=" - + rows - + ", cols=" - + cols - + ", type=" - + type - + ", datalen=" - + data.length() - + "]"; - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/calibration/JsonMatOfDouble.java b/photon-core/src/main/java/org/photonvision/vision/calibration/JsonMatOfDouble.java index 6bae04aaf1..ff463e198a 100644 --- a/photon-core/src/main/java/org/photonvision/vision/calibration/JsonMatOfDouble.java +++ b/photon-core/src/main/java/org/photonvision/vision/calibration/JsonMatOfDouble.java @@ -110,7 +110,7 @@ public Matrix getAsWpilibMat() { if (wpilibMat == null) { wpilibMat = new Matrix(new SimpleMatrix(rows, cols, true, data)); } - return (Matrix) wpilibMat; + return wpilibMat; } @Override diff --git a/photon-core/src/main/java/org/photonvision/vision/calibration/UICameraCalibrationCoefficients.java b/photon-core/src/main/java/org/photonvision/vision/calibration/UICameraCalibrationCoefficients.java index 14cbfa51e7..123b1063df 100644 --- a/photon-core/src/main/java/org/photonvision/vision/calibration/UICameraCalibrationCoefficients.java +++ b/photon-core/src/main/java/org/photonvision/vision/calibration/UICameraCalibrationCoefficients.java @@ -18,11 +18,12 @@ package org.photonvision.vision.calibration; import java.util.List; -import java.util.stream.Collectors; import org.opencv.core.Size; public class UICameraCalibrationCoefficients extends CameraCalibrationCoefficients { public int numSnapshots; + + /** Immutable list of mean errors. */ public List meanErrors; public UICameraCalibrationCoefficients( @@ -51,9 +52,9 @@ public UICameraCalibrationCoefficients( .map( it2 -> it2.reprojectionErrors.stream() - .mapToDouble(it -> Math.sqrt(it.x * it.x + it.y * it.y)) + .mapToDouble(it -> Math.hypot(it.x, it.y)) .average() .orElse(0)) - .collect(Collectors.toList()); + .toList(); } } diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java b/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java index 023394ee23..9728569cbf 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java @@ -123,10 +123,7 @@ public CameraType type() { public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; - if (obj instanceof PVCameraInfo info) { - return equals(info); - } - return false; + return obj instanceof PVCameraInfo info && equals(info); } @Override @@ -192,10 +189,7 @@ public CameraType type() { public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; - if (obj instanceof PVCameraInfo info) { - return equals(info); - } - return false; + return obj instanceof PVCameraInfo info && equals(info); } @Override @@ -252,10 +246,7 @@ public CameraType type() { public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; - if (obj instanceof PVFileCameraInfo info) { - return equals(info); - } - return false; + return obj instanceof PVFileCameraInfo info && equals(info); } @Override diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/QuirkyCamera.java b/photon-core/src/main/java/org/photonvision/vision/camera/QuirkyCamera.java index 4f85879f0b..c500592227 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/QuirkyCamera.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/QuirkyCamera.java @@ -19,10 +19,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; +import java.util.EnumMap; import java.util.List; +import java.util.Map; import java.util.Objects; public class QuirkyCamera { @@ -112,7 +111,7 @@ public class QuirkyCamera { public final String displayName; @JsonProperty("quirks") - public final HashMap quirks; + public final Map quirks; /** * Creates a QuirkyCamera that matches by USB VID/PID @@ -153,7 +152,7 @@ private QuirkyCamera( this.baseName = baseName; this.displayName = displayName; - this.quirks = new HashMap<>(); + this.quirks = new EnumMap<>(CameraQuirk.class); // (1) Fill quirk map with the supplied Quirk list for (var q : quirks) { @@ -172,7 +171,7 @@ public QuirkyCamera( @JsonProperty("usbVid") int usbVid, @JsonProperty("usbPid") int usbPid, @JsonProperty("displayName") String displayName, - @JsonProperty("quirks") HashMap quirks) { + @JsonProperty("quirks") Map quirks) { this.baseName = baseName; this.usbPid = usbPid; this.usbVid = usbVid; @@ -212,17 +211,7 @@ public static QuirkyCamera getQuirkyCamera(int usbVid, int usbPid, String baseNa // We have a quirky camera! // Copy the quirks from our predefined object and create // a QuirkyCamera object with the complete properties - List quirks = new ArrayList(); - for (var q : CameraQuirk.values()) { - if (qc.hasQuirk(q)) quirks.add(q); - } - QuirkyCamera c = - new QuirkyCamera( - usbVid, - usbPid, - baseName, - Arrays.copyOf(quirks.toArray(), quirks.size(), CameraQuirk[].class)); - return c; + return new QuirkyCamera(baseName, usbVid, usbPid, "", new EnumMap<>(qc.quirks)); } } return new QuirkyCamera(usbVid, usbPid, baseName); @@ -245,19 +234,17 @@ public boolean equals(Object o) { @Override public String toString() { - String ret = - "QuirkyCamera [baseName=" - + baseName - + ", displayName=" - + displayName - + ", usbVid=" - + usbVid - + ", usbPid=" - + usbPid - + ", quirks=" - + quirks.toString() - + "]"; - return ret; + return "QuirkyCamera [baseName=" + + baseName + + ", displayName=" + + displayName + + ", usbVid=" + + usbVid + + ", usbPid=" + + usbPid + + ", quirks=" + + quirks.toString() + + "]"; } @Override @@ -270,12 +257,7 @@ public int hashCode() { * * @param quirksToChange map of true/false for quirks we should change */ - public void updateQuirks(HashMap quirksToChange) { - for (var q : quirksToChange.entrySet()) { - var quirk = q.getKey(); - var hasQuirk = q.getValue(); - - this.quirks.put(quirk, hasQuirk); - } + public void updateQuirks(Map quirksToChange) { + quirks.putAll(quirksToChange); } } diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/GenericUSBCameraSettables.java b/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/GenericUSBCameraSettables.java index dcfea72c5f..7d923bad83 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/GenericUSBCameraSettables.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/GenericUSBCameraSettables.java @@ -25,13 +25,10 @@ import edu.wpi.first.util.PixelFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import org.photonvision.common.configuration.CameraConfiguration; -import org.photonvision.common.configuration.ConfigManager; import org.photonvision.vision.camera.CameraQuirk; import org.photonvision.vision.processes.VisionSourceSettables; @@ -103,12 +100,6 @@ protected void setUpExposureProperties() { // first. var autoExpProp = findProperty("exposure_auto", "auto_exposure"); - if (expProp.isPresent()) { - exposureAbsProp = expProp.get(); - this.minExposure = exposureAbsProp.getMin(); - this.maxExposure = exposureAbsProp.getMax(); - } - if (autoExpProp.isPresent()) { autoExposureProp = autoExpProp.get(); } @@ -274,21 +265,15 @@ private void cacheVideoModes() { videoModes = new HashMap<>(); List videoModesList = new ArrayList<>(); try { - VideoMode[] modes; - - modes = camera.enumerateVideoModes(); - - for (VideoMode videoMode : modes) { + for (VideoMode videoMode : camera.enumerateVideoModes()) { // Filter grey modes if (videoMode.pixelFormat == PixelFormat.kGray || videoMode.pixelFormat == PixelFormat.kUnknown) { continue; } - if (configuration.cameraQuirks.hasQuirk(CameraQuirk.FPSCap100)) { - if (videoMode.fps > 100) { - continue; - } + if (configuration.cameraQuirks.hasQuirk(CameraQuirk.FPSCap100) && videoMode.fps > 100) { + continue; } videoModesList.add(videoMode); @@ -302,16 +287,8 @@ private void cacheVideoModes() { var sortedList = videoModesList.stream() .distinct() // remove redundant video mode entries - .sorted(((a, b) -> (b.width + b.height) - (a.width + a.height))) - .collect(Collectors.toList()); - Collections.reverse(sortedList); - - // On vendor cameras, respect blacklisted indices - var indexBlacklist = - ConfigManager.getInstance().getConfig().getHardwareConfig().blacklistedResIndices; - for (int badIdx : indexBlacklist) { - sortedList.remove(badIdx); - } + .sorted(((a, b) -> (a.width + a.height) - (b.width + b.height))) + .toList(); for (VideoMode videoMode : sortedList) { videoModes.put(sortedList.indexOf(videoMode), videoMode); diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java b/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java index ab7bf5bc7b..b0a4dde81a 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java @@ -71,12 +71,12 @@ public USBCameraSource(CameraConfiguration config) { // yes to me... if (getCameraConfiguration().cameraQuirks == null) { int vid = - (config.matchedCameraInfo instanceof PVUsbCameraInfo) - ? ((PVUsbCameraInfo) config.matchedCameraInfo).vendorId + (config.matchedCameraInfo instanceof PVUsbCameraInfo cameraInfo) + ? cameraInfo.vendorId : -1; int pid = - (config.matchedCameraInfo instanceof PVUsbCameraInfo) - ? ((PVUsbCameraInfo) config.matchedCameraInfo).productId + (config.matchedCameraInfo instanceof PVUsbCameraInfo cameraInfo) + ? cameraInfo.productId : -1; getCameraConfiguration().cameraQuirks = diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/csi/LibcameraGpuSource.java b/photon-core/src/main/java/org/photonvision/vision/camera/csi/LibcameraGpuSource.java index 28449e9ac2..6fa1223db8 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/csi/LibcameraGpuSource.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/csi/LibcameraGpuSource.java @@ -100,7 +100,7 @@ public boolean isVendorCamera() { @Override public boolean hasLEDs() { - return (ConfigManager.getInstance().getConfig().getHardwareConfig().ledPins.size() > 0); + return (ConfigManager.getInstance().getConfig().getHardwareConfig().ledPins().size() > 0); } @Override diff --git a/photon-core/src/main/java/org/photonvision/vision/frame/FrameConsumer.java b/photon-core/src/main/java/org/photonvision/vision/frame/FrameConsumer.java deleted file mode 100644 index c22fe707e5..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/frame/FrameConsumer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.frame; - -import java.util.function.Consumer; - -public interface FrameConsumer extends Consumer {} diff --git a/photon-core/src/main/java/org/photonvision/vision/frame/consumer/DummyFrameConsumer.java b/photon-core/src/main/java/org/photonvision/vision/frame/consumer/DummyFrameConsumer.java deleted file mode 100644 index 1e9449a355..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/frame/consumer/DummyFrameConsumer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.frame.consumer; - -import org.photonvision.vision.frame.Frame; -import org.photonvision.vision.frame.FrameConsumer; - -public class DummyFrameConsumer implements FrameConsumer { - @Override - public void accept(Frame frame) { - frame.release(); // lol ez - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumer.java b/photon-core/src/main/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumer.java index d12f491fd6..dce9366a52 100644 --- a/photon-core/src/main/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumer.java +++ b/photon-core/src/main/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumer.java @@ -103,19 +103,17 @@ public void accept(CVMat image, Date now) { + matchData; // Check if the Unique Camera directory exists and create it if it doesn't - String cameraPath = FILE_PATH + File.separator + this.cameraUniqueName; - var cameraDir = new File(cameraPath); + var cameraDir = new File(FILE_PATH, this.cameraUniqueName); if (!cameraDir.exists()) { cameraDir.mkdir(); } - - String saveFilePath = cameraPath + File.separator + fileName + FILE_EXTENSION; + var saveFilePath = cameraDir.toPath().resolve(fileName + FILE_EXTENSION); logger.info("Saving image to: " + saveFilePath); if (image == null || image.getMat() == null || image.getMat().empty()) { - Imgcodecs.imwrite(saveFilePath, StaticFrames.LOST_MAT); + Imgcodecs.imwrite(saveFilePath.toString(), StaticFrames.LOST_MAT); } else { - Imgcodecs.imwrite(saveFilePath, image.getMat()); + Imgcodecs.imwrite(saveFilePath.toString(), image.getMat()); } savedImagesCount++; @@ -178,6 +176,9 @@ private String getMatchData() { } public void close() { - // troododfa;lkjadsf;lkfdsaj otgooadflsk;j + saveFrameEntry.close(); + ntEventName.close(); + ntMatchNum.close(); + ntMatchType.close(); } } diff --git a/photon-core/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java b/photon-core/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java index 189a8107be..b99dc23f31 100644 --- a/photon-core/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java +++ b/photon-core/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java @@ -17,11 +17,9 @@ package org.photonvision.vision.frame.consumer; +import edu.wpi.first.cameraserver.CameraServer; import edu.wpi.first.cscore.*; -import edu.wpi.first.networktables.NetworkTable; -import edu.wpi.first.networktables.NetworkTableInstance; import edu.wpi.first.util.PixelFormat; -import java.util.ArrayList; import org.photonvision.common.util.math.MathUtils; import org.photonvision.vision.frame.StaticFrames; import org.photonvision.vision.opencv.CVMat; @@ -34,59 +32,13 @@ public class MJPGFrameConsumer implements AutoCloseable { private CvSource cvSource; private MjpegServer mjpegServer; - private VideoListener listener; - - private final NetworkTable table; - public MJPGFrameConsumer(String sourceName, int width, int height, int port) { this.cvSource = new CvSource(sourceName, PixelFormat.kMJPEG, width, height, 30); - this.table = - NetworkTableInstance.getDefault().getTable("/CameraPublisher").getSubTable(sourceName); this.mjpegServer = new MjpegServer("serve_" + cvSource.getName(), port); mjpegServer.setSource(cvSource); mjpegServer.setCompression(75); - - listener = - new VideoListener( - event -> { - if (event.kind == VideoEvent.Kind.kNetworkInterfacesChanged) { - table.getEntry("source").setString("cv:"); - table.getEntry("streams"); - table.getEntry("connected").setBoolean(true); - table.getEntry("mode").setString(videoModeToString(cvSource.getVideoMode())); - table.getEntry("modes").setStringArray(getSourceModeValues(cvSource.getHandle())); - updateStreamValues(); - } - }, - 0x4fff, - true); - } - - private synchronized void updateStreamValues() { - // Get port - int port = mjpegServer.getPort(); - - // Generate values - var addresses = CameraServerJNI.getNetworkInterfaces(); - ArrayList values = new ArrayList<>(addresses.length + 1); - String listenAddress = CameraServerJNI.getMjpegServerListenAddress(mjpegServer.getHandle()); - if (!listenAddress.isEmpty()) { - // If a listen address is specified, only use that - values.add(makeStreamValue(listenAddress, port)); - } else { - // Otherwise generate for hostname and all interface addresses - values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port)); - for (String addr : addresses) { - if ("127.0.0.1".equals(addr)) { - continue; // ignore localhost - } - values.add(makeStreamValue(addr, port)); - } - } - - String[] streamAddresses = values.toArray(new String[0]); - table.getEntry("streams").setStringArray(streamAddresses); + CameraServer.addServer(mjpegServer); } public MJPGFrameConsumer(String name, int port) { @@ -106,53 +58,12 @@ public void accept(CVMat image) { } } - public int getCurrentStreamPort() { - return mjpegServer.getPort(); - } - - private static String makeStreamValue(String address, int port) { - return "mjpg:http://" + address + ":" + port + "/?action=stream"; - } - - private static String[] getSourceModeValues(int sourceHandle) { - VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle); - String[] modeStrings = new String[modes.length]; - for (int i = 0; i < modes.length; i++) { - modeStrings[i] = videoModeToString(modes[i]); - } - return modeStrings; - } - - private static String videoModeToString(VideoMode mode) { - return mode.width - + "x" - + mode.height - + " " - + pixelFormatToString(mode.pixelFormat) - + " " - + mode.fps - + " fps"; - } - - private static String pixelFormatToString(PixelFormat pixelFormat) { - return switch (pixelFormat) { - case kMJPEG -> "MJPEG"; - case kYUYV -> "YUYV"; - case kRGB565 -> "RGB565"; - case kBGR -> "BGR"; - case kGray -> "Gray"; - case kUYVY, kUnknown, kY16, kBGRA -> "Unknown"; - }; - } - @Override public void close() { - table.getEntry("connected").setBoolean(false); + CameraServer.removeServer(mjpegServer.getName()); mjpegServer.close(); cvSource.close(); - listener.close(); mjpegServer = null; cvSource = null; - listener = null; } } diff --git a/photon-core/src/main/java/org/photonvision/vision/frame/provider/CpuImageProcessor.java b/photon-core/src/main/java/org/photonvision/vision/frame/provider/CpuImageProcessor.java index 0ceb96c19a..1a9e13e607 100644 --- a/photon-core/src/main/java/org/photonvision/vision/frame/provider/CpuImageProcessor.java +++ b/photon-core/src/main/java/org/photonvision/vision/frame/provider/CpuImageProcessor.java @@ -100,7 +100,7 @@ public final Frame get() { m_processType, input.captureTimestamp, input.staticProps != null - ? input.staticProps.rotate(m_rImagePipe.getParams().rotation) + ? input.staticProps.rotate(m_rImagePipe.getParams().rotation()) : input.staticProps); } diff --git a/photon-core/src/main/java/org/photonvision/vision/frame/provider/LibcameraGpuFrameProvider.java b/photon-core/src/main/java/org/photonvision/vision/frame/provider/LibcameraGpuFrameProvider.java index 6a354257b0..2fa04fba2d 100644 --- a/photon-core/src/main/java/org/photonvision/vision/frame/provider/LibcameraGpuFrameProvider.java +++ b/photon-core/src/main/java/org/photonvision/vision/frame/provider/LibcameraGpuFrameProvider.java @@ -121,13 +121,13 @@ public void requestFrameRotation(ImageRotationMode rotationMode) { public void requestHsvSettings(HSVParams params) { LibCameraJNI.setThresholds( settables.r_ptr, - params.getHsvLower().val[0] / 180.0, - params.getHsvLower().val[1] / 255.0, - params.getHsvLower().val[2] / 255.0, - params.getHsvUpper().val[0] / 180.0, - params.getHsvUpper().val[1] / 255.0, - params.getHsvUpper().val[2] / 255.0, - params.getHueInverted()); + params.hsvLower().val[0] / 180.0, + params.hsvLower().val[1] / 255.0, + params.hsvLower().val[2] / 255.0, + params.hsvUpper().val[0] / 180.0, + params.hsvUpper().val[1] / 255.0, + params.hsvUpper().val[2] / 255.0, + params.hueInverted()); } @Override diff --git a/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java b/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java index bbbae5269e..51cf489157 100644 --- a/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java +++ b/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java @@ -90,14 +90,15 @@ public List resizeDetections(List. - */ - -package org.photonvision.vision.opencv; - -import org.opencv.core.Mat; - -public class DualMat { - public Mat first; - public Mat second; -} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipe.java index e4737ce959..01e237c410 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipe.java @@ -20,12 +20,14 @@ import edu.wpi.first.apriltag.AprilTagDetection; import edu.wpi.first.apriltag.AprilTagDetector; import java.util.List; +import org.photonvision.vision.apriltag.AprilTagFamily; import org.photonvision.vision.opencv.CVMat; import org.photonvision.vision.opencv.Releasable; import org.photonvision.vision.pipe.CVPipe; public class AprilTagDetectionPipe - extends CVPipe, AprilTagDetectionPipeParams> + extends CVPipe< + CVMat, List, AprilTagDetectionPipe.AprilTagDetectionPipeParams> implements Releasable { private AprilTagDetector m_detector = new AprilTagDetector(); @@ -58,11 +60,11 @@ protected List process(CVMat in) { @Override public void setParams(AprilTagDetectionPipeParams newParams) { if (this.params == null || !this.params.equals(newParams)) { - m_detector.setConfig(newParams.detectorParams); - m_detector.setQuadThresholdParameters(newParams.quadParams); + m_detector.setConfig(newParams.detectorParams()); + m_detector.setQuadThresholdParameters(newParams.quadParams()); m_detector.clearFamilies(); - m_detector.addFamily(newParams.family.getNativeName()); + m_detector.addFamily(newParams.family().getNativeName()); } super.setParams(newParams); @@ -73,4 +75,9 @@ public void release() { m_detector.close(); m_detector = null; } + + public static record AprilTagDetectionPipeParams( + AprilTagFamily family, + AprilTagDetector.Config detectorParams, + AprilTagDetector.QuadThresholdParameters quadParams) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipeParams.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipeParams.java deleted file mode 100644 index 773a0d299b..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipeParams.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.pipe.impl; - -import edu.wpi.first.apriltag.AprilTagDetector; -import org.photonvision.vision.apriltag.AprilTagFamily; - -public class AprilTagDetectionPipeParams { - public final AprilTagFamily family; - public final AprilTagDetector.Config detectorParams; - public final AprilTagDetector.QuadThresholdParameters quadParams; - - public AprilTagDetectionPipeParams( - AprilTagFamily tagFamily, - AprilTagDetector.Config config, - AprilTagDetector.QuadThresholdParameters quadParams) { - this.family = tagFamily; - this.detectorParams = config; - this.quadParams = quadParams; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((family == null) ? 0 : family.hashCode()); - result = prime * result + ((detectorParams == null) ? 0 : detectorParams.hashCode()); - result = prime * result + ((quadParams == null) ? 0 : quadParams.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - AprilTagDetectionPipeParams other = (AprilTagDetectionPipeParams) obj; - if (family != other.family) return false; - if (detectorParams == null) { - if (other.detectorParams != null) return false; - } else if (!detectorParams.equals(other.detectorParams)) return false; - if (quadParams == null) { - if (other.quadParams != null) return false; - } else if (!quadParams.equals(other.quadParams)) return false; - return true; - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagPoseEstimatorPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagPoseEstimatorPipe.java index 3ddc2f3dee..f2c713799e 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagPoseEstimatorPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagPoseEstimatorPipe.java @@ -57,8 +57,8 @@ protected AprilTagPoseEstimate process(AprilTagDetection in) { Calib3d.undistortImagePoints( temp, temp, - params.calibration.getCameraIntrinsicsMat(), - params.calibration.getDistCoeffsMat()); + params.calibration().getCameraIntrinsicsMat(), + params.calibration().getDistCoeffsMat()); // Save out undistorted corners corners = temp.toArray(); @@ -82,13 +82,13 @@ protected AprilTagPoseEstimate process(AprilTagDetection in) { in.getCenterY(), fixedCorners); - return m_poseEstimator.estimateOrthogonalIteration(corrected, params.nIters); + return m_poseEstimator.estimateOrthogonalIteration(corrected, params.nIters()); } @Override public void setParams(AprilTagPoseEstimatorPipe.AprilTagPoseEstimatorPipeParams newParams) { - if (this.params == null || !this.params.equals(newParams)) { - m_poseEstimator.setConfig(newParams.config); + if (this.params == null || !this.params.config().equals(newParams.config())) { + m_poseEstimator.setConfig(newParams.config()); } super.setParams(newParams); @@ -99,37 +99,6 @@ public void release() { temp.release(); } - public static class AprilTagPoseEstimatorPipeParams { - final AprilTagPoseEstimator.Config config; - final CameraCalibrationCoefficients calibration; - final int nIters; - - public AprilTagPoseEstimatorPipeParams( - Config config, CameraCalibrationCoefficients cal, int nIters) { - this.config = config; - this.nIters = nIters; - this.calibration = cal; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((config == null) ? 0 : config.hashCode()); - result = prime * result + nIters; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - AprilTagPoseEstimatorPipeParams other = (AprilTagPoseEstimatorPipeParams) obj; - if (config == null) { - if (other.config != null) return false; - } else if (!config.equals(other.config)) return false; - return nIters == other.nIters; - } - } + public static record AprilTagPoseEstimatorPipeParams( + Config config, CameraCalibrationCoefficients calibration, int nIters) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoDetectionPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoDetectionPipe.java index 82dfd31c33..a360dd7c3b 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoDetectionPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoDetectionPipe.java @@ -59,13 +59,12 @@ protected List process(CVMat in) { for (var detection : detections) { double[] xCorners = detection.getXCorners(); double[] yCorners = detection.getYCorners(); - Point[] cornerPoints = - new Point[] { - new Point(xCorners[0], yCorners[0]), - new Point(xCorners[1], yCorners[1]), - new Point(xCorners[2], yCorners[2]), - new Point(xCorners[3], yCorners[3]) - }; + Point[] cornerPoints = { + new Point(xCorners[0], yCorners[0]), + new Point(xCorners[1], yCorners[1]), + new Point(xCorners[2], yCorners[2]), + new Point(xCorners[3], yCorners[3]) + }; double bltr = Math.hypot( cornerPoints[2].x - cornerPoints[0].x, cornerPoints[2].y - cornerPoints[0].y); diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoPoseEstimatorPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoPoseEstimatorPipe.java index ff9a893199..f036bfbfd1 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoPoseEstimatorPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoPoseEstimatorPipe.java @@ -86,8 +86,8 @@ protected AprilTagPoseEstimate process(ArucoDetectionResult in) { Calib3d.solvePnPGeneric( objectPoints, imagePoints, - params.calibration.getCameraIntrinsicsMat(), - params.calibration.getDistCoeffsMat(), + params.calibration().getCameraIntrinsicsMat(), + params.calibration().getDistCoeffsMat(), rvecs, tvecs, false, @@ -120,8 +120,8 @@ protected AprilTagPoseEstimate process(ArucoDetectionResult in) { @Override public void setParams(ArucoPoseEstimatorPipe.ArucoPoseEstimatorPipeParams newParams) { // exact equality check OK here, the number shouldn't change - if (this.params == null || this.params.tagSize != newParams.tagSize) { - var tagSize = newParams.tagSize; + if (this.params == null || this.params.tagSize() != newParams.tagSize()) { + var tagSize = newParams.tagSize(); // This order is relevant for SOLVEPNP_IPPE_SQUARE // The expected 2d correspondences with a tag facing the camera would be (BR, BL, TL, TR) @@ -147,15 +147,7 @@ public void release() { reprojectionErrors.release(); } - public static class ArucoPoseEstimatorPipeParams { - final CameraCalibrationCoefficients calibration; - final double tagSize; - - // object vertices defined by tag size - - public ArucoPoseEstimatorPipeParams(CameraCalibrationCoefficients cal, double tagSize) { - this.calibration = cal; - this.tagSize = tagSize; - } - } + // object vertices defined by tag size + public static record ArucoPoseEstimatorPipeParams( + CameraCalibrationCoefficients calibration, double tagSize) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/BlurPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/BlurPipe.java deleted file mode 100644 index 11eff2e21c..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/BlurPipe.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.pipe.impl; - -import org.opencv.core.Mat; -import org.opencv.core.Size; -import org.opencv.imgproc.Imgproc; -import org.photonvision.vision.pipe.MutatingPipe; - -/** Represents a pipeline that blurs the image. */ -public class BlurPipe extends MutatingPipe { - /** - * Processes this pipe. - * - * @param in Input for pipe processing. - * @return The processed frame. - */ - @Override - protected Void process(Mat in) { - Imgproc.blur(in, in, params.getBlurSize()); - return null; - } - - public static class BlurParams { - // Default BlurImagePrams with zero blur. - public static BlurParams DEFAULT = new BlurParams(0); - - // Member to store the blur size. - private final int m_blurSize; - - /** - * Constructs a new BlurImageParams. - * - * @param blurSize The blur size. - */ - public BlurParams(int blurSize) { - m_blurSize = blurSize; - } - - /** - * Returns the blur size. - * - * @return The blur size. - */ - public Size getBlurSize() { - return new Size(m_blurSize, m_blurSize); - } - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CalculateFPSPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CalculateFPSPipe.java index b840e66028..f1814a0316 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CalculateFPSPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CalculateFPSPipe.java @@ -24,19 +24,12 @@ public class CalculateFPSPipe extends CVPipe { private final LinearFilter fpsFilter = LinearFilter.movingAverage(20); - - // roll my own Timer, since this is so trivial - double lastTime = -1; + private final Timer timer = new Timer(); @Override protected Integer process(Void in) { - if (lastTime < 0) { - lastTime = Timer.getFPGATimestamp(); - } - - var now = Timer.getFPGATimestamp(); - var dtSeconds = now - lastTime; - lastTime = now; + var dtSeconds = timer.get(); + timer.reset(); // If < 1 uS between ticks, something is probably wrong int fps; diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Calibrate3dPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Calibrate3dPipe.java index 428a64362e..bfa96c5a3f 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Calibrate3dPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Calibrate3dPipe.java @@ -89,7 +89,7 @@ protected CameraCalibrationCoefficients process(CalibrationInput in) { && it.imagePoints != null && it.objectPoints != null && it.size != null) - .collect(Collectors.toList()); + .toList(); CameraCalibrationCoefficients ret; var start = System.nanoTime(); @@ -134,11 +134,9 @@ protected CameraCalibrationCoefficients calibrateOpenCV( double fxGuess, double fyGuess, Path imageSavePath) { - List objPointsIn = - in.stream().map(it -> it.objectPoints).collect(Collectors.toList()); - List imgPointsIn = - in.stream().map(it -> it.imagePoints).collect(Collectors.toList()); - List levelsArr = in.stream().map(it -> it.levels).collect(Collectors.toList()); + List objPointsIn = in.stream().map(it -> it.objectPoints).toList(); + List imgPointsIn = in.stream().map(it -> it.imagePoints).toList(); + List levelsArr = in.stream().map(it -> it.levels).toList(); if (objPointsIn.size() != imgPointsIn.size() || objPointsIn.size() != levelsArr.size()) { logger.error("objpts.size != imgpts.size"); @@ -223,10 +221,9 @@ protected CameraCalibrationCoefficients calibrateMrcal( double fyGuess, Path imageSavePath) { List corner_locations = - in.stream().map(it -> it.imagePoints).map(MatOfPoint2f::new).collect(Collectors.toList()); + in.stream().map(it -> it.imagePoints).map(MatOfPoint2f::new).toList(); - List levels = - in.stream().map(it -> it.levels).map(MatOfFloat::new).collect(Collectors.toList()); + List levels = in.stream().map(it -> it.levels).map(MatOfFloat::new).toList(); int imageWidth = (int) in.get(0).size.width; int imageHeight = (int) in.get(0).size.height; diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Collect2dTargetsPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Collect2dTargetsPipe.java index d5e4bda995..836e04fc7f 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Collect2dTargetsPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Collect2dTargetsPipe.java @@ -41,12 +41,12 @@ protected List process(List in) { var calculationParams = new TrackedTarget.TargetCalculationParameters( - params.targetOrientation == TargetOrientation.Landscape, - params.targetOffsetPointEdge, - params.robotOffsetPointMode, - params.robotOffsetSinglePoint, - params.dualOffsetValues, - params.frameStaticProperties); + params.targetOrientation() == TargetOrientation.Landscape, + params.targetOffsetPointEdge(), + params.robotOffsetPointMode(), + params.robotOffsetSinglePoint(), + params.dualOffsetValues(), + params.frameStaticProperties()); for (PotentialTarget target : in) { targets.add(new TrackedTarget(target, calculationParams, target.shape)); @@ -55,27 +55,11 @@ protected List process(List in) { return targets; } - public static class Collect2dTargetsParams { - private final RobotOffsetPointMode robotOffsetPointMode; - private final Point robotOffsetSinglePoint; - private final DualOffsetValues dualOffsetValues; - private final TargetOffsetPointEdge targetOffsetPointEdge; - private final TargetOrientation targetOrientation; - private final FrameStaticProperties frameStaticProperties; - - public Collect2dTargetsParams( - RobotOffsetPointMode robotOffsetPointMode, - Point robotOffsetSinglePoint, - DualOffsetValues dualOffsetValues, - TargetOffsetPointEdge targetOffsetPointEdge, - TargetOrientation orientation, - FrameStaticProperties frameStaticProperties) { - this.frameStaticProperties = frameStaticProperties; - this.robotOffsetPointMode = robotOffsetPointMode; - this.robotOffsetSinglePoint = robotOffsetSinglePoint; - this.dualOffsetValues = dualOffsetValues; - this.targetOffsetPointEdge = targetOffsetPointEdge; - targetOrientation = orientation; - } - } + public static record Collect2dTargetsParams( + RobotOffsetPointMode robotOffsetPointMode, + Point robotOffsetSinglePoint, + DualOffsetValues dualOffsetValues, + TargetOffsetPointEdge targetOffsetPointEdge, + TargetOrientation targetOrientation, + FrameStaticProperties frameStaticProperties) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CornerDetectionPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CornerDetectionPipe.java index 660a112038..82f5635555 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CornerDetectionPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/CornerDetectionPipe.java @@ -62,19 +62,18 @@ private List findBoundingBoxCorners(TrackedTarget target) { // find the bl/br/tr/tl corners // first, min by left/right - var list_ = Arrays.asList(points); - list_.sort(leftRightComparator); + Arrays.sort(points, leftRightComparator); // of this, we now have left and right // sort to get top and bottom - var left = new ArrayList<>(List.of(list_.get(0), list_.get(1))); - left.sort(verticalComparator); - var right = new ArrayList<>(List.of(list_.get(2), list_.get(3))); - right.sort(verticalComparator); + Point[] left = {points[0], points[1]}; + Arrays.sort(left, verticalComparator); + Point[] right = {points[2], points[3]}; + Arrays.sort(right, verticalComparator); - var tl = left.get(0); - var bl = left.get(1); - var tr = right.get(0); - var br = right.get(1); + var tl = left[0]; + var bl = left[1]; + var tr = right[0]; + var br = right[1]; return List.of(bl, br, tr, tl); } @@ -85,9 +84,7 @@ private List findBoundingBoxCorners(TrackedTarget target) { * @return The straight line distance between them. */ private static double distanceBetween(Point a, Point b) { - double xDelta = a.x - b.x; - double yDelta = a.y - b.y; - return Math.sqrt(xDelta * xDelta + yDelta * yDelta); + return Math.hypot(a.x - b.x, a.y - b.y); } /** @@ -121,12 +118,12 @@ private List detectExtremeCornersByApproxPolyDp(TrackedTarget target, boo var isOpen = !convexHull && target.hasSubContours(); var peri = Imgproc.arcLength(targetContour, true); Imgproc.approxPolyDP( - targetContour, polyOutput, params.accuracyPercentage / 600.0 * peri, !isOpen); + targetContour, polyOutput, params.accuracyPercentage() / 600.0 * peri, !isOpen); // we must have at least 4 corners for this strategy to work. // If we are looking for an exact side count that is handled here too. var pointList = new ArrayList<>(polyOutput.toList()); - if (pointList.size() < 4 || (params.exactSideCount && params.sideCount != pointList.size())) + if (pointList.size() < 4 || (params.exactSideCount() && params.sideCount() != pointList.size())) return null; target.setApproximateBoundingPolygon(polyOutput); @@ -142,11 +139,9 @@ private List detectExtremeCornersByApproxPolyDp(TrackedTarget target, boo // top left and top right are the poly corners closest to the bounding box tl and tr pointList.sort(compareDistToTl); - var tl = pointList.get(0); - pointList.remove(tl); + var tl = pointList.remove(0); pointList.sort(compareDistToTr); - var tr = pointList.get(0); - pointList.remove(tr); + var tr = pointList.remove(0); // at this point we look for points on the left/right of the center of the remaining points // and maximize their distance from the center of the min area rectangle @@ -162,12 +157,13 @@ private List detectExtremeCornersByApproxPolyDp(TrackedTarget target, boo for (var p : pointList) { if (p.y > target.m_mainContour.getBoundingRect().y - + target.m_mainContour.getBoundingRect().height / 2.0) + + target.m_mainContour.getBoundingRect().height / 2.0) { if (p.x < averageXCoordinate) { leftList.add(p); } else { rightList.add(p); } + } } if (leftList.isEmpty() || rightList.isEmpty()) return null; leftList.sort(compareCenterDist); @@ -177,29 +173,15 @@ private List detectExtremeCornersByApproxPolyDp(TrackedTarget target, boo return List.of(bl, br, tr, tl); } - public static class CornerDetectionPipeParameters { - private final DetectionStrategy cornerDetectionStrategy; - - private final boolean calculateConvexHulls; - private final boolean exactSideCount; - private final int sideCount; - - /** This number can be changed to change how "accurate" our approximate polygon must be. */ - private final double accuracyPercentage; - - public CornerDetectionPipeParameters( - DetectionStrategy cornerDetectionStrategy, - boolean calculateConvexHulls, - boolean exactSideCount, - int sideCount, - double accuracyPercentage) { - this.cornerDetectionStrategy = cornerDetectionStrategy; - this.calculateConvexHulls = calculateConvexHulls; - this.exactSideCount = exactSideCount; - this.sideCount = sideCount; - this.accuracyPercentage = accuracyPercentage; - } - } + /** + * @param accuracyPercentage Represents how "accurate" our approximate polygon must be. + */ + public static record CornerDetectionPipeParameters( + DetectionStrategy cornerDetectionStrategy, + boolean calculateConvexHulls, + boolean exactSideCount, + int sideCount, + double accuracyPercentage) {} public enum DetectionStrategy { APPROX_POLY_DP_AND_EXTREME_CORNERS diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dCrosshairPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dCrosshairPipe.java index fb22c66159..ed416b1676 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dCrosshairPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dCrosshairPipe.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipe.impl; +import edu.wpi.first.math.Pair; import java.awt.*; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Mat; import org.opencv.core.Point; import org.opencv.imgproc.Imgproc; @@ -38,30 +38,31 @@ public class Draw2dCrosshairPipe Pair>, Draw2dCrosshairPipe.Draw2dCrosshairParams> { @Override protected Void process(Pair> in) { - if (!params.shouldDraw) return null; + if (!params.shouldDraw()) return null; - var image = in.getLeft(); + var image = in.getFirst(); - if (params.showCrosshair) { - double x = params.frameStaticProperties.centerX; - double y = params.frameStaticProperties.centerY; - double scale = params.frameStaticProperties.imageWidth / (double) params.divisor.value / 32.0; + if (params.showCrosshair()) { + double x = params.frameStaticProperties().centerX; + double y = params.frameStaticProperties().centerY; + double scale = + params.frameStaticProperties().imageWidth / (double) params.divisor().value / 32.0; - switch (params.robotOffsetPointMode) { + switch (params.robotOffsetPointMode()) { case None -> {} case Single -> { - if (params.singleOffsetPoint.x != 0 && params.singleOffsetPoint.y != 0) { - x = params.singleOffsetPoint.x; - y = params.singleOffsetPoint.y; + if (params.singleOffsetPoint().x != 0 && params.singleOffsetPoint().y != 0) { + x = params.singleOffsetPoint().x; + y = params.singleOffsetPoint().y; } } case Dual -> { - if (!in.getRight().isEmpty()) { - var target = in.getRight().get(0); + if (!in.getSecond().isEmpty()) { + var target = in.getSecond().get(0); if (target != null) { var area = target.getArea(); var offsetCrosshair = - TargetCalculations.calculateDualOffsetCrosshair(params.dualOffsetValues, area); + TargetCalculations.calculateDualOffsetCrosshair(params.dualOffsetValues(), area); x = offsetCrosshair.x; y = offsetCrosshair.y; } @@ -69,60 +70,62 @@ protected Void process(Pair> in) { } } - x /= (double) params.divisor.value; - y /= (double) params.divisor.value; + x /= (double) params.divisor().value; + y /= (double) params.divisor().value; Point xMax = new Point(x + scale, y); Point xMin = new Point(x - scale, y); Point yMax = new Point(x, y + scale); Point yMin = new Point(x, y - scale); - Imgproc.line(image, xMax, xMin, ColorHelper.colorToScalar(params.crosshairColor)); - Imgproc.line(image, yMax, yMin, ColorHelper.colorToScalar(params.crosshairColor)); + Imgproc.line(image, xMax, xMin, ColorHelper.colorToScalar(params.crosshairColor())); + Imgproc.line(image, yMax, yMin, ColorHelper.colorToScalar(params.crosshairColor())); } return null; } - public static class Draw2dCrosshairParams { - public boolean showCrosshair = true; - public Color crosshairColor = Color.GREEN; - - public final boolean shouldDraw; - public final FrameStaticProperties frameStaticProperties; - public final ImageRotationMode rotMode; - public final RobotOffsetPointMode robotOffsetPointMode; - public final Point singleOffsetPoint; - public final DualOffsetValues dualOffsetValues; - private final FrameDivisor divisor; - + public static record Draw2dCrosshairParams( + boolean shouldDraw, + RobotOffsetPointMode robotOffsetPointMode, + Point singleOffsetPoint, + DualOffsetValues dualOffsetValues, + FrameStaticProperties frameStaticProperties, + FrameDivisor divisor, + ImageRotationMode rotMode, + boolean showCrosshair, + Color crosshairColor) { public Draw2dCrosshairParams( + boolean shouldDraw, + RobotOffsetPointMode robotOffsetPointMode, + Point singleOffsetPoint, + DualOffsetValues dualOffsetValues, FrameStaticProperties frameStaticProperties, FrameDivisor divisor, ImageRotationMode rotMode) { - shouldDraw = true; - this.frameStaticProperties = frameStaticProperties; - this.rotMode = rotMode; - robotOffsetPointMode = RobotOffsetPointMode.None; - singleOffsetPoint = new Point(); - dualOffsetValues = new DualOffsetValues(); - this.divisor = divisor; + this( + shouldDraw, + robotOffsetPointMode, + singleOffsetPoint, + dualOffsetValues, + frameStaticProperties, + divisor, + rotMode, + true, + Color.GREEN); } public Draw2dCrosshairParams( - boolean shouldDraw, - RobotOffsetPointMode robotOffsetPointMode, - Point singleOffsetPoint, - DualOffsetValues dualOffsetValues, FrameStaticProperties frameStaticProperties, FrameDivisor divisor, ImageRotationMode rotMode) { - this.shouldDraw = shouldDraw; - this.frameStaticProperties = frameStaticProperties; - this.robotOffsetPointMode = robotOffsetPointMode; - this.singleOffsetPoint = singleOffsetPoint; - this.dualOffsetValues = dualOffsetValues; - this.divisor = divisor; - this.rotMode = rotMode; + this( + true, + RobotOffsetPointMode.None, + new Point(), + new DualOffsetValues(), + frameStaticProperties, + divisor, + rotMode); } } } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dTargetsPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dTargetsPipe.java index 3365a5cf3e..93caa4169d 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dTargetsPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw2dTargetsPipe.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipe.impl; +import edu.wpi.first.math.Pair; import java.awt.*; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.*; import org.opencv.core.Point; import org.opencv.imgproc.Imgproc; @@ -39,15 +39,15 @@ public class Draw2dTargetsPipe @Override protected Void process(Pair> in) { - var imRows = in.getLeft().rows(); - var imCols = in.getLeft().cols(); + var imRows = in.getFirst().rows(); + var imCols = in.getFirst().cols(); var imageSize = Math.sqrt(imRows * imCols); var textSize = params.kPixelsToText * imageSize; var thickness = params.kPixelsToThickness * imageSize; if (!params.shouldDraw) return null; - if (!in.getRight().isEmpty() + if (!in.getSecond().isEmpty() && (params.showCentroid || params.showMaximumBox || params.showRotatedBox @@ -58,7 +58,7 @@ protected Void process(Pair> in) { var circleColor = ColorHelper.colorToScalar(params.circleColor); var shapeColour = ColorHelper.colorToScalar(params.shapeOutlineColour); - for (int i = 0; i < (params.showMultipleTargets ? in.getRight().size() : 1); i++) { + for (int i = 0; i < (params.showMultipleTargets ? in.getSecond().size() : 1); i++) { Point[] vertices = new Point[4]; MatOfPoint contour = new MatOfPoint(); @@ -66,7 +66,7 @@ protected Void process(Pair> in) { break; } - TrackedTarget target = in.getRight().get(i); + TrackedTarget target = in.getSecond().get(i); RotatedRect r = target.getMinAreaRect(); if (r == null) continue; @@ -77,14 +77,14 @@ protected Void process(Pair> in) { if (params.shouldShowRotatedBox(target.getShape())) { Imgproc.drawContours( - in.getLeft(), + in.getFirst(), List.of(contour), 0, rotatedBoxColour, (int) Math.ceil(imageSize * params.kPixelsToBoxThickness)); } else if (params.shouldShowCircle(target.getShape())) { Imgproc.circle( - in.getLeft(), + in.getFirst(), target.getShape().center, (int) target.getShape().radius, circleColor, @@ -101,7 +101,7 @@ protected Void process(Pair> in) { mat.fromArray(poly.toArray()); divideMat(mat, mat); Imgproc.drawContours( - in.getLeft(), + in.getFirst(), List.of(mat), -1, ColorHelper.colorToScalar(params.rotatedBoxColor), @@ -113,7 +113,7 @@ protected Void process(Pair> in) { if (params.showMaximumBox) { Rect box = Imgproc.boundingRect(contour); Imgproc.rectangle( - in.getLeft(), + in.getFirst(), new Point(box.x, box.y), new Point(box.x + box.width, box.y + box.height), maximumBoxColour, @@ -123,7 +123,7 @@ protected Void process(Pair> in) { if (params.showShape) { divideMat(target.m_mainContour.mat, tempMat); Imgproc.drawContours( - in.getLeft(), + in.getFirst(), List.of(tempMat), -1, shapeColour, @@ -142,7 +142,7 @@ protected Void process(Pair> in) { var contourNumber = String.valueOf(id == -1 ? i : id); Imgproc.putText( - in.getLeft(), + in.getFirst(), contourNumber, textPos, 0, @@ -163,13 +163,13 @@ protected Void process(Pair> in) { Point yMin = new Point(x, y - crosshairRadius); Imgproc.line( - in.getLeft(), + in.getFirst(), xMax, xMin, centroidColour, (int) Math.ceil(imageSize * params.kPixelsToBoxThickness)); Imgproc.line( - in.getLeft(), + in.getFirst(), yMax, yMin, centroidColour, diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw3dTargetsPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw3dTargetsPipe.java index e3e24d188c..c5183b66e7 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw3dTargetsPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Draw3dTargetsPipe.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipe.impl; +import edu.wpi.first.math.Pair; import java.awt.*; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.calib3d.Calib3d; import org.opencv.core.*; import org.opencv.core.Point; @@ -47,7 +47,7 @@ protected Void process(Pair> in) { return null; } - for (var target : in.getRight()) { + for (var target : in.getSecond()) { // draw convex hull if (params.shouldDrawHull(target)) { var pointMat = new MatOfPoint(); @@ -59,14 +59,14 @@ protected Void process(Pair> in) { continue; } Imgproc.drawContours( - in.getLeft(), List.of(pointMat), -1, ColorHelper.colorToScalar(Color.green), 1); + in.getFirst(), List.of(pointMat), -1, ColorHelper.colorToScalar(Color.green), 1); // draw approximate polygon var poly = target.getApproximateBoundingPolygon(); if (poly != null) { divideMat2f(poly, pointMat); Imgproc.drawContours( - in.getLeft(), List.of(pointMat), -1, ColorHelper.colorToScalar(Color.blue), 2); + in.getFirst(), List.of(pointMat), -1, ColorHelper.colorToScalar(Color.blue), 2); } pointMat.release(); } @@ -126,7 +126,7 @@ protected Void process(Pair> in) { // floor, then pillars, then top for (int i = 0; i < bottomPoints.size(); i++) { Imgproc.line( - in.getLeft(), + in.getFirst(), bottomPoints.get(i), bottomPoints.get((i + 1) % (bottomPoints.size())), ColorHelper.colorToScalar(Color.green), @@ -167,21 +167,21 @@ protected Void process(Pair> in) { // XYZ is RGB // y-axis = green Imgproc.line( - in.getLeft(), + in.getFirst(), axisPoints.get(0), axisPoints.get(2), ColorHelper.colorToScalar(Color.GREEN), 3); // z-axis = blue Imgproc.line( - in.getLeft(), + in.getFirst(), axisPoints.get(0), axisPoints.get(3), ColorHelper.colorToScalar(Color.BLUE), 3); // x-axis = red Imgproc.line( - in.getLeft(), + in.getFirst(), axisPoints.get(0), axisPoints.get(1), ColorHelper.colorToScalar(Color.RED), @@ -190,7 +190,7 @@ protected Void process(Pair> in) { // box edges perpendicular to tag for (int i = 0; i < bottomPoints.size(); i++) { Imgproc.line( - in.getLeft(), + in.getFirst(), bottomPoints.get(i), topPoints.get(i), ColorHelper.colorToScalar(Color.blue), @@ -199,7 +199,7 @@ protected Void process(Pair> in) { // box edges parallel to tag for (int i = 0; i < topPoints.size(); i++) { Imgproc.line( - in.getLeft(), + in.getFirst(), topPoints.get(i), topPoints.get((i + 1) % (bottomPoints.size())), ColorHelper.colorToScalar(Color.orange), @@ -219,7 +219,7 @@ protected Void process(Pair> in) { var y = corner.y / (double) params.divisor.value; Imgproc.circle( - in.getLeft(), + in.getFirst(), new Point(x, y), params.radius, ColorHelper.colorToScalar(params.color), diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCalibrationPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCalibrationPipe.java index 925000aa74..5f6b83a177 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCalibrationPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCalibrationPipe.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipe.impl; +import edu.wpi.first.math.Pair; import java.awt.Color; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Mat; import org.opencv.core.Point; import org.opencv.core.Scalar; @@ -32,20 +32,19 @@ public class DrawCalibrationPipe extends MutatingPipe< Pair>, DrawCalibrationPipe.DrawCalibrationPipeParams> { - Scalar[] chessboardColors = - new Scalar[] { - ColorHelper.colorToScalar(Color.RED, 0.4), - ColorHelper.colorToScalar(Color.ORANGE, 0.4), - ColorHelper.colorToScalar(Color.GREEN, 0.4), - ColorHelper.colorToScalar(Color.BLUE, 0.4), - ColorHelper.colorToScalar(Color.MAGENTA, 0.4), - }; + Scalar[] chessboardColors = { + ColorHelper.colorToScalar(Color.RED, 0.4), + ColorHelper.colorToScalar(Color.ORANGE, 0.4), + ColorHelper.colorToScalar(Color.GREEN, 0.4), + ColorHelper.colorToScalar(Color.BLUE, 0.4), + ColorHelper.colorToScalar(Color.MAGENTA, 0.4), + }; @Override protected Void process(Pair> in) { - if (!params.drawAllSnapshots) return null; + if (!params.drawAllSnapshots()) return null; - var image = in.getLeft(); + var image = in.getFirst(); var imgSz = image.size(); var diag = Math.hypot(imgSz.width, imgSz.height); @@ -56,7 +55,7 @@ protected Void process(Pair> in) { int thickness = (int) Math.max(diag * 1.0 / 600.0, 1); int i = 0; - for (var target : in.getRight()) { + for (var target : in.getSecond()) { for (var c : target.getTargetCorners()) { if (c.x < 0 || c.y < 0) { // Skip if the corner is less than zero @@ -65,7 +64,8 @@ protected Void process(Pair> in) { c = new Point( - c.x / params.divisor.value.doubleValue(), c.y / params.divisor.value.doubleValue()); + c.x / params.divisor().value.doubleValue(), + c.y / params.divisor().value.doubleValue()); var r2 = r / Math.sqrt(2); var color = chessboardColors[i % chessboardColors.length]; @@ -82,13 +82,5 @@ protected Void process(Pair> in) { return null; } - public static class DrawCalibrationPipeParams { - private final FrameDivisor divisor; - public boolean drawAllSnapshots; - - public DrawCalibrationPipeParams(FrameDivisor divisor, boolean drawSnapshots) { - this.divisor = divisor; - this.drawAllSnapshots = drawSnapshots; - } - } + public static record DrawCalibrationPipeParams(FrameDivisor divisor, boolean drawAllSnapshots) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCornerDetectionPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCornerDetectionPipe.java deleted file mode 100644 index 9ef05ad99f..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCornerDetectionPipe.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.pipe.impl; - -import java.util.List; -import org.apache.commons.lang3.tuple.Pair; -import org.opencv.core.Mat; -import org.opencv.core.Scalar; -import org.opencv.imgproc.Imgproc; -import org.photonvision.vision.pipe.MutatingPipe; -import org.photonvision.vision.target.TrackedTarget; - -public class DrawCornerDetectionPipe - extends MutatingPipe>, DrawCornerDetectionPipe.DrawCornerParams> { - @Override - protected Void process(Pair> in) { - Mat image = in.getLeft(); - - for (var target : in.getRight()) { - var corners = target.getTargetCorners(); - for (var corner : corners) { - Imgproc.circle(image, corner, params.dotRadius, params.dotColor); - } - } - - return null; - } - - public static class DrawCornerParams { - int dotRadius; - Scalar dotColor; - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ErodeDilatePipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ErodeDilatePipe.java deleted file mode 100644 index 9d09a5d198..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ErodeDilatePipe.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.pipe.impl; - -import org.opencv.core.Mat; -import org.opencv.core.Size; -import org.opencv.imgproc.Imgproc; -import org.photonvision.vision.pipe.MutatingPipe; - -public class ErodeDilatePipe extends MutatingPipe { - @Override - protected Void process(Mat in) { - if (params.shouldErode()) { - Imgproc.erode(in, in, params.getKernel()); - } - if (params.shouldDilate()) { - Imgproc.dilate(in, in, params.getKernel()); - } - return null; - } - - public static class ErodeDilateParams { - private final boolean m_erode; - private final boolean m_dilate; - private final Mat m_kernel; - - public ErodeDilateParams(boolean erode, boolean dilate, int kernelSize) { - m_erode = erode; - m_dilate = dilate; - m_kernel = - Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(kernelSize, kernelSize)); - } - - public boolean shouldErode() { - return m_erode; - } - - public boolean shouldDilate() { - return m_dilate; - } - - public Mat getKernel() { - return m_kernel; - } - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterContoursPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterContoursPipe.java index 1e7616c44f..37ee977338 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterContoursPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterContoursPipe.java @@ -38,7 +38,7 @@ protected List process(List in) { } // we need the whole list for outlier rejection - rejectOutliers(m_filteredContours, params.xTol, params.yTol); + rejectOutliers(m_filteredContours, params.xTol(), params.yTol()); return m_filteredContours; } @@ -67,9 +67,7 @@ private void rejectOutliers(List list, double xTol, double yTol) { double x = c.getCenterPoint().x; double y = c.getCenterPoint().y; - if (Math.abs(x - meanX) > stdDevX * xTol) { - it.remove(); - } else if (Math.abs(y - meanY) > stdDevY * yTol) { + if (Math.abs(x - meanX) > stdDevX * xTol || Math.abs(y - meanY) > stdDevY * yTol) { it.remove(); } // Otherwise we're good! Keep it in @@ -81,66 +79,31 @@ private void filterContour(Contour contour) { // Area Filtering. double areaPercentage = - minAreaRect.size.area() / params.getFrameStaticProperties().imageArea * 100.0; - double minAreaPercentage = params.getArea().getFirst(); - double maxAreaPercentage = params.getArea().getSecond(); + minAreaRect.size.area() / params.frameStaticProperties().imageArea * 100.0; + double minAreaPercentage = params.area().getFirst(); + double maxAreaPercentage = params.area().getSecond(); if (areaPercentage < minAreaPercentage || areaPercentage > maxAreaPercentage) return; // Fullness Filtering. double contourArea = contour.getArea(); - double minFullness = params.getFullness().getFirst() * minAreaRect.size.area() / 100.0; - double maxFullness = params.getFullness().getSecond() * minAreaRect.size.area() / 100.0; + double minFullness = params.fullness().getFirst() * minAreaRect.size.area() / 100.0; + double maxFullness = params.fullness().getSecond() * minAreaRect.size.area() / 100.0; if (contourArea <= minFullness || contourArea >= maxFullness) return; // Aspect Ratio Filtering. double aspectRatio = - TargetCalculations.getAspectRatio(contour.getMinAreaRect(), params.isLandscape); - if (aspectRatio < params.getRatio().getFirst() || aspectRatio > params.getRatio().getSecond()) - return; + TargetCalculations.getAspectRatio(contour.getMinAreaRect(), params.isLandscape()); + if (aspectRatio < params.ratio().getFirst() || aspectRatio > params.ratio().getSecond()) return; m_filteredContours.add(contour); } - public static class FilterContoursParams { - private final DoubleCouple m_area; - private final DoubleCouple m_ratio; - private final DoubleCouple m_fullness; - 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, - DoubleCouple ratio, - DoubleCouple extent, - FrameStaticProperties camProperties, - double xTol, - 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() { - return m_area; - } - - public DoubleCouple getRatio() { - return m_ratio; - } - - public DoubleCouple getFullness() { - return m_fullness; - } - - public FrameStaticProperties getFrameStaticProperties() { - return m_frameStaticProperties; - } - } + public static record FilterContoursParams( + DoubleCouple area, + DoubleCouple ratio, + DoubleCouple fullness, + FrameStaticProperties frameStaticProperties, + double xTol, // IQR tolerance for x + double yTol, // IQR tolerance for y + boolean isLandscape) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java index d22556668a..03479dc51e 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java @@ -41,49 +41,24 @@ protected List process(List in } private void filterContour(NeuralNetworkPipeResult contour) { - var boc = contour.bbox; + var boc = contour.bbox(); // Area filtering - double areaPercentage = boc.area() / params.getFrameStaticProperties().imageArea * 100.0; - double minAreaPercentage = params.getArea().getFirst(); - double maxAreaPercentage = params.getArea().getSecond(); + double areaPercentage = boc.area() / params.frameStaticProperties().imageArea * 100.0; + double minAreaPercentage = params.area().getFirst(); + double maxAreaPercentage = params.area().getSecond(); if (areaPercentage < minAreaPercentage || areaPercentage > maxAreaPercentage) return; // Aspect ratio filtering; much simpler since always axis-aligned double aspectRatio = boc.width / boc.height; - if (aspectRatio < params.getRatio().getFirst() || aspectRatio > params.getRatio().getSecond()) - return; + if (aspectRatio < params.ratio().getFirst() || aspectRatio > params.ratio().getSecond()) return; m_filteredContours.add(contour); } - public static class FilterContoursParams { - private final DoubleCouple m_area; - private final DoubleCouple m_ratio; - private final FrameStaticProperties m_frameStaticProperties; - public final boolean isLandscape; - - public FilterContoursParams( - DoubleCouple area, - DoubleCouple ratio, - FrameStaticProperties camProperties, - boolean isLandscape) { - this.m_area = area; - this.m_ratio = ratio; - this.m_frameStaticProperties = camProperties; - this.isLandscape = isLandscape; - } - - public DoubleCouple getArea() { - return m_area; - } - - public DoubleCouple getRatio() { - return m_ratio; - } - - public FrameStaticProperties getFrameStaticProperties() { - return m_frameStaticProperties; - } - } + public static record FilterContoursParams( + DoubleCouple area, + DoubleCouple ratio, + FrameStaticProperties frameStaticProperties, + boolean isLandscape) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterShapesPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterShapesPipe.java index 1802d6971f..4f2489a922 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterShapesPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterShapesPipe.java @@ -48,40 +48,20 @@ protected List process(List in) { } private boolean shouldRemove(CVShape shape) { - return shape.shape != params.desiredShape - || shape.contour.getArea() / params.getFrameStaticProperties().imageArea * 100.0 - > params.maxArea - || shape.contour.getArea() / params.getFrameStaticProperties().imageArea * 100.0 - < params.minArea - || shape.contour.getPerimeter() > params.maxPeri - || shape.contour.getPerimeter() < params.minPeri; + return shape.shape != params.desiredShape() + || shape.contour.getArea() / params.frameStaticProperties().imageArea * 100.0 + > params.maxArea() + || shape.contour.getArea() / params.frameStaticProperties().imageArea * 100.0 + < params.minArea() + || shape.contour.getPerimeter() > params.maxPeri() + || shape.contour.getPerimeter() < params.minPeri(); } - public static class FilterShapesPipeParams { - private final ContourShape desiredShape; - private final FrameStaticProperties frameStaticProperties; - private final double minArea; - private final double maxArea; - private final double minPeri; - private final double maxPeri; - - public FilterShapesPipeParams( - ContourShape desiredShape, - double minArea, - double maxArea, - double minPeri, - double maxPeri, - FrameStaticProperties frameStaticProperties) { - this.desiredShape = desiredShape; - this.minArea = minArea; - this.maxArea = maxArea; - this.minPeri = minPeri; - this.maxPeri = maxPeri; - this.frameStaticProperties = frameStaticProperties; - } - - public FrameStaticProperties getFrameStaticProperties() { - return frameStaticProperties; - } - } + public static record FilterShapesPipeParams( + ContourShape desiredShape, + double minArea, + double maxArea, + double minPeri, + double maxPeri, + FrameStaticProperties frameStaticProperties) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java index a85c57a3e0..1d670cb78e 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java @@ -17,10 +17,10 @@ package org.photonvision.vision.pipe.impl; +import edu.wpi.first.math.Pair; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.calib3d.Calib3d; import org.opencv.core.*; import org.opencv.imgproc.Imgproc; @@ -54,7 +54,7 @@ public class FindBoardCornersPipe // Since we return results in real-time, we want to ensure it goes as fast as // possible // and fails as fast as possible. - final int findChessboardFlags = + static final int findChessboardFlags = Calib3d.CALIB_CB_NORMALIZE_IMAGE | Calib3d.CALIB_CB_ADAPTIVE_THRESH | Calib3d.CALIB_CB_FILTER_QUADS @@ -91,30 +91,30 @@ public void createObjectPoints() { * number of corners. */ this.patternSize = - params.type == UICalibrationData.BoardType.CHESSBOARD - ? new Size(params.boardWidth - 1, params.boardHeight - 1) - : new Size(params.boardWidth, params.boardHeight); + params.type() == UICalibrationData.BoardType.CHESSBOARD + ? new Size(params.boardWidth() - 1, params.boardHeight() - 1) + : new Size(params.boardWidth(), params.boardHeight()); // Chessboard and dot board have different 3D points to project as a dot board // has alternating // dots per column - if (params.type == UICalibrationData.BoardType.CHESSBOARD) { + if (params.type() == UICalibrationData.BoardType.CHESSBOARD) { // Here we can create an NxN grid since a chessboard is rectangular for (int heightIdx = 0; heightIdx < patternSize.height; heightIdx++) { for (int widthIdx = 0; widthIdx < patternSize.width; widthIdx++) { - double boardYCoord = heightIdx * params.gridSize; - double boardXCoord = widthIdx * params.gridSize; + double boardYCoord = heightIdx * params.gridSize(); + double boardXCoord = widthIdx * params.gridSize(); objectPoints.push_back(new MatOfPoint3f(new Point3(boardXCoord, boardYCoord, 0.0))); } } - } else if (params.type == UICalibrationData.BoardType.CHARUCOBOARD) { + } else if (params.type() == UICalibrationData.BoardType.CHARUCOBOARD) { board = new CharucoBoard( - new Size(params.boardWidth, params.boardHeight), - (float) params.gridSize, - (float) params.markerSize, - Objdetect.getPredefinedDictionary(params.tagFamily.getValue())); - board.setLegacyPattern(params.useOldPattern); + new Size(params.boardWidth(), params.boardHeight()), + (float) params.gridSize(), + (float) params.markerSize(), + Objdetect.getPredefinedDictionary(params.tagFamily().getValue())); + board.setLegacyPattern(params.useOldPattern()); detector = new CharucoDetector(board); detector.getDetectorParameters().set_adaptiveThreshConstant(10); detector.getDetectorParameters().set_adaptiveThreshWinSizeMin(11); @@ -122,7 +122,7 @@ public void createObjectPoints() { detector.getDetectorParameters().set_adaptiveThreshWinSizeMax(91); } else { - logger.error("Can't create pattern for unknown board type " + params.type); + logger.error("Can't create pattern for unknown board type " + params.type()); } } @@ -145,7 +145,7 @@ protected FindBoardCornersPipeResult process(Pair in) { * @return */ private double getFindCornersScaleFactor(Mat inFrame) { - return 1.0 / params.divisor.value; + return 1.0 / params.divisor().value; } /** @@ -170,9 +170,7 @@ private double getApproxMinSpacing(MatOfPoint2f inPoints) { // +1 idx Neighbor distance double[] startPoint = inPoints.get(pointIdx, 0); double[] endPoint = inPoints.get(pointIdx + 1, 0); - double deltaX = startPoint[0] - endPoint[0]; - double deltaY = startPoint[1] - endPoint[1]; - double distToNext = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + double distToNext = Math.hypot(startPoint[0] - endPoint[0], startPoint[1] - endPoint[1]); minSpacing = Math.min(distToNext, minSpacing); } @@ -185,8 +183,8 @@ private double getApproxMinSpacing(MatOfPoint2f inPoints) { * @return the size to scale the input mat to */ private Size getFindCornersImgSize(Mat in) { - int width = in.cols() / params.divisor.value; - int height = in.rows() / params.divisor.value; + int width = in.cols() / params.divisor().value; + int height = in.rows() / params.divisor().value; return new Size(width, height); } @@ -222,7 +220,7 @@ private void rescalePointsToOrigFrame( */ private Size getWindowSize(MatOfPoint2f inPoints) { double windowHalfWidth = 11; // Dot board uses fixed-size window half-width - if (params.type == UICalibrationData.BoardType.CHESSBOARD) { + if (params.type() == UICalibrationData.BoardType.CHESSBOARD) { // Chessboard uses a dynamic sized window based on how far apart the corners are windowHalfWidth = Math.floor(getApproxMinSpacing(inPoints) * 0.50); windowHalfWidth = Math.max(1, windowHalfWidth); @@ -244,8 +242,8 @@ private FindBoardCornersPipeResult findBoardCorners(Pair in) { var objPts = new MatOfPoint3f(); var outBoardCorners = new MatOfPoint2f(); - var inFrame = in.getLeft(); - var outFrame = in.getRight(); + var inFrame = in.getFirst(); + var outFrame = in.getSecond(); // Convert the inFrame too grayscale to increase contrast Imgproc.cvtColor(inFrame, inFrame, Imgproc.COLOR_BGR2GRAY); @@ -254,7 +252,7 @@ private FindBoardCornersPipeResult findBoardCorners(Pair in) { // Get the size of the inFrame this.imageSize = new Size(inFrame.width(), inFrame.height()); - if (params.type == UICalibrationData.BoardType.CHARUCOBOARD) { + if (params.type() == UICalibrationData.BoardType.CHARUCOBOARD) { Mat objPoints = new Mat(); // 3 dimensional currentObjectPoints, the physical target ChArUco Board Mat imgPoints = @@ -295,10 +293,10 @@ private FindBoardCornersPipeResult findBoardCorners(Pair in) { // for each backend { Point[] boardCorners = - new Point[(this.params.boardHeight - 1) * (this.params.boardWidth - 1)]; + new Point[(this.params.boardHeight() - 1) * (this.params.boardWidth() - 1)]; Point3[] objectPoints = - new Point3[(this.params.boardHeight - 1) * (this.params.boardWidth - 1)]; - levels = new float[(this.params.boardHeight - 1) * (this.params.boardWidth - 1)]; + new Point3[(this.params.boardHeight() - 1) * (this.params.boardWidth() - 1)]; + levels = new float[(this.params.boardHeight() - 1) * (this.params.boardWidth() - 1)]; for (int i = 0; i < detectedIds.total(); i++) { int id = (int) detectedIds.get(i, 0)[0]; @@ -329,7 +327,7 @@ private FindBoardCornersPipeResult findBoardCorners(Pair in) { // this since we // don't need that copy. See: // https://github.com/opencv/opencv/blob/a8ec6586118c3f8e8f48549a85f2da7a5b78bcc9/modules/imgproc/src/resize.cpp#L4185 - if (params.divisor != FrameDivisor.NONE) { + if (params.divisor() != FrameDivisor.NONE) { Imgproc.resize(inFrame, smallerInFrame, getFindCornersImgSize(inFrame)); } else { smallerInFrame = inFrame; @@ -371,65 +369,15 @@ private FindBoardCornersPipeResult findBoardCorners(Pair in) { return new FindBoardCornersPipeResult(inFrame.size(), objPts, outBoardCorners, outLevels); } - public static class FindCornersPipeParams { - final int boardHeight; - final int boardWidth; - final UICalibrationData.BoardType type; - final double gridSize; - final double markerSize; - final FrameDivisor divisor; - final UICalibrationData.TagFamily tagFamily; - final boolean useOldPattern; - - public FindCornersPipeParams( - int boardHeight, - int boardWidth, - UICalibrationData.BoardType type, - UICalibrationData.TagFamily tagFamily, - double gridSize, - double markerSize, - FrameDivisor divisor, - boolean useOldPattern) { - this.boardHeight = boardHeight; - this.boardWidth = boardWidth; - this.tagFamily = tagFamily; - this.type = type; - this.gridSize = gridSize; // meter - this.markerSize = markerSize; // meter - this.divisor = divisor; - this.useOldPattern = useOldPattern; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + boardHeight; - result = prime * result + boardWidth; - result = prime * result + ((type == null) ? 0 : type.hashCode()); - long temp; - temp = Double.doubleToLongBits(gridSize); - result = prime * result + (int) (temp ^ (temp >>> 32)); - result = prime * result + ((divisor == null) ? 0 : divisor.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - FindCornersPipeParams other = (FindCornersPipeParams) obj; - if (boardHeight != other.boardHeight) return false; - if (boardWidth != other.boardWidth) return false; - if (tagFamily != other.tagFamily) return false; - if (useOldPattern != other.useOldPattern) return false; - if (type != other.type) return false; - if (Double.doubleToLongBits(gridSize) != Double.doubleToLongBits(other.gridSize)) - return false; - return divisor == other.divisor; - } - } + public static record FindCornersPipeParams( + int boardHeight, + int boardWidth, + UICalibrationData.BoardType type, + UICalibrationData.TagFamily tagFamily, + double gridSize, // meters + double markerSize, // meters + FrameDivisor divisor, + boolean useOldPattern) {} public static class FindBoardCornersPipeResult implements Releasable { public Size size; diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindCirclesPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindCirclesPipe.java index 07ec9ecd82..08277f0d25 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindCirclesPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindCirclesPipe.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipe.impl; +import edu.wpi.first.math.Pair; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Mat; import org.opencv.core.Point; import org.opencv.imgproc.Imgproc; @@ -49,12 +49,12 @@ protected List process(Pair> in) { circles.release(); List output = new ArrayList<>(); - var diag = params.diagonalLengthPx; - var minRadius = (int) (params.minRadius * diag / 100.0); - var maxRadius = (int) (params.maxRadius * diag / 100.0); + var diag = params.diagonalLengthPx(); + var minRadius = (int) (params.minRadius() * diag / 100.0); + var maxRadius = (int) (params.maxRadius() * diag / 100.0); Imgproc.HoughCircles( - in.getLeft(), + in.getFirst(), circles, // Detection method, see #HoughModes. The available methods are #HOUGH_GRADIENT and // #HOUGH_GRADIENT_ALT. @@ -65,9 +65,9 @@ protected List process(Pair> in) { unless some small very circles need to be detected. */ 1.0, - params.minDist, - params.maxCannyThresh, - Math.max(1.0, params.accuracy), + params.minDist(), + params.maxCannyThresh(), + Math.max(1.0, params.accuracy()), minRadius, maxRadius); // Great, we now found the center point of the circle, and it's radius, but we have no idea what @@ -76,7 +76,7 @@ protected List process(Pair> in) { // only match against them // This does mean that contours closer than allowableThreshold aren't matched to anything if // there's a 'better' option - var unmatchedContours = in.getRight(); + var unmatchedContours = in.getSecond(); for (int x = 0; x < circles.cols(); x++) { // Grab the current circle we are looking at double[] c = circles.get(0, x); @@ -91,8 +91,8 @@ protected List process(Pair> in) { // NOTE: This means that the centroid of the contour must be within the "allowable // threshold" // of the center of the circle - if (Math.abs(x_center - (mu.m10 / mu.m00)) <= params.allowableThreshold - && Math.abs(y_center - (mu.m01 / mu.m00)) <= params.allowableThreshold) { + if (Math.abs(x_center - (mu.m10 / mu.m00)) <= params.allowableThreshold() + && Math.abs(y_center - (mu.m01 / mu.m00)) <= params.allowableThreshold()) { // If it is, then add it to the output array output.add(new CVShape(contour, new Point(c[0], c[1]), c[2])); unmatchedContours.remove(contour); @@ -107,41 +107,29 @@ protected List process(Pair> in) { return output; } - public static class FindCirclePipeParams { - private final int allowableThreshold; - private final int minRadius; - private final int maxRadius; - private final int minDist; - private final int maxCannyThresh; - private final int accuracy; - private final double diagonalLengthPx; - - /* - * @params minDist - Minimum distance between the centers of the detected circles. - * If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed. - * - * @param maxCannyThresh -First method-specific parameter. In case of #HOUGH_GRADIENT and #HOUGH_GRADIENT_ALT, it is the higher threshold of the two passed to the Canny edge detector (the lower one is twice smaller). - * Note that #HOUGH_GRADIENT_ALT uses #Scharr algorithm to compute image derivatives, so the threshold value should normally be higher, such as 300 or normally exposed and contrasty images. - * - * - * @param allowableThreshold - When finding the corresponding contour, this is used to see how close a center should be to a contour for it to be considered THAT contour. - * Should be increased with lower resolutions and decreased with higher resolution - * */ - public FindCirclePipeParams( - int allowableThreshold, - int minRadius, - int minDist, - int maxRadius, - int maxCannyThresh, - int accuracy, - double diagonalLengthPx) { - this.allowableThreshold = allowableThreshold; - this.minRadius = minRadius; - this.maxRadius = maxRadius; - this.minDist = minDist; - this.maxCannyThresh = maxCannyThresh; - this.accuracy = accuracy; - this.diagonalLengthPx = diagonalLengthPx; - } - } + /** + * @param allowableThreshold When finding the corresponding contour, this is used to see how close + * a center should be to a contour for it to be considered THAT contour. Should be increased + * with lower resolutions and decreased with higher resolution + * @param minRadius Minimum circle radius, [0, 100] + * @param minDist Minimum distance between the centers of the detected circles. If the parameter + * is too small, multiple neighbor circles may be falsely detected in addition to a true one. + * If it is too large, some circles may be missed. + * @param maxRadius Maximum circle radius, [0, 100] + * @param maxCannyThresh First method-specific parameter. In case of #HOUGH_GRADIENT and + * #HOUGH_GRADIENT_ALT, it is the higher threshold of the two passed to the Canny edge + * detector (the lower one is twice smaller). Note that #HOUGH_GRADIENT_ALT uses #Scharr + * algorithm to compute image derivatives, so the threshold value should normally be higher, + * such as 300 or normally exposed and contrasty images. + * @param accuracy Circle accuracy, [1, 100] + * @param diagonalLengthPx The diagonal length of the image in pixels + */ + public static record FindCirclePipeParams( + int allowableThreshold, + int minRadius, + int minDist, + int maxRadius, + int maxCannyThresh, + int accuracy, + double diagonalLengthPx) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindContoursPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindContoursPipe.java index d5564d63fc..3181a637b7 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindContoursPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindContoursPipe.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import org.opencv.core.Mat; import org.opencv.core.MatOfPoint; import org.opencv.imgproc.Imgproc; @@ -40,7 +39,7 @@ protected List process(Mat in) { Imgproc.findContours( in, m_foundContours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_KCOS); - return m_foundContours.stream().map(Contour::new).collect(Collectors.toList()); + return m_foundContours.stream().map(Contour::new).toList(); } public static class FindContoursParams {} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindPolygonPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindPolygonPipe.java index 4cfc15259f..fd32a9152a 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindPolygonPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindPolygonPipe.java @@ -56,19 +56,17 @@ private CVShape getShape(Contour in) { private int getCorners(Contour contour) { var approx = contour.getApproxPolyDp( - (100 - params.accuracyPercentage) / 100.0 * Imgproc.arcLength(contour.getMat2f(), true), + (100 - params.accuracyPercentage()) + / 100.0 + * Imgproc.arcLength(contour.getMat2f(), true), true); // The height of the resultant approximation is the number of vertices return (int) approx.size().height; } - public static class FindPolygonPipeParams { - private final double accuracyPercentage; - - // Should be a value between 0-100 - public FindPolygonPipeParams(double accuracyPercentage) { - this.accuracyPercentage = accuracyPercentage; - } - } + /** + * @param accuracyPercentage Accuracy percentage, 0-100 + */ + public static record FindPolygonPipeParams(double accuracyPercentage) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GPUAcceleratedHSVPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GPUAcceleratedHSVPipe.java deleted file mode 100644 index 5b49faf641..0000000000 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GPUAcceleratedHSVPipe.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * 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 . - */ - -package org.photonvision.vision.pipe.impl; - -import static com.jogamp.opengl.GL.*; -import static com.jogamp.opengl.GL2ES2.*; - -import com.jogamp.opengl.*; -import com.jogamp.opengl.util.GLBuffers; -import com.jogamp.opengl.util.texture.Texture; -import com.jogamp.opengl.util.texture.TextureData; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import jogamp.opengl.GLOffscreenAutoDrawableImpl; -import org.opencv.core.CvType; -import org.opencv.core.Mat; -import org.photonvision.common.logging.LogGroup; -import org.photonvision.common.logging.Logger; -import org.photonvision.vision.pipe.CVPipe; - -public class GPUAcceleratedHSVPipe extends CVPipe { - private static final String k_vertexShader = - String.join( - "\n", - "#version 100", - "", - "attribute vec4 position;", - "", - "void main() {", - " gl_Position = position;", - "}"); - private static final String k_fragmentShader = - String.join( - "\n", - "#version 100", - "", - "precision highp float;", - "precision highp int;", - "", - "uniform vec3 lowerThresh;", - "uniform vec3 upperThresh;", - "uniform vec2 resolution;", - "uniform sampler2D texture0;", - "", - "vec3 rgb2hsv(vec3 c) {", - " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);", - " vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));", - " vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));", - "", - " float d = q.x - min(q.w, q.y);", - " float e = 1.0e-10;", - " return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);", - "}", - "", - "bool inRange(vec3 hsv) {", - " bvec3 botBool = greaterThanEqual(hsv, lowerThresh);", - " bvec3 topBool = lessThanEqual(hsv, upperThresh);", - " return all(botBool) && all(topBool);", - "}", - "", - "void main() {", - " vec2 uv = gl_FragCoord.xy/resolution;", - // Important! We do this .bgr swizzle because the image comes in as BGR, but we pretend - // it's RGB for convenience+speed - " vec3 col = texture2D(texture0, uv).bgr;", - // Only the first value in the vec4 gets used for GL_RED, and only the last value gets - // used for GL_ALPHA - " gl_FragColor = inRange(rgb2hsv(col)) ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(0.0, 0.0, 0.0, 0.0);", - "}"); - private static final int k_startingWidth = 1280, k_startingHeight = 720; - private static final float[] k_vertexPositions = { - // Set up a quad that covers the screen - -1f, +1f, +1f, +1f, -1f, -1f, +1f, -1f - }; - private static final int k_positionVertexAttribute = - 0; // ID for the vertex shader position variable - - public enum PBOMode { - NONE, - SINGLE_BUFFERED, - DOUBLE_BUFFERED - } - - private final IntBuffer vertexVBOIds = GLBuffers.newDirectIntBuffer(1), - unpackPBOIds = GLBuffers.newDirectIntBuffer(2), - packPBOIds = GLBuffers.newDirectIntBuffer(2); - - private final GL2ES2 gl; - private final GLProfile profile; - private final int outputFormat; - private final PBOMode pboMode; - private final GLOffscreenAutoDrawableImpl.FBOImpl drawable; - private final Texture texture; - // The texture uniform holds the image that's being processed - // The resolution uniform holds the current image resolution - // The lower and upper uniforms hold the lower and upper HSV limits for thresholding - private final int textureUniformId, resolutionUniformId, lowerUniformId, upperUniformId; - - private final Logger logger = new Logger(GPUAcceleratedHSVPipe.class, LogGroup.General); - - private byte[] inputBytes, outputBytes; - private Mat outputMat = new Mat(k_startingHeight, k_startingWidth, CvType.CV_8UC1); - private int previousWidth = -1, previousHeight = -1; - private int unpackIndex = 0, unpackNextIndex = 0, packIndex = 0, packNextIndex = 0; - - public GPUAcceleratedHSVPipe(PBOMode pboMode) { - this.pboMode = pboMode; - - // Set up GL profile and ask for specific capabilities - profile = GLProfile.get(pboMode == PBOMode.NONE ? GLProfile.GLES2 : GLProfile.GL4ES3); - final var capabilities = new GLCapabilities(profile); - capabilities.setHardwareAccelerated(true); - capabilities.setFBO(true); - capabilities.setDoubleBuffered(false); - capabilities.setOnscreen(false); - capabilities.setRedBits(8); - capabilities.setBlueBits(0); - capabilities.setGreenBits(0); - capabilities.setAlphaBits(0); - - // Set up the offscreen area we're going to draw to - final var factory = GLDrawableFactory.getFactory(profile); - drawable = - (GLOffscreenAutoDrawableImpl.FBOImpl) - factory.createOffscreenAutoDrawable( - factory.getDefaultDevice(), - capabilities, - new DefaultGLCapabilitiesChooser(), - k_startingWidth, - k_startingHeight); - drawable.display(); - drawable.getContext().makeCurrent(); - - // Get an OpenGL context; OpenGL ES 2.0 and OpenGL 2.0 are compatible with all the coprocs we - // care about but not compatible with PBOs. Open GL ES 3.0 and OpenGL 4.0 are compatible with - // select coprocs *and* PBOs - gl = pboMode == PBOMode.NONE ? drawable.getGL().getGLES2() : drawable.getGL().getGL4ES3(); - final int programId = gl.glCreateProgram(); - - if (pboMode == PBOMode.NONE && !gl.glGetString(GL_EXTENSIONS).contains("GL_EXT_texture_rg")) { - logger.warn( - "OpenGL ES 2.0 implementation does not have the 'GL_EXT_texture_rg' extension, falling back to GL_ALPHA instead of GL_RED output format"); - outputFormat = GL_ALPHA; - } else { - outputFormat = GL_RED; - } - - // JOGL creates a framebuffer color attachment that has RGB set as the format, which is not - // appropriate for us because we want a single-channel format - // We make ourown FBO color attachment to remedy this - // Detach and destroy the FBO color attachment that JOGL made for us - drawable.getFBObject(GL_FRONT).detachColorbuffer(gl, 0, true); - // Equivalent to calling glBindFramebuffer - drawable.getFBObject(GL_FRONT).bind(gl); - if (true) { // For now renderbuffers are disabled - // Create a color attachment texture to hold our rendered output - var colorBufferIds = GLBuffers.newDirectIntBuffer(1); - gl.glGenTextures(1, colorBufferIds); - gl.glBindTexture(GL_TEXTURE_2D, colorBufferIds.get(0)); - gl.glTexImage2D( - GL_TEXTURE_2D, - 0, - outputFormat == GL_RED ? GL_R8 : GL_ALPHA8, - k_startingWidth, - k_startingHeight, - 0, - outputFormat, - GL_UNSIGNED_BYTE, - null); - gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Attach the texture to the framebuffer - gl.glBindTexture(GL_TEXTURE_2D, 0); - gl.glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferIds.get(0), 0); - // Cleanup - gl.glBindTexture(GL_TEXTURE_2D, 0); - } else { - // Create a color attachment texture to hold our rendered output - var renderBufferIds = GLBuffers.newDirectIntBuffer(1); - gl.glGenRenderbuffers(1, renderBufferIds); - gl.glBindRenderbuffer(GL_RENDERBUFFER, renderBufferIds.get(0)); - gl.glRenderbufferStorage( - GL_RENDERBUFFER, - outputFormat == GL_RED ? GL_R8 : GL_ALPHA8, - k_startingWidth, - k_startingHeight); - // Attach the texture to the framebuffer - gl.glFramebufferRenderbuffer( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBufferIds.get(0)); - // Cleanup - gl.glBindRenderbuffer(GL_RENDERBUFFER, 0); - } - drawable.getFBObject(GL_FRONT).unbind(gl); - - // Check that the FBO is attached - int fboStatus = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (fboStatus == GL_FRAMEBUFFER_UNSUPPORTED) { - throw new RuntimeException( - "GL implementation does not support rendering to internal format '" - + String.format("0x%08X", outputFormat == GL_RED ? GL_R8 : GL_ALPHA8) - + "' with type '" - + String.format("0x%08X", GL_UNSIGNED_BYTE) - + "'"); - } else if (fboStatus != GL_FRAMEBUFFER_COMPLETE) { - throw new RuntimeException( - "Framebuffer is not complete; framebuffer status is " - + String.format("0x%08X", fboStatus)); - } - - logger.debug( - "Created an OpenGL context with renderer '" - + gl.glGetString(GL_RENDERER) - + "', version '" - + gl.glGetString(GL.GL_VERSION) - + "', and profile '" - + profile - + "'"); - - var fmt = GLBuffers.newDirectIntBuffer(1); - gl.glGetIntegerv(GLES3.GL_IMPLEMENTATION_COLOR_READ_FORMAT, fmt); - var type = GLBuffers.newDirectIntBuffer(1); - gl.glGetIntegerv(GLES3.GL_IMPLEMENTATION_COLOR_READ_TYPE, type); - - // Tell OpenGL that the attribute in the vertex shader named position is bound to index 0 (the - // index for the generic position input) - gl.glBindAttribLocation(programId, 0, "position"); - - // Compile and set up our two shaders with our program - final int vertexId = createShader(gl, programId, k_vertexShader, GL_VERTEX_SHADER); - final int fragmentId = createShader(gl, programId, k_fragmentShader, GL_FRAGMENT_SHADER); - - // Link our program together and check for errors - gl.glLinkProgram(programId); - IntBuffer status = GLBuffers.newDirectIntBuffer(1); - gl.glGetProgramiv(programId, GL_LINK_STATUS, status); - if (status.get(0) == GL_FALSE) { - IntBuffer infoLogLength = GLBuffers.newDirectIntBuffer(1); - gl.glGetProgramiv(programId, GL_INFO_LOG_LENGTH, infoLogLength); - - ByteBuffer bufferInfoLog = GLBuffers.newDirectByteBuffer(infoLogLength.get(0)); - gl.glGetProgramInfoLog(programId, infoLogLength.get(0), null, bufferInfoLog); - byte[] bytes = new byte[infoLogLength.get(0)]; - bufferInfoLog.get(bytes); - String strInfoLog = new String(bytes); - - throw new RuntimeException("Linker failure: " + strInfoLog); - } - gl.glValidateProgram(programId); - - // Cleanup shaders that are now compiled in - gl.glDetachShader(programId, vertexId); - gl.glDetachShader(programId, fragmentId); - gl.glDeleteShader(vertexId); - gl.glDeleteShader(fragmentId); - - // Tell OpenGL to use our program - gl.glUseProgram(programId); - - // Set up our texture - texture = new Texture(GL_TEXTURE_2D); - texture.setTexParameteri(gl, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - texture.setTexParameteri(gl, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - texture.setTexParameteri(gl, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - texture.setTexParameteri(gl, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Set up a uniform holding our image as a texture - textureUniformId = gl.glGetUniformLocation(programId, "texture0"); - gl.glUniform1i(textureUniformId, 0); - - // Set up a uniform to hold image resolution - resolutionUniformId = gl.glGetUniformLocation(programId, "resolution"); - - // Set up uniforms for the HSV thresholds - lowerUniformId = gl.glGetUniformLocation(programId, "lowerThresh"); - upperUniformId = gl.glGetUniformLocation(programId, "upperThresh"); - - // Set up a quad that covers the entire screen so that our fragment shader draws onto the entire - // screen - gl.glGenBuffers(1, vertexVBOIds); - - FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(k_vertexPositions); - gl.glBindBuffer(GL_ARRAY_BUFFER, vertexVBOIds.get(0)); - gl.glBufferData( - GL_ARRAY_BUFFER, - (long) vertexBuffer.capacity() * Float.BYTES, - vertexBuffer, - GL_STATIC_DRAW); - - // Set up pixel unpack buffer (a PBO to transfer image data to the GPU) - if (pboMode != PBOMode.NONE) { - gl.glGenBuffers(2, unpackPBOIds); - - gl.glBindBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER, unpackPBOIds.get(0)); - gl.glBufferData( - GLES3.GL_PIXEL_UNPACK_BUFFER, - k_startingHeight * k_startingWidth * 3, - null, - GLES3.GL_STREAM_DRAW); - if (pboMode == PBOMode.DOUBLE_BUFFERED) { - gl.glBindBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER, unpackPBOIds.get(1)); - gl.glBufferData( - GLES3.GL_PIXEL_UNPACK_BUFFER, - k_startingHeight * k_startingWidth * 3, - null, - GLES3.GL_STREAM_DRAW); - } - gl.glBindBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER, 0); - } - - // Set up pixel pack buffer (a PBO to transfer the processed image back from the GPU) - if (pboMode != PBOMode.NONE) { - gl.glGenBuffers(2, packPBOIds); - - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(0)); - gl.glBufferData( - GLES3.GL_PIXEL_PACK_BUFFER, - k_startingHeight * k_startingWidth, - null, - GLES3.GL_STREAM_READ); - if (pboMode == PBOMode.DOUBLE_BUFFERED) { - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(1)); - gl.glBufferData( - GLES3.GL_PIXEL_PACK_BUFFER, - k_startingHeight * k_startingWidth, - null, - GLES3.GL_STREAM_READ); - } - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, 0); - } - } - - private static int createShader(GL2ES2 gl, int programId, String glslCode, int shaderType) { - int shaderId = gl.glCreateShader(shaderType); - if (shaderId == 0) throw new RuntimeException("Shader ID is zero"); - - IntBuffer length = GLBuffers.newDirectIntBuffer(new int[] {glslCode.length()}); - gl.glShaderSource(shaderId, 1, new String[] {glslCode}, length); - gl.glCompileShader(shaderId); - - IntBuffer intBuffer = IntBuffer.allocate(1); - gl.glGetShaderiv(shaderId, GL_COMPILE_STATUS, intBuffer); - - if (intBuffer.get(0) != 1) { - gl.glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, intBuffer); - int size = intBuffer.get(0); - if (size > 0) { - ByteBuffer byteBuffer = ByteBuffer.allocate(size); - gl.glGetShaderInfoLog(shaderId, size, intBuffer, byteBuffer); - System.err.println(new String(byteBuffer.array())); - } - throw new RuntimeException("Couldn't compile shader"); - } - - gl.glAttachShader(programId, shaderId); - - return shaderId; - } - - @Override - protected Mat process(Mat in) { - if (in.width() != previousWidth && in.height() != previousHeight) { - logger.debug("Resizing OpenGL viewport, byte buffers, and PBOs"); - - drawable.setSurfaceSize(in.width(), in.height()); - gl.glViewport(0, 0, in.width(), in.height()); - - previousWidth = in.width(); - previousHeight = in.height(); - - inputBytes = new byte[in.width() * in.height() * 3]; - - outputBytes = new byte[in.width() * in.height()]; - outputMat = new Mat(k_startingHeight, k_startingWidth, CvType.CV_8UC1); - - if (pboMode != PBOMode.NONE) { - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(0)); - gl.glBufferData( - GLES3.GL_PIXEL_PACK_BUFFER, - (long) in.width() * in.height(), - null, - GLES3.GL_STREAM_READ); - - if (pboMode == PBOMode.DOUBLE_BUFFERED) { - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(1)); - gl.glBufferData( - GLES3.GL_PIXEL_PACK_BUFFER, - (long) in.width() * in.height(), - null, - GLES3.GL_STREAM_READ); - } - } - } - - if (pboMode == PBOMode.DOUBLE_BUFFERED) { - unpackIndex = (unpackIndex + 1) % 2; - unpackNextIndex = (unpackIndex + 1) % 2; - } - - // Reset the fullscreen quad - gl.glBindBuffer(GL_ARRAY_BUFFER, vertexVBOIds.get(0)); - gl.glEnableVertexAttribArray(k_positionVertexAttribute); - gl.glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0); - gl.glBindBuffer(GL_ARRAY_BUFFER, 0); - - // Load and bind our image as a 2D texture - gl.glActiveTexture(GL_TEXTURE0); - texture.enable(gl); - texture.bind(gl); - - // Load our image into the texture - in.get(0, 0, inputBytes); - if (pboMode == PBOMode.NONE) { - ByteBuffer buf = ByteBuffer.wrap(inputBytes); - // (We're actually taking in BGR even though this says RGB; it's much easier and faster to - // switch it around in the fragment shader) - texture.updateImage( - gl, - new TextureData( - profile, - GL_RGB8, - in.width(), - in.height(), - 0, - GL_RGB, - GL_UNSIGNED_BYTE, - false, - false, - false, - buf, - null)); - } else { - // Bind the PBO to the texture - gl.glBindBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER, unpackPBOIds.get(unpackIndex)); - - // Copy pixels from the PBO to the texture object - gl.glTexSubImage2D( - GLES3.GL_TEXTURE_2D, - 0, - 0, - 0, - in.width(), - in.height(), - GLES3.GL_RGB8, - GLES3.GL_UNSIGNED_BYTE, - 0); - - // Bind (potentially) another PBO to update the texture source - gl.glBindBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER, unpackPBOIds.get(unpackNextIndex)); - - // This call with a nullptr for the data arg tells OpenGL *not* to wait to be in sync with the - // GPU - // This causes the previous data in the PBO to be discarded - gl.glBufferData( - GLES3.GL_PIXEL_UNPACK_BUFFER, - (long) in.width() * in.height() * 3, - null, - GLES3.GL_STREAM_DRAW); - - // Map the buffer of GPU memory into a place that's accessible by us - var buf = - gl.glMapBufferRange( - GLES3.GL_PIXEL_UNPACK_BUFFER, - 0, - (long) in.width() * in.height() * 3, - GLES3.GL_MAP_WRITE_BIT); - buf.put(inputBytes); - - gl.glUnmapBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER); - gl.glBindBuffer(GLES3.GL_PIXEL_UNPACK_BUFFER, 0); - } - - // Put values in a uniform holding the image resolution - gl.glUniform2f(resolutionUniformId, in.width(), in.height()); - - // Put values in threshold uniforms - var lowr = params.getHsvLower().val; - var upr = params.getHsvUpper().val; - gl.glUniform3f(lowerUniformId, (float) lowr[0], (float) lowr[1], (float) lowr[2]); - gl.glUniform3f(upperUniformId, (float) upr[0], (float) upr[1], (float) upr[2]); - - // Draw the fullscreen quad - gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, k_vertexPositions.length); - - // Cleanup - texture.disable(gl); - gl.glDisableVertexAttribArray(k_positionVertexAttribute); - gl.glUseProgram(0); - - if (pboMode == PBOMode.NONE) { - return saveMatNoPBO(gl, in.width(), in.height()); - } else { - return saveMatPBO((GLES3) gl, in.width(), in.height(), pboMode == PBOMode.DOUBLE_BUFFERED); - } - } - - private Mat saveMatNoPBO(GL2ES2 gl, int width, int height) { - ByteBuffer buffer = GLBuffers.newDirectByteBuffer(width * height); - // We use GL_RED/GL_ALPHA to get things in a single-channel format - // Note that which pixel format you use is *very* important to performance - // E.g. GL_ALPHA is super slow in this case - gl.glReadPixels(0, 0, width, height, outputFormat, GL_UNSIGNED_BYTE, buffer); - - return new Mat(height, width, CvType.CV_8UC1, buffer); - } - - private Mat saveMatPBO(GLES3 gl, int width, int height, boolean doubleBuffered) { - if (doubleBuffered) { - packIndex = (packIndex + 1) % 2; - packNextIndex = (packIndex + 1) % 2; - } - - // Set the target framebuffer attachment to read - gl.glReadBuffer(GLES3.GL_COLOR_ATTACHMENT0); - - // Read pixels from the framebuffer to the PBO - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(packIndex)); - // We use GL_RED (which is always supported in GLES3) to get things in a single-channel format - // Note that which pixel format you use is *very* important to performance - // E.g. GL_ALPHA is super slow in this case - gl.glReadPixels(0, 0, width, height, GLES3.GL_RED, GLES3.GL_UNSIGNED_BYTE, 0); - - // Map the PBO into the CPU's memory - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(packNextIndex)); - var buf = - gl.glMapBufferRange( - GLES3.GL_PIXEL_PACK_BUFFER, 0, (long) width * height, GLES3.GL_MAP_READ_BIT); - buf.get(outputBytes); - outputMat.put(0, 0, outputBytes); - gl.glUnmapBuffer(GLES3.GL_PIXEL_PACK_BUFFER); - gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, 0); - - return outputMat; - } -} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GrayscalePipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GrayscalePipe.java index 04b1bf774a..97b95b1955 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GrayscalePipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GrayscalePipe.java @@ -32,7 +32,5 @@ protected Mat process(Mat in) { return outputMat; } - public static class GrayscaleParams { - public GrayscaleParams() {} - } + public static class GrayscaleParams {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GroupContoursPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GroupContoursPipe.java index 7711467dd2..184215beb9 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GroupContoursPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GroupContoursPipe.java @@ -38,14 +38,14 @@ protected List process(List input) { m_targets.clear(); - if (params.getGroup() == ContourGroupingMode.Single) { + if (params.group() == ContourGroupingMode.Single) { for (var contour : input) { m_targets.add(new PotentialTarget(contour)); } } // Check if we have at least 2 targets for 2 or more // This will only ever return 1 contour! - else if (params.getGroup() == ContourGroupingMode.TwoOrMore + else if (params.group() == ContourGroupingMode.TwoOrMore && input.size() >= ContourGroupingMode.TwoOrMore.count) { // Just blob everything together Contour groupedContour = Contour.combineContourList(input); @@ -53,7 +53,7 @@ else if (params.getGroup() == ContourGroupingMode.TwoOrMore m_targets.add(new PotentialTarget(groupedContour, input)); } } else { - int groupingCount = params.getGroup().count; + int groupingCount = params.group().count; if (input.size() >= groupingCount) { input.sort(Contour.SortByMomentsX); @@ -73,7 +73,7 @@ else if (params.getGroup() == ContourGroupingMode.TwoOrMore // FYI: This method only takes 2 contours! Contour groupedContour = Contour.groupContoursByIntersection( - groupingSet.get(0), groupingSet.get(1), params.getIntersection()); + groupingSet.get(0), groupingSet.get(1), params.intersection()); if (groupedContour != null) { m_targets.add(new PotentialTarget(groupedContour, groupingSet)); @@ -88,22 +88,6 @@ else if (params.getGroup() == ContourGroupingMode.TwoOrMore return m_targets; } - public static class GroupContoursParams { - private final ContourGroupingMode m_group; - private final ContourIntersectionDirection m_intersection; - - public GroupContoursParams( - ContourGroupingMode group, ContourIntersectionDirection intersectionDirection) { - m_group = group; - m_intersection = intersectionDirection; - } - - public ContourGroupingMode getGroup() { - return m_group; - } - - public ContourIntersectionDirection getIntersection() { - return m_intersection; - } - } + public static record GroupContoursParams( + ContourGroupingMode group, ContourIntersectionDirection intersection) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java index e0ba36ce0e..e58a20f89b 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java @@ -32,24 +32,24 @@ protected Mat process(Mat in) { // rather than copying. Free performance! Imgproc.cvtColor(in, outputMat, Imgproc.COLOR_BGR2HSV, 3); - if (params.getHueInverted()) { + if (params.hueInverted()) { // In Java code we do this by taking an image thresholded // from [0, minHue] and ORing it with [maxHue, 180] // we want hue from the end of the slider to max hue - Scalar firstLower = params.getHsvLower().clone(); - Scalar firstUpper = params.getHsvUpper().clone(); - firstLower.val[0] = params.getHsvUpper().val[0]; + Scalar firstLower = params.hsvLower().clone(); + Scalar firstUpper = params.hsvUpper().clone(); + firstLower.val[0] = params.hsvUpper().val[0]; firstUpper.val[0] = 180; var lowerThresholdMat = new Mat(); Core.inRange(outputMat, firstLower, firstUpper, lowerThresholdMat); // We want hue from 0 to the start of the slider - var secondLower = params.getHsvLower().clone(); - var secondUpper = params.getHsvUpper().clone(); + var secondLower = params.hsvLower().clone(); + var secondUpper = params.hsvUpper().clone(); secondLower.val[0] = 0; - secondUpper.val[0] = params.getHsvLower().val[0]; + secondUpper.val[0] = params.hsvLower().val[0]; // Now that the output mat's been used by the first inRange, it's fine to mutate it Core.inRange(outputMat, secondLower, secondUpper, outputMat); @@ -60,35 +60,19 @@ protected Mat process(Mat in) { lowerThresholdMat.release(); } else { - Core.inRange(outputMat, params.getHsvLower(), params.getHsvUpper(), outputMat); + Core.inRange(outputMat, params.hsvLower(), params.hsvUpper(), outputMat); } return outputMat; } - public static class HSVParams { - private final Scalar m_hsvLower; - private final Scalar m_hsvUpper; - private final boolean m_hueInverted; - + public static record HSVParams(Scalar hsvLower, Scalar hsvUpper, boolean hueInverted) { public HSVParams( IntegerCouple hue, IntegerCouple saturation, IntegerCouple value, boolean hueInverted) { - m_hsvLower = new Scalar(hue.getFirst(), saturation.getFirst(), value.getFirst()); - m_hsvUpper = new Scalar(hue.getSecond(), saturation.getSecond(), value.getSecond()); - - this.m_hueInverted = hueInverted; - } - - public Scalar getHsvLower() { - return m_hsvLower; - } - - public Scalar getHsvUpper() { - return m_hsvUpper; - } - - public boolean getHueInverted() { - return m_hueInverted; + this( + new Scalar(hue.getFirst(), saturation.getFirst(), value.getFirst()), + new Scalar(hue.getSecond(), saturation.getSecond(), value.getSecond()), + hueInverted); } } } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/MultiTargetPNPPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/MultiTargetPNPPipe.java index d0c338db1e..b795da581f 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/MultiTargetPNPPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/MultiTargetPNPPipe.java @@ -43,9 +43,9 @@ public class MultiTargetPNPPipe @Override protected Optional process(List targetList) { if (params == null - || params.cameraCoefficients == null - || params.cameraCoefficients.getCameraIntrinsicsMat() == null - || params.cameraCoefficients.getDistCoeffsMat() == null) { + || params.cameraCoefficients() == null + || params.cameraCoefficients().getCameraIntrinsicsMat() == null + || params.cameraCoefficients().getDistCoeffsMat() == null) { if (!hasWarned) { logger.warn( "Cannot perform solvePNP an uncalibrated camera! Please calibrate this resolution..."); @@ -62,7 +62,7 @@ private Optional calculateCameraInField(List(); for (var target : targetList) { int id = target.getFiducialId(); - if (params.atfl.getTagPose(id).isPresent()) tagIDsUsed.add((short) id); + if (params.atfl().getTagPose(id).isPresent()) tagIDsUsed.add((short) id); } // Only run with multiple targets @@ -72,11 +72,11 @@ private Optional calculateCameraInField(List calculateCameraInField(List process(CVMat in) { // Check if the model has changed - if (detector.getModel() != params.model) { + if (detector.getModel() != params.model()) { detector.release(); - detector = params.model.load(); + detector = params.model().load(); } Mat frame = in.getMat(); @@ -52,17 +52,10 @@ protected List process(CVMat in) { return List.of(); } - return detector.detect(in.getMat(), params.nms, params.confidence); + return detector.detect(in.getMat(), params.nms(), params.confidence()); } - public static class ObjectDetectionPipeParams { - public double confidence; - public double nms; - public int max_detections; - public Model model; - - public ObjectDetectionPipeParams() {} - } + public static record ObjectDetectionPipeParams(double confidence, double nms, Model model) {} public List getClassNames() { return detector.getClasses(); diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ResizeImagePipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ResizeImagePipe.java index 3d9c030434..7a65b27099 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ResizeImagePipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ResizeImagePipe.java @@ -32,22 +32,12 @@ public class ResizeImagePipe extends MutatingPipe process(List targetList) { - if (params.cameraCoefficients == null - || params.cameraCoefficients.getCameraIntrinsicsMat() == null - || params.cameraCoefficients.getDistCoeffsMat() == null) { + if (params.cameraCoefficients() == null + || params.cameraCoefficients().getCameraIntrinsicsMat() == null + || params.cameraCoefficients().getDistCoeffsMat() == null) { if (!hasWarned) { logger.warn( "Cannot perform solvePNP an uncalibrated camera! Please calibrate this resolution..."); @@ -65,9 +65,9 @@ private void calculateTargetPose(TrackedTarget target) { var corners = target.getTargetCorners(); if (corners == null || corners.isEmpty() - || params.cameraCoefficients == null - || params.cameraCoefficients.getCameraIntrinsicsMat() == null - || params.cameraCoefficients.getDistCoeffsMat() == null) { + || params.cameraCoefficients() == null + || params.cameraCoefficients().getCameraIntrinsicsMat() == null + || params.cameraCoefficients().getDistCoeffsMat() == null) { return; } this.imagePoints.fromList(corners); @@ -76,10 +76,10 @@ private void calculateTargetPose(TrackedTarget target) { var tVec = new Mat(); try { Calib3d.solvePnP( - params.targetModel.getRealWorldTargetCoordinates(), + params.targetModel().getRealWorldTargetCoordinates(), imagePoints, - params.cameraCoefficients.getCameraIntrinsicsMat(), - params.cameraCoefficients.getDistCoeffsMat(), + params.cameraCoefficients().getCameraIntrinsicsMat(), + params.cameraCoefficients().getDistCoeffsMat(), rVec, tVec); } catch (Exception e) { @@ -103,14 +103,6 @@ private void calculateTargetPose(TrackedTarget target) { target.setAltCameraToTarget3d(new Transform3d()); } - public static class SolvePNPPipeParams { - private final CameraCalibrationCoefficients cameraCoefficients; - private final TargetModel targetModel; - - public SolvePNPPipeParams( - CameraCalibrationCoefficients cameraCoefficients, TargetModel targetModel) { - this.cameraCoefficients = cameraCoefficients; - this.targetModel = targetModel; - } - } + public static record SolvePNPPipeParams( + CameraCalibrationCoefficients cameraCoefficients, TargetModel targetModel) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SortContoursPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SortContoursPipe.java index b084c75c41..8be3116bdc 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SortContoursPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SortContoursPipe.java @@ -39,46 +39,23 @@ protected List process(List in) { if (!in.isEmpty()) { m_sortedContours.addAll(in); - if (params.getSortMode() != ContourSortMode.Centermost) { - m_sortedContours.sort(params.getSortMode().getComparator()); + if (params.sortMode() != ContourSortMode.Centermost) { + m_sortedContours.sort(params.sortMode().getComparator()); } else { // we need knowledge of camera properties to calculate this distance -- do it ourselves m_sortedContours.sort(Comparator.comparingDouble(this::calcSquareCenterDistance)); } } - return new ArrayList<>( - m_sortedContours.subList(0, Math.min(in.size(), params.getMaxTargets()))); + return new ArrayList<>(m_sortedContours.subList(0, Math.min(in.size(), params.maxTargets()))); } private double calcSquareCenterDistance(PotentialTarget tgt) { - return Math.sqrt( - Math.pow(params.getCamProperties().centerX - tgt.getMinAreaRect().center.x, 2) - + Math.pow(params.getCamProperties().centerY - tgt.getMinAreaRect().center.y, 2)); + return Math.hypot( + params.frameStaticProperties().centerX - tgt.getMinAreaRect().center.x, + params.frameStaticProperties().centerY - tgt.getMinAreaRect().center.y); } - public static class SortContoursParams { - private final ContourSortMode m_sortMode; - private final int m_maxTargets; - private final FrameStaticProperties m_frameStaticProperties; - - public SortContoursParams( - ContourSortMode sortMode, int maxTargets, FrameStaticProperties camProperties) { - m_sortMode = sortMode; - m_maxTargets = maxTargets; - m_frameStaticProperties = camProperties; - } - - public ContourSortMode getSortMode() { - return m_sortMode; - } - - public FrameStaticProperties getCamProperties() { - return m_frameStaticProperties; - } - - public int getMaxTargets() { - return m_maxTargets; - } - } + public static record SortContoursParams( + ContourSortMode sortMode, int maxTargets, FrameStaticProperties frameStaticProperties) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SpeckleRejectPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SpeckleRejectPipe.java index 4f4c5ce547..8f0a79cd61 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SpeckleRejectPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/SpeckleRejectPipe.java @@ -40,7 +40,7 @@ protected List process(List in) { } averageArea /= in.size(); - double minAllowedArea = params.getMinPercentOfAvg() / 100.0 * averageArea; + double minAllowedArea = params.minPercentOfAvg() / 100.0 * averageArea; for (Contour c : in) { if (c.getArea() >= minAllowedArea) { m_despeckledContours.add(c); @@ -53,15 +53,5 @@ protected List process(List in) { return m_despeckledContours; } - public static class SpeckleRejectParams { - private final double m_minPercentOfAvg; - - public SpeckleRejectParams(double minPercentOfAvg) { - m_minPercentOfAvg = minPercentOfAvg; - } - - public double getMinPercentOfAvg() { - return m_minPercentOfAvg; - } - } + public static record SpeckleRejectParams(double minPercentOfAvg) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/AprilTagPipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/AprilTagPipeline.java index 5cc9cc98f7..3e98f7e9e1 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/AprilTagPipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/AprilTagPipeline.java @@ -38,7 +38,7 @@ import org.photonvision.vision.frame.FrameThresholdType; import org.photonvision.vision.pipe.CVPipe.CVPipeResult; import org.photonvision.vision.pipe.impl.AprilTagDetectionPipe; -import org.photonvision.vision.pipe.impl.AprilTagDetectionPipeParams; +import org.photonvision.vision.pipe.impl.AprilTagDetectionPipe.AprilTagDetectionPipeParams; import org.photonvision.vision.pipe.impl.AprilTagPoseEstimatorPipe; import org.photonvision.vision.pipe.impl.AprilTagPoseEstimatorPipe.AprilTagPoseEstimatorPipeParams; import org.photonvision.vision.pipe.impl.CalculateFPSPipe; @@ -134,8 +134,8 @@ protected CVPipelineResult process(Frame frame, AprilTagPipelineSettings setting return new CVPipelineResult(frame.sequenceID, 0, 0, List.of(), frame); } - CVPipeResult> tagDetectionPipeResult; - tagDetectionPipeResult = aprilTagDetectionPipe.run(frame.processedImage); + CVPipeResult> tagDetectionPipeResult = + aprilTagDetectionPipe.run(frame.processedImage); sumPipeNanosElapsed += tagDetectionPipeResult.nanosElapsed; List detections = tagDetectionPipeResult.output; diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/ArucoPipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/ArucoPipeline.java index 8395054a13..b0a4505a6d 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/ArucoPipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/ArucoPipeline.java @@ -145,8 +145,8 @@ protected CVPipelineResult process(Frame frame, ArucoPipelineSettings settings) return new CVPipelineResult(frame.sequenceID, 0, 0, List.of(), frame); } - CVPipeResult> tagDetectionPipeResult; - tagDetectionPipeResult = arucoDetectionPipe.run(frame.processedImage); + CVPipeResult> tagDetectionPipeResult = + arucoDetectionPipe.run(frame.processedImage); sumPipeNanosElapsed += tagDetectionPipeResult.nanosElapsed; // If we want to debug the thresholding steps, draw the first step to the color image @@ -163,14 +163,13 @@ protected CVPipelineResult process(Frame frame, ArucoPipelineSettings settings) // Populate target list for multitag // (TODO: Address circular dependencies. Multitag only requires corners and IDs, this should // not be necessary.) - TrackedTarget target = + + targetList.add( new TrackedTarget( detection, null, new TargetCalculationParameters( - false, null, null, null, null, frameStaticProperties)); - - targetList.add(target); + false, null, null, null, null, frameStaticProperties))); } // Do multi-tag pose estimation diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java index ec4f1e609c..d0a006254d 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java @@ -17,12 +17,11 @@ package org.photonvision.vision.pipeline; +import edu.wpi.first.math.Pair; import edu.wpi.first.math.util.Units; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Mat; import org.opencv.core.Point; import org.photonvision.common.dataflow.DataChangeService; @@ -83,7 +82,7 @@ public Calibrate3dPipeline(int minSnapshots) { @Override protected void setPipeParamsImpl() { - FindBoardCornersPipe.FindCornersPipeParams findCornersPipeParams = + findBoardCornersPipe.setParams( new FindBoardCornersPipe.FindCornersPipeParams( settings.boardHeight, settings.boardWidth, @@ -92,13 +91,11 @@ protected void setPipeParamsImpl() { settings.gridSize, settings.markerSize, settings.streamingFrameDivisor, - settings.useOldPattern); - findBoardCornersPipe.setParams(findCornersPipeParams); + settings.useOldPattern)); - Calibrate3dPipe.CalibratePipeParams calibratePipeParams = + calibrate3dPipe.setParams( new Calibrate3dPipe.CalibratePipeParams( - settings.boardHeight, settings.boardWidth, settings.gridSize, settings.useMrCal); - calibrate3dPipe.setParams(calibratePipeParams); + settings.boardHeight, settings.boardWidth, settings.gridSize, settings.useMrCal)); } @Override @@ -125,9 +122,7 @@ protected CVPipelineResult process(Frame frame, Calibration3dPipelineSettings se var outputColorCVMat = new CVMat(); inputColorMat.copyTo(outputColorCVMat.getMat()); - FindBoardCornersPipeResult findBoardResult; - - findBoardResult = + FindBoardCornersPipeResult findBoardResult = findBoardCornersPipe.run(Pair.of(inputColorMat, outputColorCVMat.getMat())).output; if (takeSnapshot) { @@ -166,9 +161,7 @@ protected CVPipelineResult process(Frame frame, Calibration3dPipelineSettings se } List> getCornersList() { - return foundCornersList.stream() - .map(it -> it.imagePoints.toList()) - .collect(Collectors.toList()); + return foundCornersList.stream().map(it -> it.imagePoints.toList()).toList(); } public boolean hasEnough() { diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java index cefcddce1e..0174c8bcb7 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java @@ -17,10 +17,9 @@ package org.photonvision.vision.pipeline; +import edu.wpi.first.math.Pair; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Point; import org.photonvision.vision.frame.Frame; import org.photonvision.vision.frame.FrameThresholdType; @@ -73,19 +72,15 @@ protected void setPipeParamsImpl() { settings.offsetDualPointB, settings.offsetDualPointBArea); - SpeckleRejectPipe.SpeckleRejectParams speckleRejectParams = - new SpeckleRejectPipe.SpeckleRejectParams(settings.contourSpecklePercentage); - speckleRejectPipe.setParams(speckleRejectParams); + speckleRejectPipe.setParams( + new SpeckleRejectPipe.SpeckleRejectParams(settings.contourSpecklePercentage)); - FindContoursPipe.FindContoursParams findContoursParams = - new FindContoursPipe.FindContoursParams(); - findContoursPipe.setParams(findContoursParams); + findContoursPipe.setParams(new FindContoursPipe.FindContoursParams()); - FindPolygonPipe.FindPolygonPipeParams findPolygonPipeParams = - new FindPolygonPipe.FindPolygonPipeParams(settings.accuracyPercentage); - findPolygonPipe.setParams(findPolygonPipeParams); + findPolygonPipe.setParams( + new FindPolygonPipe.FindPolygonPipeParams(settings.accuracyPercentage)); - FindCirclesPipe.FindCirclePipeParams findCirclePipeParams = + findCirclesPipe.setParams( new FindCirclesPipe.FindCirclePipeParams( settings.circleDetectThreshold, settings.contourRadius.getFirst(), @@ -93,49 +88,45 @@ protected void setPipeParamsImpl() { settings.contourRadius.getSecond(), settings.maxCannyThresh, settings.circleAccuracy, - Math.hypot(frameStaticProperties.imageWidth, frameStaticProperties.imageHeight)); - findCirclesPipe.setParams(findCirclePipeParams); + Math.hypot(frameStaticProperties.imageWidth, frameStaticProperties.imageHeight))); - FilterShapesPipe.FilterShapesPipeParams filterShapesPipeParams = + filterShapesPipe.setParams( new FilterShapesPipe.FilterShapesPipeParams( settings.contourShape, settings.contourArea.getFirst(), settings.contourArea.getSecond(), settings.contourPerimeter.getFirst(), settings.contourPerimeter.getSecond(), - frameStaticProperties); - filterShapesPipe.setParams(filterShapesPipeParams); + frameStaticProperties)); - SortContoursPipe.SortContoursParams sortContoursParams = + sortContoursPipe.setParams( new SortContoursPipe.SortContoursParams( settings.contourSortMode, - settings.outputShowMultipleTargets ? MAX_MULTI_TARGET_RESULTS : 1, - frameStaticProperties); // TODO don't hardcode? - sortContoursPipe.setParams(sortContoursParams); + settings.outputShowMultipleTargets + ? MAX_MULTI_TARGET_RESULTS // TODO don't hardcode? + : 1, + frameStaticProperties)); - Collect2dTargetsPipe.Collect2dTargetsParams collect2dTargetsParams = + collect2dTargetsPipe.setParams( new Collect2dTargetsPipe.Collect2dTargetsParams( settings.offsetRobotOffsetMode, settings.offsetSinglePoint, dualOffsetValues, settings.contourTargetOffsetPointEdge, settings.contourTargetOrientation, - frameStaticProperties); - collect2dTargetsPipe.setParams(collect2dTargetsParams); + frameStaticProperties)); - var params = + cornerDetectionPipe.setParams( new CornerDetectionPipe.CornerDetectionPipeParameters( settings.cornerDetectionStrategy, settings.cornerDetectionUseConvexHulls, settings.cornerDetectionExactSideCount, settings.cornerDetectionSideCount, - settings.cornerDetectionAccuracyPercentage); - cornerDetectionPipe.setParams(params); + settings.cornerDetectionAccuracyPercentage)); - var solvePNPParams = + solvePNPPipe.setParams( new SolvePNPPipe.SolvePNPPipeParams( - frameStaticProperties.cameraCalibration, settings.targetModel); - solvePNPPipe.setParams(solvePNPParams); + frameStaticProperties.cameraCalibration, settings.targetModel)); Draw2dTargetsPipe.Draw2dTargetsParams draw2DTargetsParams = new Draw2dTargetsPipe.Draw2dTargetsParams( @@ -147,7 +138,7 @@ protected void setPipeParamsImpl() { draw2DTargetsParams.showRotatedBox = false; draw2DTargetsPipe.setParams(draw2DTargetsParams); - Draw2dCrosshairPipe.Draw2dCrosshairParams draw2dCrosshairParams = + draw2dCrosshairPipe.setParams( new Draw2dCrosshairPipe.Draw2dCrosshairParams( settings.outputShouldDraw, settings.offsetRobotOffsetMode, @@ -155,16 +146,14 @@ protected void setPipeParamsImpl() { dualOffsetValues, frameStaticProperties, settings.streamingFrameDivisor, - settings.inputImageRotationMode); - draw2dCrosshairPipe.setParams(draw2dCrosshairParams); + settings.inputImageRotationMode)); - var draw3dTargetsParams = + draw3dTargetsPipe.setParams( new Draw3dTargetsPipe.Draw3dContoursParams( settings.outputShouldDraw, frameStaticProperties.cameraCalibration, settings.targetModel, - settings.streamingFrameDivisor); - draw3dTargetsPipe.setParams(draw3dTargetsParams); + settings.streamingFrameDivisor)); } @Override @@ -199,7 +188,7 @@ protected CVPipelineResult process(Frame frame, ColoredShapePipelineSettings set sortContoursPipe.run( filterShapeResult.output.stream() .map(shape -> new PotentialTarget(shape.getContour(), shape)) - .collect(Collectors.toList())); + .toList()); sumPipeNanosElapsed += sortContoursResult.nanosElapsed; CVPipeResult> collect2dTargetsResult = diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/DriverModePipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/DriverModePipeline.java index 856c03579c..a8c52efc85 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/DriverModePipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/DriverModePipeline.java @@ -17,8 +17,8 @@ package org.photonvision.vision.pipeline; +import edu.wpi.first.math.Pair; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.photonvision.common.util.math.MathUtils; import org.photonvision.vision.frame.Frame; import org.photonvision.vision.frame.FrameThresholdType; @@ -47,10 +47,11 @@ public DriverModePipeline(DriverModePipelineSettings settings) { @Override protected void setPipeParamsImpl() { - Draw2dCrosshairPipe.Draw2dCrosshairParams draw2dCrosshairParams = + draw2dCrosshairPipe.setParams( new Draw2dCrosshairPipe.Draw2dCrosshairParams( - frameStaticProperties, settings.streamingFrameDivisor, settings.inputImageRotationMode); - draw2dCrosshairPipe.setParams(draw2dCrosshairParams); + frameStaticProperties, + settings.streamingFrameDivisor, + settings.inputImageRotationMode)); resizeImagePipe.setParams( new ResizeImagePipe.ResizeImageParams(settings.streamingFrameDivisor)); diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/ObjectDetectionPipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/ObjectDetectionPipeline.java index 684fdd0247..572e08d6b8 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/ObjectDetectionPipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/ObjectDetectionPipeline.java @@ -19,7 +19,6 @@ import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import org.photonvision.common.configuration.NeuralNetworkModelManager; import org.photonvision.vision.frame.Frame; import org.photonvision.vision.frame.FrameThresholdType; @@ -56,9 +55,6 @@ public ObjectDetectionPipeline(ObjectDetectionPipelineSettings settings) { @Override protected void setPipeParamsImpl() { - var params = new ObjectDetectionPipeParams(); - params.confidence = settings.confidence; - params.nms = settings.nms; Optional selectedModel = NeuralNetworkModelManager.getInstance().getModel(settings.model); @@ -71,10 +67,8 @@ protected void setPipeParamsImpl() { if (selectedModel.isEmpty()) { selectedModel = Optional.of(NullModel.getInstance()); } - - params.model = selectedModel.get(); - - objectDetectorPipe.setParams(params); + objectDetectorPipe.setParams( + new ObjectDetectionPipeParams(settings.confidence, settings.nms, selectedModel.get())); DualOffsetValues dualOffsetValues = new DualOffsetValues( @@ -83,30 +77,27 @@ protected void setPipeParamsImpl() { settings.offsetDualPointB, settings.offsetDualPointBArea); - SortContoursPipe.SortContoursParams sortContoursParams = + sortContoursPipe.setParams( new SortContoursPipe.SortContoursParams( settings.contourSortMode, settings.outputShowMultipleTargets ? MAX_MULTI_TARGET_RESULTS : 1, - frameStaticProperties); - sortContoursPipe.setParams(sortContoursParams); + frameStaticProperties)); - var filterContoursParams = + filterContoursPipe.setParams( new FilterObjectDetectionsPipe.FilterContoursParams( settings.contourArea, settings.contourRatio, frameStaticProperties, - settings.contourTargetOrientation == TargetOrientation.Landscape); - filterContoursPipe.setParams(filterContoursParams); + settings.contourTargetOrientation == TargetOrientation.Landscape)); - Collect2dTargetsPipe.Collect2dTargetsParams collect2dTargetsParams = + collect2dTargetsPipe.setParams( new Collect2dTargetsPipe.Collect2dTargetsParams( settings.offsetRobotOffsetMode, settings.offsetSinglePoint, dualOffsetValues, settings.contourTargetOffsetPointEdge, settings.contourTargetOrientation, - frameStaticProperties); - collect2dTargetsPipe.setParams(collect2dTargetsParams); + frameStaticProperties)); } @Override @@ -130,9 +121,7 @@ protected CVPipelineResult process(Frame frame, ObjectDetectionPipelineSettings CVPipeResult> sortContoursResult = sortContoursPipe.run( - filterContoursResult.output.stream() - .map(shape -> new PotentialTarget(shape)) - .collect(Collectors.toList())); + filterContoursResult.output.stream().map(shape -> new PotentialTarget(shape)).toList()); sumPipeNanosElapsed += sortContoursResult.nanosElapsed; CVPipeResult> collect2dTargetsResult = diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/OutputStreamPipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/OutputStreamPipeline.java index da2c400978..366ef1a0a2 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/OutputStreamPipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/OutputStreamPipeline.java @@ -17,8 +17,8 @@ package org.photonvision.vision.pipeline; +import edu.wpi.first.math.Pair; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; import org.photonvision.vision.frame.Frame; import org.photonvision.vision.frame.FrameStaticProperties; import org.photonvision.vision.opencv.DualOffsetValues; @@ -55,28 +55,25 @@ protected void setPipeParams( settings.offsetDualPointB, settings.offsetDualPointBArea); - var draw2DTargetsParams = + draw2dTargetsPipe.setParams( new Draw2dTargetsPipe.Draw2dTargetsParams( settings.outputShouldDraw, settings.outputShowMultipleTargets, - settings.streamingFrameDivisor); - draw2dTargetsPipe.setParams(draw2DTargetsParams); + settings.streamingFrameDivisor)); - var draw2DAprilTagsParams = + draw2dAprilTagsPipe.setParams( new Draw2dAprilTagsPipe.Draw2dAprilTagsParams( settings.outputShouldDraw, settings.outputShowMultipleTargets, - settings.streamingFrameDivisor); - draw2dAprilTagsPipe.setParams(draw2DAprilTagsParams); + settings.streamingFrameDivisor)); - var draw2DArucoParams = + draw2dArucoPipe.setParams( new Draw2dArucoPipe.Draw2dArucoParams( settings.outputShouldDraw, settings.outputShowMultipleTargets, - settings.streamingFrameDivisor); - draw2dArucoPipe.setParams(draw2DArucoParams); + settings.streamingFrameDivisor)); - var draw2dCrosshairParams = + draw2dCrosshairPipe.setParams( new Draw2dCrosshairPipe.Draw2dCrosshairParams( settings.outputShouldDraw, settings.offsetRobotOffsetMode, @@ -84,41 +81,36 @@ protected void setPipeParams( dualOffsetValues, frameStaticProperties, settings.streamingFrameDivisor, - settings.inputImageRotationMode); - draw2dCrosshairPipe.setParams(draw2dCrosshairParams); + settings.inputImageRotationMode)); - var draw3dTargetsParams = + draw3dTargetsPipe.setParams( new Draw3dTargetsPipe.Draw3dContoursParams( settings.outputShouldDraw, frameStaticProperties.cameraCalibration, settings.targetModel, - settings.streamingFrameDivisor); - draw3dTargetsPipe.setParams(draw3dTargetsParams); + settings.streamingFrameDivisor)); - var draw3dAprilTagsParams = + draw3dAprilTagsPipe.setParams( new Draw3dAprilTagsPipe.Draw3dAprilTagsParams( settings.outputShouldDraw, frameStaticProperties.cameraCalibration, settings.targetModel, - settings.streamingFrameDivisor); - draw3dAprilTagsPipe.setParams(draw3dAprilTagsParams); + settings.streamingFrameDivisor)); - var draw3dArucoParams = + draw3dArucoPipe.setParams( new Draw3dArucoPipe.Draw3dArucoParams( settings.outputShouldDraw, frameStaticProperties.cameraCalibration, settings.targetModel, - settings.streamingFrameDivisor); - draw3dArucoPipe.setParams(draw3dArucoParams); + settings.streamingFrameDivisor)); resizeImagePipe.setParams( new ResizeImagePipe.ResizeImageParams(settings.streamingFrameDivisor)); - if (settings instanceof Calibration3dPipelineSettings) { + if (settings instanceof Calibration3dPipelineSettings pipelineSettings) { drawCalibrationPipe.setParams( new DrawCalibrationPipe.DrawCalibrationPipeParams( - settings.streamingFrameDivisor, - ((Calibration3dPipelineSettings) settings).drawAllSnapshots)); + pipelineSettings.streamingFrameDivisor, pipelineSettings.drawAllSnapshots)); } } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/PipelineProfiler.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/PipelineProfiler.java index 57c94b0640..8d3fb88e5e 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/PipelineProfiler.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/PipelineProfiler.java @@ -37,19 +37,18 @@ public class PipelineProfiler { * output) 14 - draw2dTargetsPipe (on input) 15 - draw2dTargetsPipe (on output) 16 - * draw3dTargetsPipe (OPTIONAL, on input) 17 - draw3dTargetsPipe (OPTIONAL, on output) */ - private static final String[] ReflectivePipeNames = - new String[] { - "RotateImage", - "HSV", - "FindContours", - "SpeckleReject", - "FilterContours", - "GroupContours", - "SortContours", - "Collect2dTargets", - "CornerDetection", - "SolvePNP", - }; + private static final String[] ReflectivePipeNames = { + "RotateImage", + "HSV", + "FindContours", + "SpeckleReject", + "FilterContours", + "GroupContours", + "SortContours", + "Collect2dTargets", + "CornerDetection", + "SolvePNP", + }; public static final int ReflectivePipeCount = ReflectivePipeNames.length; diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java index fa2cb1a555..fc798d4184 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java @@ -64,14 +64,12 @@ protected void setPipeParamsImpl() { settings.offsetDualPointB, settings.offsetDualPointBArea); - var findContoursParams = new FindContoursPipe.FindContoursParams(); - findContoursPipe.setParams(findContoursParams); + findContoursPipe.setParams(new FindContoursPipe.FindContoursParams()); - var speckleRejectParams = - new SpeckleRejectPipe.SpeckleRejectParams(settings.contourSpecklePercentage); - speckleRejectPipe.setParams(speckleRejectParams); + speckleRejectPipe.setParams( + new SpeckleRejectPipe.SpeckleRejectParams(settings.contourSpecklePercentage)); - var filterContoursParams = + filterContoursPipe.setParams( new FilterContoursPipe.FilterContoursParams( settings.contourArea, settings.contourRatio, @@ -79,44 +77,38 @@ protected void setPipeParamsImpl() { frameStaticProperties, settings.contourFilterRangeX, settings.contourFilterRangeY, - settings.contourTargetOrientation == TargetOrientation.Landscape); - filterContoursPipe.setParams(filterContoursParams); + settings.contourTargetOrientation == TargetOrientation.Landscape)); - var groupContoursParams = + groupContoursPipe.setParams( new GroupContoursPipe.GroupContoursParams( - settings.contourGroupingMode, settings.contourIntersection); - groupContoursPipe.setParams(groupContoursParams); + settings.contourGroupingMode, settings.contourIntersection)); - var sortContoursParams = + sortContoursPipe.setParams( new SortContoursPipe.SortContoursParams( settings.contourSortMode, settings.outputShowMultipleTargets ? MAX_MULTI_TARGET_RESULTS : 1, - frameStaticProperties); - sortContoursPipe.setParams(sortContoursParams); + frameStaticProperties)); - var collect2dTargetsParams = + collect2dTargetsPipe.setParams( new Collect2dTargetsPipe.Collect2dTargetsParams( settings.offsetRobotOffsetMode, settings.offsetSinglePoint, dualOffsetValues, settings.contourTargetOffsetPointEdge, settings.contourTargetOrientation, - frameStaticProperties); - collect2dTargetsPipe.setParams(collect2dTargetsParams); + frameStaticProperties)); - var cornerDetectionPipeParams = + cornerDetectionPipe.setParams( new CornerDetectionPipe.CornerDetectionPipeParameters( settings.cornerDetectionStrategy, settings.cornerDetectionUseConvexHulls, settings.cornerDetectionExactSideCount, settings.cornerDetectionSideCount, - settings.cornerDetectionAccuracyPercentage); - cornerDetectionPipe.setParams(cornerDetectionPipeParams); + settings.cornerDetectionAccuracyPercentage)); - var solvePNPParams = + solvePNPPipe.setParams( new SolvePNPPipe.SolvePNPPipeParams( - frameStaticProperties.cameraCalibration, settings.targetModel); - solvePNPPipe.setParams(solvePNPParams); + frameStaticProperties.cameraCalibration, settings.targetModel)); } @Override diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/result/CalibrationPipelineResult.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/result/CalibrationPipelineResult.java index a06bd84436..acf895c50d 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/result/CalibrationPipelineResult.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/result/CalibrationPipelineResult.java @@ -18,14 +18,13 @@ package org.photonvision.vision.pipeline.result; import java.util.List; -import java.util.stream.Collectors; import org.opencv.core.Point; import org.photonvision.vision.frame.Frame; import org.photonvision.vision.target.TrackedTarget; public class CalibrationPipelineResult extends CVPipelineResult { private static List cornersToTarget(List> corners) { - return corners.stream().map(TrackedTarget::new).collect(Collectors.toList()); + return corners.stream().map(TrackedTarget::new).toList(); } public CalibrationPipelineResult( diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/PipelineManager.java b/photon-core/src/main/java/org/photonvision/vision/processes/PipelineManager.java index 85adb4cbd0..9d8b6cc321 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/PipelineManager.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/PipelineManager.java @@ -90,19 +90,16 @@ public PipelineManager(CameraConfiguration config) { * @return The gotten settings of the pipeline whose index was provided. */ public CVPipelineSettings getPipelineSettings(int index) { - if (index < 0) { - switch (index) { - case DRIVERMODE_INDEX: - return driverModePipeline.getSettings(); - case CAL_3D_INDEX: - return calibration3dPipeline.getSettings(); + return switch (index) { + case DRIVERMODE_INDEX -> driverModePipeline.getSettings(); + case CAL_3D_INDEX -> calibration3dPipeline.getSettings(); + default -> { + for (var setting : userPipelineSettings) { + if (setting.pipelineIndex == index) yield setting; + } + yield null; } - } - - for (var setting : userPipelineSettings) { - if (setting.pipelineIndex == index) return setting; - } - return null; + }; } /** @@ -112,19 +109,16 @@ public CVPipelineSettings getPipelineSettings(int index) { * @return the nickname of the pipeline whose index was provided. */ public String getPipelineNickname(int index) { - if (index < 0) { - switch (index) { - case DRIVERMODE_INDEX: - return driverModePipeline.getSettings().pipelineNickname; - case CAL_3D_INDEX: - return calibration3dPipeline.getSettings().pipelineNickname; + return switch (index) { + case DRIVERMODE_INDEX -> driverModePipeline.getSettings().pipelineNickname; + case CAL_3D_INDEX -> calibration3dPipeline.getSettings().pipelineNickname; + default -> { + for (var setting : userPipelineSettings) { + if (setting.pipelineIndex == index) yield setting.pipelineNickname; + } + yield null; } - } - - for (var setting : userPipelineSettings) { - if (setting.pipelineIndex == index) return setting.pipelineNickname; - } - return null; + }; } /** @@ -156,17 +150,12 @@ public int getCurrentPipelineIndex() { */ public CVPipeline getCurrentPipeline() { updatePipelineFromRequested(); - if (currentPipelineIndex < 0) { - switch (currentPipelineIndex) { - case CAL_3D_INDEX: - return calibration3dPipeline; - case DRIVERMODE_INDEX: - return driverModePipeline; - } - } - - // Just return the current user pipeline, we're not on aa built-in one - return currentUserPipeline; + return switch (currentPipelineIndex) { + case CAL_3D_INDEX -> calibration3dPipeline; + case DRIVERMODE_INDEX -> driverModePipeline; + // Just return the current user pipeline, we're not on a built-in one + default -> currentUserPipeline; + }; } /** @@ -339,40 +328,22 @@ public CVPipelineSettings addPipeline(PipelineType type, String nickname) { } private CVPipelineSettings createSettingsForType(PipelineType type, String nickname) { - switch (type) { - case Reflective -> { - var added = new ReflectivePipelineSettings(); - added.pipelineNickname = nickname; - return added; - } - case ColoredShape -> { - var added = new ColoredShapePipelineSettings(); - added.pipelineNickname = nickname; - return added; - } - case AprilTag -> { - var added = new AprilTagPipelineSettings(); - added.pipelineNickname = nickname; - return added; - } - case Aruco -> { - var added = new ArucoPipelineSettings(); - added.pipelineNickname = nickname; - return added; - } - case ObjectDetection -> { - var added = new ObjectDetectionPipelineSettings(); - added.pipelineNickname = nickname; - return added; - } - case Calib3d, DriverMode -> { - logger.error("Got invalid pipeline type: " + type); - return null; - } + CVPipelineSettings settings = + switch (type) { + case Reflective -> new ReflectivePipelineSettings(); + case ColoredShape -> new ColoredShapePipelineSettings(); + case AprilTag -> new AprilTagPipelineSettings(); + case Aruco -> new ArucoPipelineSettings(); + case ObjectDetection -> new ObjectDetectionPipelineSettings(); + case Calib3d, DriverMode -> { + logger.error("Got invalid pipeline type: " + type); + yield null; + } + }; + if (settings != null) { + settings.pipelineNickname = nickname; } - - // This can never happen, this is here to satisfy the compiler. - throw new IllegalStateException("Got impossible pipeline type: " + type); + return settings; } private void addPipelineInternal(CVPipelineSettings settings) { diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java index 34e9976ec7..f9bd0587df 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java @@ -160,7 +160,7 @@ public VisionModule(PipelineManager pipelineManager, VisionSource visionSource) // Set vendor FOV if (isVendorCamera()) { - var fov = ConfigManager.getInstance().getConfig().getHardwareConfig().vendorFOV; + var fov = ConfigManager.getInstance().getConfig().getHardwareConfig().vendorFOV(); logger.info("Setting FOV of vendor camera to " + fov); visionSource.getSettables().setFOV(fov); } @@ -571,20 +571,20 @@ public UICameraConfiguration toUICameraConfig() { var temp = new HashMap>(); var videoModes = visionSource.getSettables().getAllVideoModes(); - for (var k : videoModes.keySet()) { + for (var k : videoModes.entrySet()) { var internalMap = new HashMap(); - internalMap.put("width", videoModes.get(k).width); - internalMap.put("height", videoModes.get(k).height); - internalMap.put("fps", videoModes.get(k).fps); + internalMap.put("width", k.getValue().width); + internalMap.put("height", k.getValue().height); + internalMap.put("fps", k.getValue().fps); internalMap.put( "pixelFormat", - ((videoModes.get(k) instanceof LibcameraGpuSource.FPSRatedVideoMode) + ((k.getValue() instanceof LibcameraGpuSource.FPSRatedVideoMode) ? "kPicam" - : videoModes.get(k).pixelFormat.toString()) + : k.getValue().pixelFormat.toString()) .substring(1)); // Remove the k prefix - temp.put(k, internalMap); + temp.put(k.getKey(), internalMap); } if (videoModes.size() == 0) { diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java index d40e0d75bc..7a5da5331b 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java @@ -17,11 +17,11 @@ package org.photonvision.vision.processes; +import edu.wpi.first.math.Pair; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; -import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Point; import org.photonvision.common.dataflow.DataChangeSubscriber; import org.photonvision.common.dataflow.events.DataChangeEvent; @@ -55,23 +55,22 @@ public VisionModuleChangeSubscriber(VisionModule parentModule) { @Override public void onDataChangeEvent(DataChangeEvent event) { - if (event instanceof IncomingWebSocketEvent wsEvent) { - // Camera index -1 means a "multicast event" (i.e. the event is received by all cameras) - if (wsEvent.cameraUniqueName != null - && wsEvent.cameraUniqueName.equals(parentModule.uniqueName())) { - logger.trace("Got PSC event - propName: " + wsEvent.propertyName); - changeListLock.lock(); - try { - getSettingChanges() - .add( - new VisionModuleChange( - wsEvent.propertyName, - wsEvent.data, - parentModule.pipelineManager.getCurrentPipeline().getSettings(), - wsEvent.originContext)); - } finally { - changeListLock.unlock(); - } + // Camera index -1 means a "multicast event" (i.e. the event is received by all cameras) + if (event instanceof IncomingWebSocketEvent wsEvent + && wsEvent.cameraUniqueName != null + && wsEvent.cameraUniqueName.equals(parentModule.uniqueName())) { + logger.trace("Got PSC event - propName: " + wsEvent.propertyName); + changeListLock.lock(); + try { + getSettingChanges() + .add( + new VisionModuleChange( + wsEvent.propertyName, + wsEvent.data, + parentModule.pipelineManager.getCurrentPipeline().getSettings(), + wsEvent.originContext)); + } finally { + changeListLock.unlock(); } } } @@ -89,12 +88,8 @@ public void processSettingChanges() { var newPropValue = change.getNewPropValue(); var currentSettings = change.getCurrentSettings(); var originContext = change.getOriginContext(); - boolean handled = true; switch (propName) { - case "pipelineName" -> { - newPipelineNickname((String) newPropValue); - continue; - } + case "pipelineName" -> newPipelineNickname((String) newPropValue); case "newPipelineInfo" -> newPipelineInfo((Pair) newPropValue); case "deleteCurrPipeline" -> deleteCurrPipeline(); case "changePipeline" -> changePipeline((Integer) newPropValue); @@ -120,45 +115,43 @@ public void processSettingChanges() { parentModule.saveAndBroadcastAll(); } case "isDriverMode" -> parentModule.setDriverMode((Boolean) newPropValue); - default -> handled = false; - } - - // special case for camera settables - if (propName.startsWith("camera")) { - var propMethodName = "set" + propName.replace("camera", ""); - var methods = parentModule.visionSource.getSettables().getClass().getMethods(); - for (var method : methods) { - if (method.getName().equalsIgnoreCase(propMethodName)) { - try { - method.invoke(parentModule.visionSource.getSettables(), newPropValue); - } catch (Exception e) { - logger.error("Failed to invoke camera settable method: " + method.getName(), e); + default -> { + // special case for camera settables + if (propName.startsWith("camera")) { + var propMethodName = "set" + propName.replace("camera", ""); + var methods = parentModule.visionSource.getSettables().getClass().getMethods(); + for (var method : methods) { + if (method.getName().equalsIgnoreCase(propMethodName)) { + try { + method.invoke(parentModule.visionSource.getSettables(), newPropValue); + } catch (Exception e) { + logger.error("Failed to invoke camera settable method: " + method.getName(), e); + } + } } } - } - } - if (!handled) { - try { - setProperty(currentSettings, propName, newPropValue); - logger.trace("Set prop " + propName + " to value " + newPropValue); - } catch (NoSuchFieldException | IllegalAccessException e) { - logger.error( - "Could not set prop " - + propName - + " with value " - + newPropValue - + " on " - + currentSettings - + " | " - + e.getClass().getSimpleName(), - e); - } catch (Exception e) { - logger.error("Unknown exception when setting PSC prop!", e); + try { + setProperty(currentSettings, propName, newPropValue); + logger.trace("Set prop " + propName + " to value " + newPropValue); + } catch (NoSuchFieldException | IllegalAccessException e) { + logger.error( + "Could not set prop " + + propName + + " with value " + + newPropValue + + " on " + + currentSettings + + " | " + + e.getClass().getSimpleName(), + e); + } catch (Exception e) { + logger.error("Unknown exception when setting PSC prop!", e); + } + + parentModule.saveAndBroadcastSelective(originContext, propName, newPropValue); } } - - parentModule.saveAndBroadcastSelective(originContext, propName, newPropValue); } getSettingChanges().clear(); } finally { @@ -173,8 +166,8 @@ public void newPipelineNickname(String newNickname) { } public void newPipelineInfo(Pair typeName) { - var type = typeName.getRight(); - var name = typeName.getLeft(); + var type = typeName.getSecond(); + var name = typeName.getFirst(); logger.info("Adding a " + type + " pipeline with name " + name); @@ -230,9 +223,8 @@ public void robotOffsetPoint(AdvancedPipelineSettings curAdvSettings, int offset switch (offsetOperation) { case CLEAR -> curAdvSettings.offsetSinglePoint = new Point(); case TAKE_SINGLE -> curAdvSettings.offsetSinglePoint = newPoint; - case TAKE_FIRST_DUAL, TAKE_SECOND_DUAL -> { - logger.warn("Dual point operation in single point mode"); - } + case TAKE_FIRST_DUAL, TAKE_SECOND_DUAL -> + logger.warn("Dual point operation in single point mode"); } } case Dual -> { @@ -253,14 +245,10 @@ public void robotOffsetPoint(AdvancedPipelineSettings curAdvSettings, int offset curAdvSettings.offsetDualPointB = newPoint; curAdvSettings.offsetDualPointBArea = latestTarget.getArea(); } - case TAKE_SINGLE -> { - logger.warn("Single point operation in dual point mode"); - } + case TAKE_SINGLE -> logger.warn("Single point operation in dual point mode"); } } - case None -> { - logger.warn("Robot offset point operation requested, but no offset mode set"); - } + case None -> logger.warn("Robot offset point operation requested, but no offset mode set"); } } diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java index fc6818a36c..7eb3c86212 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java @@ -18,8 +18,6 @@ package org.photonvision.vision.processes; import java.util.*; -import java.util.stream.Collectors; -import org.photonvision.common.dataflow.websocket.UICameraConfiguration; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; @@ -68,9 +66,7 @@ private synchronized int newCameraIndex() { // Big list, which should contain every vision source (currently loaded plus the new ones being // added) List bigList = - this.getModules().stream() - .map(it -> it.getCameraConfiguration().streamIndex) - .collect(Collectors.toList()); + this.getModules().stream().map(it -> it.getCameraConfiguration().streamIndex).toList(); int idx = 0; while (bigList.contains(idx)) { @@ -83,24 +79,4 @@ private synchronized int newCameraIndex() { return idx; } - - public static class UiVmmState { - public final List visionModules; - - UiVmmState(List _v) { - this.visionModules = _v; - } - } - - public synchronized UiVmmState getState() { - return new UiVmmState( - this.visionModules.stream() - .map(VisionModule::toUICameraConfig) - .map( - it -> { - it.calibrations = null; - return it; - }) - .collect(Collectors.toList())); - } } diff --git a/photon-core/src/main/java/org/photonvision/vision/target/PotentialTarget.java b/photon-core/src/main/java/org/photonvision/vision/target/PotentialTarget.java index 520f1d454d..a7c00e62ee 100644 --- a/photon-core/src/main/java/org/photonvision/vision/target/PotentialTarget.java +++ b/photon-core/src/main/java/org/photonvision/vision/target/PotentialTarget.java @@ -56,11 +56,11 @@ public PotentialTarget(Contour inputContour, CVShape shape) { } public PotentialTarget(NeuralNetworkPipeResult det) { - this.shape = new CVShape(new Contour(det.bbox), ContourShape.Quadrilateral); + this.shape = new CVShape(new Contour(det.bbox()), ContourShape.Quadrilateral); this.m_mainContour = this.shape.getContour(); m_subContours = List.of(); - this.clsId = det.classIdx; - this.confidence = det.confidence; + this.clsId = det.classIdx(); + this.confidence = det.confidence(); } public PotentialTarget(CVShape cvShape) { diff --git a/photon-core/src/main/java/org/photonvision/vision/target/TargetCalculations.java b/photon-core/src/main/java/org/photonvision/vision/target/TargetCalculations.java index 22c92ae2ce..1cdcd31f52 100644 --- a/photon-core/src/main/java/org/photonvision/vision/target/TargetCalculations.java +++ b/photon-core/src/main/java/org/photonvision/vision/target/TargetCalculations.java @@ -134,17 +134,16 @@ public static Point calculateRobotOffsetPoint( Point camCenterPoint, DualOffsetValues dualOffsetValues, RobotOffsetPointMode offsetMode) { - switch (offsetMode) { - case None: - default: - return camCenterPoint; - case Single: + return switch (offsetMode) { + case None -> camCenterPoint; + case Single -> { if (offsetPoint.x == 0 && offsetPoint.y == 0) { - return camCenterPoint; + yield camCenterPoint; } else { - return offsetPoint; + yield offsetPoint; } - case Dual: + } + case Dual -> { var resultPoint = new Point(); var lineValues = dualOffsetValues.getLineValues(); var offsetSlope = lineValues.getFirst(); @@ -152,8 +151,9 @@ public static Point calculateRobotOffsetPoint( resultPoint.x = (offsetPoint.x - offsetIntercept) / offsetSlope; resultPoint.y = (offsetPoint.y * offsetSlope) + offsetIntercept; - return resultPoint; - } + yield resultPoint; + } + }; } public static double getAspectRatio(RotatedRect rect, boolean isLandscape) { diff --git a/photon-core/src/main/java/org/photonvision/vision/target/TrackedTarget.java b/photon-core/src/main/java/org/photonvision/vision/target/TrackedTarget.java index ee31696cf6..1c5e22c05d 100644 --- a/photon-core/src/main/java/org/photonvision/vision/target/TrackedTarget.java +++ b/photon-core/src/main/java/org/photonvision/vision/target/TrackedTarget.java @@ -122,11 +122,9 @@ public TrackedTarget( tvec.put( 0, 0, - new double[] { - bestPose.getTranslation().getX(), - bestPose.getTranslation().getY(), - bestPose.getTranslation().getZ() - }); + bestPose.getTranslation().getX(), + bestPose.getTranslation().getY(), + bestPose.getTranslation().getZ()); setCameraRelativeTvec(tvec); // Opencv expects a 3d vector with norm = angle and direction = axis @@ -136,13 +134,12 @@ public TrackedTarget( } double[] corners = tagDetection.getCorners(); - Point[] cornerPoints = - new Point[] { - new Point(corners[0], corners[1]), - new Point(corners[2], corners[3]), - new Point(corners[4], corners[5]), - new Point(corners[6], corners[7]) - }; + Point[] cornerPoints = { + new Point(corners[0], corners[1]), + new Point(corners[2], corners[3]), + new Point(corners[4], corners[5]), + new Point(corners[6], corners[7]) + }; m_targetCorners = List.of(cornerPoints); MatOfPoint contourMat = new MatOfPoint(cornerPoints); m_approximateBoundingPolygon = new MatOfPoint2f(cornerPoints); @@ -198,13 +195,12 @@ public TrackedTarget( double[] xCorners = result.getXCorners(); double[] yCorners = result.getYCorners(); - Point[] cornerPoints = - new Point[] { - new Point(xCorners[0], yCorners[0]), - new Point(xCorners[1], yCorners[1]), - new Point(xCorners[2], yCorners[2]), - new Point(xCorners[3], yCorners[3]) - }; + Point[] cornerPoints = { + new Point(xCorners[0], yCorners[0]), + new Point(xCorners[1], yCorners[1]), + new Point(xCorners[2], yCorners[2]), + new Point(xCorners[3], yCorners[3]) + }; m_targetCorners = List.of(cornerPoints); MatOfPoint contourMat = new MatOfPoint(cornerPoints); m_approximateBoundingPolygon = new MatOfPoint2f(cornerPoints); @@ -236,11 +232,9 @@ public TrackedTarget( tvec.put( 0, 0, - new double[] { - bestPose.getTranslation().getX(), - bestPose.getTranslation().getY(), - bestPose.getTranslation().getZ() - }); + bestPose.getTranslation().getX(), + bestPose.getTranslation().getY(), + bestPose.getTranslation().getZ()); setCameraRelativeTvec(tvec); var rvec = new Mat(3, 1, CvType.CV_64FC1); diff --git a/photon-core/src/test/java/org/photonvision/common/configuration/ConfigTest.java b/photon-core/src/test/java/org/photonvision/common/configuration/ConfigTest.java index 8f5c333a86..95262912af 100644 --- a/photon-core/src/test/java/org/photonvision/common/configuration/ConfigTest.java +++ b/photon-core/src/test/java/org/photonvision/common/configuration/ConfigTest.java @@ -17,6 +17,9 @@ package org.photonvision.common.configuration; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -87,9 +90,9 @@ public void serializeConfig() { Path.of(configMgr.configDirectoryFile.toString(), "cameras", "TestCamera") .toAbsolutePath() .toString()); - Assertions.assertTrue(camConfDir.exists(), "TestCamera config folder not found!"); + assertTrue(camConfDir.exists(), "TestCamera config folder not found!"); - Assertions.assertTrue( + assertTrue( Files.exists(Path.of(configMgr.configDirectoryFile.toString(), "networkSettings.json")), "networkSettings.json file not found!"); } @@ -104,17 +107,17 @@ public void deserializeConfig() { var apriltagPipelineSettings = configMgr.getConfig().getCameraConfigurations().get("TestCamera").pipelineSettings.get(2); - Assertions.assertEquals(REFLECTIVE_PIPELINE_SETTINGS, reflectivePipelineSettings); - Assertions.assertEquals(COLORED_SHAPE_PIPELINE_SETTINGS, coloredShapePipelineSettings); - Assertions.assertEquals(APRIL_TAG_PIPELINE_SETTINGS, apriltagPipelineSettings); + assertEquals(REFLECTIVE_PIPELINE_SETTINGS, reflectivePipelineSettings); + assertEquals(COLORED_SHAPE_PIPELINE_SETTINGS, coloredShapePipelineSettings); + assertEquals(APRIL_TAG_PIPELINE_SETTINGS, apriltagPipelineSettings); - Assertions.assertTrue( + assertTrue( reflectivePipelineSettings instanceof ReflectivePipelineSettings, "Config loaded pipeline settings for index 0 not of expected type ReflectivePipelineSettings!"); - Assertions.assertTrue( + assertTrue( coloredShapePipelineSettings instanceof ColoredShapePipelineSettings, "Config loaded pipeline settings for index 1 not of expected type ColoredShapePipelineSettings!"); - Assertions.assertTrue( + assertTrue( apriltagPipelineSettings instanceof AprilTagPipelineSettings, "Config loaded pipeline settings for index 2 not of expected type AprilTagPipelineSettings!"); } @@ -184,7 +187,7 @@ public void testJacksonHandlesOldTargetEnum() throws IOException { AprilTagPipelineSettings settings = (AprilTagPipelineSettings) JacksonUtils.deserialize(tempFile.toPath(), CVPipelineSettings.class); - Assertions.assertEquals(TargetModel.kAprilTag6in_16h5, settings.targetModel); + assertEquals(TargetModel.kAprilTag6in_16h5, settings.targetModel); tempFile.delete(); } diff --git a/photon-core/src/test/java/org/photonvision/common/configuration/NetworkConfigTest.java b/photon-core/src/test/java/org/photonvision/common/configuration/NetworkConfigTest.java index 7c9d6d6f42..0cc3c027c4 100644 --- a/photon-core/src/test/java/org/photonvision/common/configuration/NetworkConfigTest.java +++ b/photon-core/src/test/java/org/photonvision/common/configuration/NetworkConfigTest.java @@ -17,11 +17,13 @@ package org.photonvision.common.configuration; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class NetworkConfigTest { @@ -30,7 +32,7 @@ public void testSerialization() throws IOException { var mapper = new ObjectMapper(); var path = Path.of("netTest.json"); mapper.writeValue(path.toFile(), new NetworkConfig()); - Assertions.assertDoesNotThrow(() -> mapper.readValue(path.toFile(), NetworkConfig.class)); + assertDoesNotThrow(() -> mapper.readValue(path.toFile(), NetworkConfig.class)); new File("netTest.json").delete(); } @@ -40,13 +42,13 @@ public void testDeserializeTeamNumberOrNtServerAddress() { var folder = Path.of("test-resources/network-old-team-number"); var configMgr = new ConfigManager(folder, new LegacyConfigProvider(folder)); configMgr.load(); - Assertions.assertEquals("9999", configMgr.getConfig().getNetworkConfig().ntServerAddress); + assertEquals("9999", configMgr.getConfig().getNetworkConfig().ntServerAddress); } { var folder = Path.of("test-resources/network-new-team-number"); var configMgr = new ConfigManager(folder, new LegacyConfigProvider(folder)); configMgr.load(); - Assertions.assertEquals("9999", configMgr.getConfig().getNetworkConfig().ntServerAddress); + assertEquals("9999", configMgr.getConfig().getNetworkConfig().ntServerAddress); } } } diff --git a/photon-core/src/test/java/org/photonvision/common/util/LogFileManagementTest.java b/photon-core/src/test/java/org/photonvision/common/util/LogFileManagementTest.java index e834874641..9f96b59bd4 100644 --- a/photon-core/src/test/java/org/photonvision/common/util/LogFileManagementTest.java +++ b/photon-core/src/test/java/org/photonvision/common/util/LogFileManagementTest.java @@ -17,6 +17,11 @@ package org.photonvision.common.util; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -26,7 +31,6 @@ import java.time.ZoneOffset; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.logging.Logger; @@ -39,7 +43,7 @@ public void fileCleanupTest() { String testDir = ConfigManager.getInstance().getLogsDir().toString() + "/test"; - Assertions.assertDoesNotThrow(() -> Files.createDirectories(Path.of(testDir))); + assertDoesNotThrow(() -> Files.createDirectories(Path.of(testDir))); // Create a bunch of log files with dummy contents. for (int fileIdx = 0; fileIdx < Logger.MAX_LOGS_TO_KEEP + 5; fileIdx++) { @@ -52,20 +56,19 @@ public void fileCleanupTest() { testLogWriter.write("Test log contents created for testing purposes only"); testLogWriter.close(); } catch (IOException e) { - Assertions.fail("Could not create test files"); + fail("Could not create test files"); } } // Confirm new log files were created - Assertions.assertTrue( + assertTrue( Logger.MAX_LOGS_TO_KEEP + 5 <= countLogFiles(testDir), "Not enough log files discovered"); // Run the log cleanup routine Logger.cleanLogs(Path.of(testDir)); // Confirm we deleted log files - Assertions.assertEquals( - Logger.MAX_LOGS_TO_KEEP, countLogFiles(testDir), "Not enough log files deleted"); + assertEquals(Logger.MAX_LOGS_TO_KEEP, countLogFiles(testDir), "Not enough log files deleted"); // Clean uptest directory org.photonvision.common.util.file.FileUtils.deleteDirectory(Path.of(testDir)); diff --git a/photon-core/src/test/java/org/photonvision/common/util/TimedTaskManagerTest.java b/photon-core/src/test/java/org/photonvision/common/util/TimedTaskManagerTest.java index 7b7567d671..5039ebd991 100644 --- a/photon-core/src/test/java/org/photonvision/common/util/TimedTaskManagerTest.java +++ b/photon-core/src/test/java/org/photonvision/common/util/TimedTaskManagerTest.java @@ -17,8 +17,9 @@ package org.photonvision.common.util; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class TimedTaskManagerTest { @@ -27,6 +28,6 @@ public void atomicIntegerIncrementTest() throws InterruptedException { AtomicInteger i = new AtomicInteger(); TimedTaskManager.getInstance().addTask("TaskManagerTest", i::getAndIncrement, 2); Thread.sleep(400); - Assertions.assertEquals(200, i.get(), 15); + assertEquals(200, i.get(), 15); } } diff --git a/photon-core/src/test/java/org/photonvision/hardware/HardwareConfigTest.java b/photon-core/src/test/java/org/photonvision/hardware/HardwareConfigTest.java index 9cd13e5dda..67822816b2 100644 --- a/photon-core/src/test/java/org/photonvision/hardware/HardwareConfigTest.java +++ b/photon-core/src/test/java/org/photonvision/hardware/HardwareConfigTest.java @@ -17,11 +17,11 @@ package org.photonvision.hardware; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.photonvision.common.configuration.HardwareConfig; import org.photonvision.common.hardware.GPIO.CustomGPIO; @@ -34,11 +34,10 @@ public void loadJson() { System.out.println("Loading Hardware configs..."); var config = new ObjectMapper().readValue(TestUtils.getHardwareConfigJson(), HardwareConfig.class); - assertEquals(config.deviceName, "PhotonVision"); - assertEquals(config.deviceLogoPath, "photonvision.png"); - assertEquals(config.supportURL, "https://support.photonvision.com"); - Assertions.assertArrayEquals( - config.ledPins.stream().mapToInt(i -> i).toArray(), new int[] {2, 13}); + assertEquals(config.deviceName(), "PhotonVision"); + assertEquals(config.deviceLogoPath(), "photonvision.png"); + assertEquals(config.supportURL(), "https://support.photonvision.com"); + assertArrayEquals(config.ledPins().stream().mapToInt(i -> i).toArray(), new int[] {2, 13}); CustomGPIO.setConfig(config); } catch (IOException e) { diff --git a/photon-core/src/test/java/org/photonvision/vision/QuirkyCameraTest.java b/photon-core/src/test/java/org/photonvision/vision/QuirkyCameraTest.java index 927a2cf27d..e9126bf28b 100644 --- a/photon-core/src/test/java/org/photonvision/vision/QuirkyCameraTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/QuirkyCameraTest.java @@ -17,8 +17,9 @@ package org.photonvision.vision; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.HashMap; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.photonvision.vision.camera.CameraQuirk; import org.photonvision.vision.camera.QuirkyCamera; @@ -35,7 +36,7 @@ public void ps3EyeTest() { } QuirkyCamera psEye = QuirkyCamera.getQuirkyCamera(0x1415, 0x2000); - Assertions.assertEquals(psEye.quirks, ps3EyeQuirks); + assertEquals(psEye.quirks, ps3EyeQuirks); } @Test @@ -46,6 +47,6 @@ public void quirklessCameraTest() { } QuirkyCamera quirkless = QuirkyCamera.getQuirkyCamera(1234, 8888); - Assertions.assertEquals(quirkless.quirks, noQuirks); + assertEquals(quirkless.quirks, noQuirks); } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/AprilTagTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/AprilTagTest.java index 24bffd6d55..7a1fa96488 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/AprilTagTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/AprilTagTest.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipeline; +import static org.junit.jupiter.api.Assertions.assertEquals; + import edu.wpi.first.math.geometry.Translation3d; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.photonvision.common.configuration.ConfigManager; @@ -29,7 +29,6 @@ import org.photonvision.vision.frame.provider.FileFrameProvider; import org.photonvision.vision.pipeline.result.CVPipelineResult; import org.photonvision.vision.target.TargetModel; -import org.photonvision.vision.target.TrackedTarget; public class AprilTagTest { @BeforeEach @@ -59,7 +58,7 @@ public void testApriltagFacingCamera() { CVPipelineResult pipelineResult; pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); // Draw on input var outputPipe = new OutputStreamPipeline(); @@ -74,33 +73,31 @@ public void testApriltagFacingCamera() { // Test corner order var corners = target.getTargetCorners(); - Assertions.assertEquals(260, corners.get(0).x, 10); - Assertions.assertEquals(245, corners.get(0).y, 10); - Assertions.assertEquals(315, corners.get(1).x, 10); - Assertions.assertEquals(245, corners.get(1).y, 10); - Assertions.assertEquals(315, corners.get(2).x, 10); - Assertions.assertEquals(190, corners.get(2).y, 10); - Assertions.assertEquals(260, corners.get(3).x, 10); - Assertions.assertEquals(190, corners.get(3).y, 10); + assertEquals(260, corners.get(0).x, 10); + assertEquals(245, corners.get(0).y, 10); + assertEquals(315, corners.get(1).x, 10); + assertEquals(245, corners.get(1).y, 10); + assertEquals(315, corners.get(2).x, 10); + assertEquals(190, corners.get(2).y, 10); + assertEquals(260, corners.get(3).x, 10); + assertEquals(190, corners.get(3).y, 10); var pose = target.getBestCameraToTarget3d(); // Test pose estimate translation - Assertions.assertEquals(2, pose.getTranslation().getX(), 0.2); - Assertions.assertEquals(0.1, pose.getTranslation().getY(), 0.2); - Assertions.assertEquals(0.0, pose.getTranslation().getZ(), 0.2); + assertEquals(2, pose.getTranslation().getX(), 0.2); + assertEquals(0.1, pose.getTranslation().getY(), 0.2); + assertEquals(0.0, pose.getTranslation().getZ(), 0.2); // Test pose estimate rotation // We expect the object axes to be in NWU, with the x-axis coming out of the tag // This visible tag is facing the camera almost parallel, so in world space: // The object's X axis should be (-1, 0, 0) - Assertions.assertEquals( - -1, new Translation3d(1, 0, 0).rotateBy(pose.getRotation()).getX(), 0.1); + assertEquals(-1, new Translation3d(1, 0, 0).rotateBy(pose.getRotation()).getX(), 0.1); // The object's Y axis should be (0, -1, 0) - Assertions.assertEquals( - -1, new Translation3d(0, 1, 0).rotateBy(pose.getRotation()).getY(), 0.1); + assertEquals(-1, new Translation3d(0, 1, 0).rotateBy(pose.getRotation()).getY(), 0.1); // The object's Z axis should be (0, 0, 1) - Assertions.assertEquals(1, new Translation3d(0, 0, 1).rotateBy(pose.getRotation()).getZ(), 0.1); + assertEquals(1, new Translation3d(0, 0, 1).rotateBy(pose.getRotation()).getZ(), 0.1); } @Test @@ -124,7 +121,7 @@ public void testApriltagDistorted() { CVPipelineResult pipelineResult; pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); // Draw on input var outputPipe = new OutputStreamPipeline(); @@ -136,20 +133,8 @@ public void testApriltagDistorted() { // these numbers are not *accurate*, but they are known and expected var pose = pipelineResult.targets.get(0).getBestCameraToTarget3d(); - Assertions.assertEquals(4.14, pose.getTranslation().getX(), 0.2); - Assertions.assertEquals(2, pose.getTranslation().getY(), 0.2); - Assertions.assertEquals(0.0, pose.getTranslation().getZ(), 0.2); - } - - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.println( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " " + "fps)"); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - System.out.println( - "Found targets at " - + pipelineResult.targets.stream() - .map(TrackedTarget::getBestCameraToTarget3d) - .collect(Collectors.toList())); + assertEquals(4.14, pose.getTranslation().getX(), 0.2); + assertEquals(2, pose.getTranslation().getY(), 0.2); + assertEquals(0.0, pose.getTranslation().getZ(), 0.2); } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/ArucoPipelineTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/ArucoPipelineTest.java index 8a7a4af464..a145b503ef 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/ArucoPipelineTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/ArucoPipelineTest.java @@ -17,9 +17,9 @@ package org.photonvision.vision.pipeline; +import static org.junit.jupiter.api.Assertions.assertEquals; + import edu.wpi.first.math.geometry.Translation3d; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.photonvision.common.configuration.ConfigManager; @@ -29,7 +29,6 @@ import org.photonvision.vision.frame.provider.FileFrameProvider; import org.photonvision.vision.pipeline.result.CVPipelineResult; import org.photonvision.vision.target.TargetModel; -import org.photonvision.vision.target.TrackedTarget; public class ArucoPipelineTest { @BeforeEach @@ -59,7 +58,7 @@ public void testApriltagFacingCamera() { CVPipelineResult pipelineResult; pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); // Draw on input var outputPipe = new OutputStreamPipeline(); @@ -74,44 +73,30 @@ public void testApriltagFacingCamera() { // Test corner order var corners = target.getTargetCorners(); - Assertions.assertEquals(260, corners.get(0).x, 10); - Assertions.assertEquals(245, corners.get(0).y, 10); - Assertions.assertEquals(315, corners.get(1).x, 10); - Assertions.assertEquals(245, corners.get(1).y, 10); - Assertions.assertEquals(315, corners.get(2).x, 10); - Assertions.assertEquals(190, corners.get(2).y, 10); - Assertions.assertEquals(260, corners.get(3).x, 10); - Assertions.assertEquals(190, corners.get(3).y, 10); + assertEquals(260, corners.get(0).x, 10); + assertEquals(245, corners.get(0).y, 10); + assertEquals(315, corners.get(1).x, 10); + assertEquals(245, corners.get(1).y, 10); + assertEquals(315, corners.get(2).x, 10); + assertEquals(190, corners.get(2).y, 10); + assertEquals(260, corners.get(3).x, 10); + assertEquals(190, corners.get(3).y, 10); var pose = target.getBestCameraToTarget3d(); // Test pose estimate translation - Assertions.assertEquals(2, pose.getTranslation().getX(), 0.2); - Assertions.assertEquals(0.1, pose.getTranslation().getY(), 0.2); - Assertions.assertEquals(0.0, pose.getTranslation().getZ(), 0.2); + assertEquals(2, pose.getTranslation().getX(), 0.2); + assertEquals(0.1, pose.getTranslation().getY(), 0.2); + assertEquals(0.0, pose.getTranslation().getZ(), 0.2); // Test pose estimate rotation // We expect the object axes to be in NWU, with the x-axis coming out of the tag // This visible tag is facing the camera almost parallel, so in world space: // The object's X axis should be (-1, 0, 0) - Assertions.assertEquals( - -1, new Translation3d(1, 0, 0).rotateBy(pose.getRotation()).getX(), 0.1); + assertEquals(-1, new Translation3d(1, 0, 0).rotateBy(pose.getRotation()).getX(), 0.1); // The object's Y axis should be (0, -1, 0) - Assertions.assertEquals( - -1, new Translation3d(0, 1, 0).rotateBy(pose.getRotation()).getY(), 0.1); + assertEquals(-1, new Translation3d(0, 1, 0).rotateBy(pose.getRotation()).getY(), 0.1); // The object's Z axis should be (0, 0, 1) - Assertions.assertEquals(1, new Translation3d(0, 0, 1).rotateBy(pose.getRotation()).getZ(), 0.1); - } - - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.println( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " " + "fps)"); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - System.out.println( - "Found targets at " - + pipelineResult.targets.stream() - .map(TrackedTarget::getBestCameraToTarget3d) - .collect(Collectors.toList())); + assertEquals(1, new Translation3d(0, 0, 1).rotateBy(pose.getRotation()).getZ(), 0.1); } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/CalibrationRotationPipeTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/CalibrationRotationPipeTest.java index 296e70481e..53283228b3 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/CalibrationRotationPipeTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/CalibrationRotationPipeTest.java @@ -23,8 +23,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.cartesian.CartesianTest; @@ -123,7 +121,7 @@ public void testUndistortImagePointsWithRotation(@Enum ImageRotationMode rot) { 0.09625562194891251, -0.1860797479660746 }), - new double[] {}, + new double[0], List.of(), new Size(), 1, @@ -151,13 +149,13 @@ public void testUndistortImagePointsWithRotation(@Enum ImageRotationMode rot) { var rotatedDistortedPoints = distortedOriginalPoints.stream() .map(it -> rot.rotatePoint(it, frameProps.imageWidth, frameProps.imageHeight)) - .collect(Collectors.toList()); + .toList(); // Now let's instead rotate then distort var rotatedOriginalPoints = Arrays.stream(originalPoints) .map(it -> rot.rotatePoint(it, frameProps.imageWidth, frameProps.imageHeight)) - .collect(Collectors.toList()); + .toList(); var distortedRotatedPoints = OpenCVHelp.distortPoints( @@ -288,7 +286,7 @@ public void testApriltagRotated() { 0.04625562194891251, -0.0860797479660746 }), - new double[] {}, + new double[0], List.of(), new Size(), 1, @@ -310,9 +308,7 @@ public void testApriltagRotated() { // rotate and try again var rotAngle = ImageRotationMode.DEG_90_CCW; var rotatedDistortedPoints = - distortedCorners.stream() - .map(it -> rotAngle.rotatePoint(it, 1280, 720)) - .collect(Collectors.toList()); + distortedCorners.stream().map(it -> rotAngle.rotatePoint(it, 1280, 720)).toList(); pipe.setParams( new SolvePNPPipeParams( coeffs.rotateCoefficients(rotAngle), TargetModel.kAprilTag6p5in_36h11)); @@ -327,14 +323,11 @@ public void testApriltagRotated() { System.out.println("Base: " + pose_base); System.out.println("rot-unrot: " + pose_unrotated); - Assertions.assertEquals(pose_base.getX(), pose_unrotated.getX(), 0.01); - Assertions.assertEquals(pose_base.getY(), pose_unrotated.getY(), 0.01); - Assertions.assertEquals(pose_base.getZ(), pose_unrotated.getZ(), 0.01); - Assertions.assertEquals( - pose_base.getRotation().getX(), pose_unrotated.getRotation().getX(), 0.01); - Assertions.assertEquals( - pose_base.getRotation().getY(), pose_unrotated.getRotation().getY(), 0.01); - Assertions.assertEquals( - pose_base.getRotation().getZ(), pose_unrotated.getRotation().getZ(), 0.01); + assertEquals(pose_base.getX(), pose_unrotated.getX(), 0.01); + assertEquals(pose_base.getY(), pose_unrotated.getY(), 0.01); + assertEquals(pose_base.getZ(), pose_unrotated.getZ(), 0.01); + assertEquals(pose_base.getRotation().getX(), pose_unrotated.getRotation().getX(), 0.01); + assertEquals(pose_base.getRotation().getY(), pose_unrotated.getRotation().getY(), 0.01); + assertEquals(pose_base.getRotation().getZ(), pose_unrotated.getRotation().getZ(), 0.01); } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/CirclePNPTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/CirclePNPTest.java index 9a4d392adc..35f02fc900 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/CirclePNPTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/CirclePNPTest.java @@ -20,7 +20,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.photonvision.common.util.TestUtils; @@ -34,7 +33,6 @@ import org.photonvision.vision.opencv.ContourShape; import org.photonvision.vision.pipeline.result.CVPipelineResult; import org.photonvision.vision.target.TargetModel; -import org.photonvision.vision.target.TrackedTarget; public class CirclePNPTest { private static final String LIFECAM_240P_CAL_FILE = "lifecam240p.json"; @@ -111,7 +109,7 @@ public void testCircle() { frameProvider.requestFrameThresholdType(pipeline.getThresholdType()); CVPipelineResult pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); TestUtils.showImage( pipelineResult.inputAndOutputFrame.colorImage.getMat(), "Pipeline output", 999999); @@ -123,7 +121,7 @@ private static void continuouslyRunPipeline(Frame frame, ReflectivePipelineSetti while (true) { CVPipelineResult pipelineResult = pipeline.run(frame, QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); int preRelease = CVMat.getMatCount(); pipelineResult.release(); int postRelease = CVMat.getMatCount(); @@ -151,16 +149,4 @@ public static void main(String[] args) { continuouslyRunPipeline(frameProvider.get(), settings); } - - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.println( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " " + "fps)"); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - System.out.println( - "Found targets at " - + pipelineResult.targets.stream() - .map(TrackedTarget::getBestCameraToTarget3d) - .collect(Collectors.toList())); - } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/ColoredShapePipelineTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/ColoredShapePipelineTest.java index b896185624..0e33c0fa3a 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/ColoredShapePipelineTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/ColoredShapePipelineTest.java @@ -35,7 +35,7 @@ public static void testTriangleDetection( TestUtils.showImage( colouredShapePipelineResult.inputAndOutputFrame.processedImage.getMat(), "Pipeline output: Triangle."); - printTestResults(colouredShapePipelineResult); + TestUtils.printTestResults(colouredShapePipelineResult); } public static void testQuadrilateralDetection( @@ -46,7 +46,7 @@ public static void testQuadrilateralDetection( TestUtils.showImage( colouredShapePipelineResult.inputAndOutputFrame.processedImage.getMat(), "Pipeline output: Quadrilateral."); - printTestResults(colouredShapePipelineResult); + TestUtils.printTestResults(colouredShapePipelineResult); } public static void testCustomShapeDetection( @@ -57,7 +57,7 @@ public static void testCustomShapeDetection( TestUtils.showImage( colouredShapePipelineResult.inputAndOutputFrame.processedImage.getMat(), "Pipeline output: Custom."); - printTestResults(colouredShapePipelineResult); + TestUtils.printTestResults(colouredShapePipelineResult); } @Test @@ -69,7 +69,7 @@ public static void testCircleShapeDetection( TestUtils.showImage( colouredShapePipelineResult.inputAndOutputFrame.processedImage.getMat(), "Pipeline output: Circle."); - printTestResults(colouredShapePipelineResult); + TestUtils.printTestResults(colouredShapePipelineResult); } @Test @@ -115,11 +115,4 @@ public static void main(String[] args) { // testCircleShapeDetection(pipeline, settings, frameProvider.get()); // testPowercellDetection(settings, pipeline); } - - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.print( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " fps), "); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/PipelineProfilerTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/PipelineProfilerTest.java index dbabd15e63..e7cb30d117 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/PipelineProfilerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/PipelineProfilerTest.java @@ -17,7 +17,9 @@ package org.photonvision.vision.pipeline; -import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; public class PipelineProfilerTest { @@ -35,7 +37,7 @@ public void reflectiveProfile() { System.out.println(validResult); - Assertions.assertEquals("Invalid data", invalidResult); - Assertions.assertTrue(validResult.contains("Total: 45.0ms")); + assertEquals("Invalid data", invalidResult); + assertTrue(validResult.contains("Total: 45.0ms")); } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/ReflectivePipelineTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/ReflectivePipelineTest.java index 0817cf37dc..5e10b56b19 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/ReflectivePipelineTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/ReflectivePipelineTest.java @@ -17,7 +17,9 @@ package org.photonvision.vision.pipeline; -import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; import org.photonvision.common.util.TestUtils; import org.photonvision.vision.camera.QuirkyCamera; @@ -60,10 +62,10 @@ public void test2019() { CVPipelineResult pipelineResult; pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResults(pipelineResult); - Assertions.assertTrue(pipelineResult.hasTargets()); - Assertions.assertEquals(2, pipelineResult.targets.size(), "Target count wrong!"); + assertTrue(pipelineResult.hasTargets()); + assertEquals(2, pipelineResult.targets.size(), "Target count wrong!"); TestUtils.showImage(pipelineResult.inputAndOutputFrame.colorImage.getMat(), "Pipeline output"); } @@ -84,7 +86,7 @@ public void test2020() { TestUtils.WPI2020Image.FOV); CVPipelineResult pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResults(pipelineResult); TestUtils.showImage( pipelineResult.inputAndOutputFrame.processedImage.getMat(), "Pipeline output"); @@ -95,7 +97,7 @@ private static void continuouslyRunPipeline(Frame frame, ReflectivePipelineSetti while (true) { CVPipelineResult pipelineResult = pipeline.run(frame, QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResults(pipelineResult); int preRelease = CVMat.getMatCount(); pipelineResult.release(); int postRelease = CVMat.getMatCount(); @@ -123,11 +125,4 @@ public static void main(String[] args) { continuouslyRunPipeline(frameProvider.get(), settings); } - - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.print( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " fps), "); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/SolvePNPTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/SolvePNPTest.java index b205a7f9d2..fad273df4a 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/SolvePNPTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/SolvePNPTest.java @@ -24,7 +24,6 @@ import edu.wpi.first.math.geometry.Rotation3d; import edu.wpi.first.math.geometry.Translation3d; import edu.wpi.first.math.util.Units; -import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.photonvision.common.util.TestUtils; @@ -38,7 +37,6 @@ import org.photonvision.vision.pipe.impl.HSVPipe; import org.photonvision.vision.pipeline.result.CVPipelineResult; import org.photonvision.vision.target.TargetModel; -import org.photonvision.vision.target.TrackedTarget; public class SolvePNPTest { private static final String LIFECAM_240P_CAL_FILE = "lifecam240p.json"; @@ -113,7 +111,7 @@ public void test2019() { frameProvider.requestHsvSettings(hsvParams); CVPipelineResult pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); // Draw on input var outputPipe = new OutputStreamPipeline(); @@ -168,7 +166,7 @@ public void test2020() { frameProvider.requestHsvSettings(hsvParams); CVPipelineResult pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); // Draw on input var outputPipe = new OutputStreamPipeline(); @@ -204,7 +202,7 @@ private static void continuouslyRunPipeline(Frame frame, ReflectivePipelineSetti while (true) { CVPipelineResult pipelineResult = pipeline.run(frame, QuirkyCamera.DefaultCamera); - printTestResults(pipelineResult); + TestUtils.printTestResultsWithLocation(pipelineResult); int preRelease = CVMat.getMatCount(); pipelineResult.release(); int postRelease = CVMat.getMatCount(); @@ -232,16 +230,4 @@ public static void main(String[] args) { continuouslyRunPipeline(frameProvider.get(), settings); } - - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.println( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " " + "fps)"); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - System.out.println( - "Found targets at " - + pipelineResult.targets.stream() - .map(TrackedTarget::getBestCameraToTarget3d) - .collect(Collectors.toList())); - } } diff --git a/photon-core/src/test/java/org/photonvision/vision/processes/PipelineManagerTest.java b/photon-core/src/test/java/org/photonvision/vision/processes/PipelineManagerTest.java index b90de65aed..3d229bdfe4 100644 --- a/photon-core/src/test/java/org/photonvision/vision/processes/PipelineManagerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/processes/PipelineManagerTest.java @@ -17,9 +17,10 @@ package org.photonvision.vision.processes; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.ArrayList; import java.util.List; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.photonvision.common.configuration.ConfigManager; @@ -62,7 +63,7 @@ public void testUniqueName() { for (int i = 2; i < 15; i++) { expected.add("Another (" + i + ")"); } - Assertions.assertEquals(expected, nicks); + assertEquals(expected, nicks); } @Test diff --git a/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java b/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java index 465cc9bc69..d718666774 100644 --- a/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java @@ -17,6 +17,7 @@ package org.photonvision.vision.processes; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -25,8 +26,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.photonvision.common.configuration.CameraConfiguration; @@ -189,8 +188,8 @@ public void setupManager() { sleep(1500); - Assertions.assertNotNull(module0DataConsumer.result); - printTestResults(module0DataConsumer.result); + assertNotNull(module0DataConsumer.result); + TestUtils.printTestResults(module0DataConsumer.result); } @Test @@ -233,15 +232,12 @@ public void testMultipleStreamIndex() { var modules = List.of(testSource, testSource2, testSource3, usbSimulation, usbSimulation2).stream() .map(vmm::addSource) - .collect(Collectors.toList()); + .toList(); System.out.println( Arrays.toString( modules.stream().map(it -> it.getCameraConfiguration().streamIndex).toArray())); - var idxs = - modules.stream() - .map(it -> it.getCameraConfiguration().streamIndex) - .collect(Collectors.toList()); + var idxs = modules.stream().map(it -> it.getCameraConfiguration().streamIndex).toList(); assertTrue(usbSimulation.equals(usbSimulation)); assertTrue(!usbSimulation.equals(usbSimulation2)); @@ -253,13 +249,6 @@ public void testMultipleStreamIndex() { assertTrue(idxs.contains(4)); } - private static void printTestResults(CVPipelineResult pipelineResult) { - double fps = 1000 / pipelineResult.getLatencyMillis(); - System.out.print( - "Pipeline ran in " + pipelineResult.getLatencyMillis() + "ms (" + fps + " fps), "); - System.out.println("Found " + pipelineResult.targets.size() + " valid targets"); - } - private void sleep(int millis) { try { Thread.sleep(millis); diff --git a/photon-core/src/test/java/org/photonvision/vision/target/TargetCalculationsTest.java b/photon-core/src/test/java/org/photonvision/vision/target/TargetCalculationsTest.java index 340b8c9939..c6aad210c8 100644 --- a/photon-core/src/test/java/org/photonvision/vision/target/TargetCalculationsTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/target/TargetCalculationsTest.java @@ -24,7 +24,6 @@ import edu.wpi.first.math.geometry.Translation3d; import java.util.List; import java.util.stream.Stream; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -316,9 +315,9 @@ public void testDualOffsetCrosshair() { Point crosshairPointOutside = TargetCalculations.calculateDualOffsetCrosshair(dualOffsetValues, 1); - Assertions.assertEquals(expectedHalfway.x, crosshairPointHalfway.x); - Assertions.assertEquals(expectedHalfway.y, crosshairPointHalfway.y); - Assertions.assertEquals(expectedOutside.x, crosshairPointOutside.x); - Assertions.assertEquals(expectedOutside.y, crosshairPointOutside.y); + assertEquals(expectedHalfway.x, crosshairPointHalfway.x); + assertEquals(expectedHalfway.y, crosshairPointHalfway.y); + assertEquals(expectedOutside.x, crosshairPointOutside.x); + assertEquals(expectedOutside.y, crosshairPointOutside.y); } } diff --git a/photon-lib/src/main/java/org/photonvision/PhotonCamera.java b/photon-lib/src/main/java/org/photonvision/PhotonCamera.java index a60ec848fa..198c387323 100644 --- a/photon-lib/src/main/java/org/photonvision/PhotonCamera.java +++ b/photon-lib/src/main/java/org/photonvision/PhotonCamera.java @@ -50,7 +50,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import org.opencv.core.Core; import org.photonvision.common.hardware.VisionLEDMode; import org.photonvision.common.networktables.PacketSubscriber; @@ -138,7 +137,7 @@ public PhotonCamera(NetworkTableInstance instance, String cameraName) { .getRawTopic("rawBytes") .subscribe( PhotonPipelineResult.photonStruct.getTypeString(), - new byte[] {}, + new byte[0], PubSubOption.periodic(0.01), PubSubOption.sendAll(true), PubSubOption.pollStorage(20)); @@ -175,65 +174,77 @@ public PhotonCamera(NetworkTableInstance instance, String cameraName) { } public static void verifyDependencies() { + // spotless:off if (!WPILibVersion.Version.equals(PhotonVersion.wpilibTargetVersion)) { - String bfw = - "\n\n\n\n\n" - + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" - + ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - + ">>> \n" - + ">>> You are running an incompatible version \n" - + ">>> of PhotonVision ! \n" - + ">>> \n" - + ">>> PhotonLib " - + PhotonVersion.versionString - + " is built for WPILib " - + PhotonVersion.wpilibTargetVersion - + "\n" - + ">>> but you are using WPILib " - + WPILibVersion.Version - + ">>> \n" - + ">>> This is neither tested nor supported. \n" - + ">>> You MUST update PhotonVision, \n" - + ">>> PhotonLib, or both. \n" - + ">>> Verify the output of `./gradlew dependencies` \n" - + ">>> \n" - + ">>> Your code will now crash. \n" - + ">>> We hope your day gets better. \n" - + ">>> \n" - + ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; + String bfw = """ + + + + + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s + >>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s + >>> \s + >>> You are running an incompatible version \s + >>> of PhotonVision ! \s + >>> \s + >>> PhotonLib """ + + PhotonVersion.versionString + + " is built for WPILib " + + PhotonVersion.wpilibTargetVersion + + "\n" + + ">>> but you are using WPILib " + + WPILibVersion.Version + + """ + >>> \s + >>> This is neither tested nor supported. \s + >>> You MUST update PhotonVision, \s + >>> PhotonLib, or both. \s + >>> Verify the output of `./gradlew dependencies` + >>> \s + >>> Your code will now crash. \s + >>> We hope your day gets better. \s + >>> \s + >>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s + """; DriverStation.reportWarning(bfw, false); DriverStation.reportError(bfw, false); throw new UnsupportedOperationException(bfw); } if (!Core.VERSION.equals(PhotonVersion.opencvTargetVersion)) { - String bfw = - "\n\n\n\n\n" - + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" - + ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - + ">>> \n" - + ">>> You are running an incompatible version \n" - + ">>> of PhotonVision ! \n" - + ">>> \n" - + ">>> PhotonLib " - + PhotonVersion.versionString - + " is built for OpenCV " - + PhotonVersion.opencvTargetVersion - + "\n" - + ">>> but you are using OpenCV " - + Core.VERSION - + ">>> \n" - + ">>> This is neither tested nor supported. \n" - + ">>> You MUST update PhotonVision, \n" - + ">>> PhotonLib, or both. \n" - + ">>> Verify the output of `./gradlew dependencies` \n" - + ">>> \n" - + ">>> Your code will now crash. \n" - + ">>> We hope your day gets better. \n" - + ">>> \n" - + ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; + String bfw = """ + + + + + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s + >>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s + >>> \s + >>> You are running an incompatible version \s + >>> of PhotonVision ! \s + >>> \s + >>> PhotonLib """ + + PhotonVersion.versionString + + " is built for OpenCV " + + PhotonVersion.opencvTargetVersion + + "\n" + + ">>> but you are using OpenCV " + + Core.VERSION + + """ + >>> \s + >>> This is neither tested nor supported. \s + >>> You MUST update PhotonVision, \s + >>> PhotonLib, or both. \s + >>> Verify the output of `./gradlew dependencies` + >>> \s + >>> Your code will now crash. \s + >>> We hope your day gets better. \s + >>> \s + >>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s + """; + // spotless:on DriverStation.reportWarning(bfw, false); DriverStation.reportError(bfw, false); @@ -533,23 +544,30 @@ else if (!isConnected()) { // Error on a verified version mismatch // But stay silent otherwise - String bfw = - "\n\n\n\n\n" - + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" - + ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - + ">>> \n" - + ">>> You are running an incompatible version \n" - + ">>> of PhotonVision on your coprocessor! \n" - + ">>> \n" - + ">>> This is neither tested nor supported. \n" - + ">>> You MUST update PhotonVision, \n" - + ">>> PhotonLib, or both. \n" - + ">>> \n" - + ">>> Your code will now crash. \n" - + ">>> We hope your day gets better. \n" - + ">>> \n" - + ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; + // spotless:off + String bfw = """ + + + + + + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + >>> \s + >>> You are running an incompatible version \s + >>> of PhotonVision on your coprocessor! \s + >>> \s + >>> This is neither tested nor supported. \s + >>> You MUST update PhotonVision, \s + >>> PhotonLib, or both. \s + >>> \s + >>> Your code will now crash. \s + >>> We hope your day gets better. \s + >>> \s + >>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + """; + // spotless:on DriverStation.reportWarning(bfw, false); var versionMismatchMessage = @@ -575,6 +593,6 @@ private List getTablesThatLookLikePhotonCameras() { it -> { return rootPhotonTable.getSubTable(it).getEntry("rawBytes").exists(); }) - .collect(Collectors.toList()); + .toList(); } } diff --git a/photon-lib/src/main/java/org/photonvision/simulation/SimCameraProperties.java b/photon-lib/src/main/java/org/photonvision/simulation/SimCameraProperties.java index f9b7f8a462..7e806e1593 100644 --- a/photon-lib/src/main/java/org/photonvision/simulation/SimCameraProperties.java +++ b/photon-lib/src/main/java/org/photonvision/simulation/SimCameraProperties.java @@ -171,7 +171,7 @@ public SimCameraProperties setCalibration(int resWidth, int resHeight, Rotation2 DriverStation.reportError( "Requested invalid FOV! Clamping between (1, 179) degrees...", false); } - double resDiag = Math.sqrt(resWidth * resWidth + resHeight * resHeight); + double resDiag = Math.hypot(resWidth, resHeight); double diagRatio = Math.tan(fovDiag.getRadians() / 2); var fovWidth = new Rotation2d(Math.atan(diagRatio * (resWidth / resDiag)) * 2); var fovHeight = new Rotation2d(Math.atan(diagRatio * (resHeight / resDiag)) * 2); @@ -202,24 +202,20 @@ public SimCameraProperties setCalibration( this.distCoeffs = distCoeffs; // left, right, up, and down view planes - var p = - new Translation3d[] { - new Translation3d( - 1, - new Rotation3d(0, 0, getPixelYaw(0).plus(new Rotation2d(-Math.PI / 2)).getRadians())), - new Translation3d( - 1, - new Rotation3d( - 0, 0, getPixelYaw(resWidth).plus(new Rotation2d(Math.PI / 2)).getRadians())), - new Translation3d( - 1, - new Rotation3d( - 0, getPixelPitch(0).plus(new Rotation2d(Math.PI / 2)).getRadians(), 0)), - new Translation3d( - 1, - new Rotation3d( - 0, getPixelPitch(resHeight).plus(new Rotation2d(-Math.PI / 2)).getRadians(), 0)) - }; + Translation3d[] p = { + new Translation3d( + 1, new Rotation3d(0, 0, getPixelYaw(0).plus(new Rotation2d(-Math.PI / 2)).getRadians())), + new Translation3d( + 1, + new Rotation3d( + 0, 0, getPixelYaw(resWidth).plus(new Rotation2d(Math.PI / 2)).getRadians())), + new Translation3d( + 1, new Rotation3d(0, getPixelPitch(0).plus(new Rotation2d(Math.PI / 2)).getRadians(), 0)), + new Translation3d( + 1, + new Rotation3d( + 0, getPixelPitch(resHeight).plus(new Rotation2d(-Math.PI / 2)).getRadians(), 0)) + }; viewplanes.clear(); for (Translation3d translation3d : p) { viewplanes.add( diff --git a/photon-lib/src/main/java/org/photonvision/simulation/VideoSimUtil.java b/photon-lib/src/main/java/org/photonvision/simulation/VideoSimUtil.java index 325a2ab2c8..89face6763 100644 --- a/photon-lib/src/main/java/org/photonvision/simulation/VideoSimUtil.java +++ b/photon-lib/src/main/java/org/photonvision/simulation/VideoSimUtil.java @@ -39,7 +39,6 @@ import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; -import org.opencv.core.MatOfByte; import org.opencv.core.MatOfPoint; import org.opencv.core.MatOfPoint2f; import org.opencv.core.Point; @@ -103,16 +102,8 @@ public static Point[] getImageCorners(Size size) { */ private static Mat get36h11TagImage(int id) { RawFrame frame = AprilTag.generate36h11AprilTagImage(id); - - var buf = frame.getData(); - byte[] arr = new byte[buf.remaining()]; - buf.get(arr); - // frame.close(); - - var mat = new MatOfByte(arr).reshape(1, 10).submat(new Rect(0, 0, 10, 10)); - mat.dump(); - - return mat; + return new Mat( + frame.getHeight(), frame.getWidth(), CvType.CV_8UC1, frame.getData(), frame.getStride()); } /** Gets the points representing the marker(black square) corners. */ diff --git a/photon-lib/src/main/java/org/photonvision/simulation/VisionSystemSim.java b/photon-lib/src/main/java/org/photonvision/simulation/VisionSystemSim.java index b61b939465..7aa7ff1c28 100644 --- a/photon-lib/src/main/java/org/photonvision/simulation/VisionSystemSim.java +++ b/photon-lib/src/main/java/org/photonvision/simulation/VisionSystemSim.java @@ -41,7 +41,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import org.photonvision.PhotonCamera; import org.photonvision.estimation.TargetModel; @@ -357,10 +356,7 @@ public void update(Pose3d robotPoseMeters) { entry -> dbgField .getObject(entry.getKey()) - .setPoses( - entry.getValue().stream() - .map(t -> t.getPose().toPose2d()) - .collect(Collectors.toList()))); + .setPoses(entry.getValue().stream().map(t -> t.getPose().toPose2d()).toList())); if (robotPoseMeters == null) return; diff --git a/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java b/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java index c25955480d..2f8e6c57d2 100644 --- a/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java +++ b/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java @@ -46,7 +46,6 @@ import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -95,7 +94,7 @@ public void teardown() { @Test public void testEmpty() { - Assertions.assertDoesNotThrow( + assertDoesNotThrow( () -> { var packet = new Packet(1); var ret = new PhotonPipelineResult(); diff --git a/photon-lib/src/test/java/org/photonvision/PhotonUtilTest.java b/photon-lib/src/test/java/org/photonvision/PhotonUtilTest.java index bbc70cf856..fbb632a91d 100644 --- a/photon-lib/src/test/java/org/photonvision/PhotonUtilTest.java +++ b/photon-lib/src/test/java/org/photonvision/PhotonUtilTest.java @@ -24,9 +24,10 @@ package org.photonvision; +import static org.junit.jupiter.api.Assertions.assertEquals; + import edu.wpi.first.math.geometry.*; import edu.wpi.first.math.util.Units; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; class PhotonUtilTest { @@ -40,7 +41,7 @@ public void testDistance() { var dist = PhotonUtils.calculateDistanceToTargetMeters(camHeight, targetHeight, camPitch, targetPitch); - Assertions.assertEquals(3.464, dist, 0.01); + assertEquals(3.464, dist, 0.01); camHeight = 1; targetHeight = 2; @@ -49,7 +50,7 @@ public void testDistance() { dist = PhotonUtils.calculateDistanceToTargetMeters(camHeight, targetHeight, camPitch, targetPitch); - Assertions.assertEquals(5.671, dist, 0.01); + assertEquals(5.671, dist, 0.01); } @Test @@ -75,9 +76,9 @@ public void testTransform() { fieldToTarget, cameraToRobot); - Assertions.assertEquals(-3.464, fieldToRobot.getX(), 0.1); - Assertions.assertEquals(0, fieldToRobot.getY(), 0.1); - Assertions.assertEquals(0, fieldToRobot.getRotation().getDegrees(), 0.1); + assertEquals(-3.464, fieldToRobot.getX(), 0.1); + assertEquals(0, fieldToRobot.getY(), 0.1); + assertEquals(0, fieldToRobot.getRotation().getDegrees(), 0.1); } @Test @@ -94,8 +95,8 @@ public void testAprilTagUtils() { new Translation2d(Units.inchesToMeters(324), Units.inchesToMeters(162)), new Rotation2d()); var currentPose = new Pose2d(0, 0, Rotation2d.fromDegrees(0)); - Assertions.assertEquals(4.0, fieldToRobot.getX()); - Assertions.assertEquals( + assertEquals(4.0, fieldToRobot.getX()); + assertEquals( Math.toDegrees(Math.atan2((Units.inchesToMeters(162)), (Units.inchesToMeters(324)))), PhotonUtils.getYawToPose(currentPose, targetPose).getDegrees()); } diff --git a/photon-lib/src/test/java/org/photonvision/PhotonVersionTest.java b/photon-lib/src/test/java/org/photonvision/PhotonVersionTest.java index 216a0536a1..f21c8957fc 100644 --- a/photon-lib/src/test/java/org/photonvision/PhotonVersionTest.java +++ b/photon-lib/src/test/java/org/photonvision/PhotonVersionTest.java @@ -25,10 +25,11 @@ package org.photonvision; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class PhotonVersionTest { @@ -52,11 +53,11 @@ public static boolean versionMatches(String versionString, String other) { @Test public void testVersion() { - Assertions.assertTrue(versionMatches("v2021.1.6", "v2021.1.6")); - Assertions.assertTrue(versionMatches("dev-v2021.1.6", "v2021.1.6")); - Assertions.assertTrue(versionMatches("dev-v2021.1.6-5-gca49ea50", "v2021.1.6")); - Assertions.assertFalse(versionMatches("", "v2021.1.6")); - Assertions.assertFalse(versionMatches("v2021.1.6", "")); + assertTrue(versionMatches("v2021.1.6", "v2021.1.6")); + assertTrue(versionMatches("dev-v2021.1.6", "v2021.1.6")); + assertTrue(versionMatches("dev-v2021.1.6-5-gca49ea50", "v2021.1.6")); + assertFalse(versionMatches("", "v2021.1.6")); + assertFalse(versionMatches("v2021.1.6", "")); } @Test diff --git a/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java b/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java index d4c324965c..9ba79d4633 100644 --- a/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java +++ b/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java @@ -24,6 +24,7 @@ package org.photonvision; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -50,7 +51,6 @@ import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -111,7 +111,7 @@ public void teardown() { @Test public void testEmpty() { - Assertions.assertDoesNotThrow( + assertDoesNotThrow( () -> { var sysUnderTest = new VisionSystemSim("Test"); sysUnderTest.addVisionTargets( diff --git a/photon-server/src/main/java/org/photonvision/server/DataSocketHandler.java b/photon-server/src/main/java/org/photonvision/server/DataSocketHandler.java index 67243f4a3c..848c7a4475 100644 --- a/photon-server/src/main/java/org/photonvision/server/DataSocketHandler.java +++ b/photon-server/src/main/java/org/photonvision/server/DataSocketHandler.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import edu.wpi.first.math.Pair; import io.javalin.websocket.WsBinaryMessageContext; import io.javalin.websocket.WsCloseContext; import io.javalin.websocket.WsConnectContext; @@ -33,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import org.apache.commons.lang3.tuple.Pair; import org.msgpack.jackson.dataformat.MessagePackFactory; import org.photonvision.common.dataflow.DataChangeDestination; import org.photonvision.common.dataflow.DataChangeService; @@ -112,14 +112,13 @@ public void onBinaryMessage(WsBinaryMessageContext context) { var socketMessageType = DataSocketMessageType.fromEntryKey(entryKey); logger.trace( - () -> - "Got WS message: [" - + socketMessageType - + "] ==> [" - + entryKey - + "], [" - + entryValue - + "]"); + "Got WS message: [" + + socketMessageType + + "] ==> [" + + entryKey + + "], [" + + entryValue + + "]"); if (socketMessageType == null) { logger.warn("Got unknown socket message type: " + entryKey); @@ -127,39 +126,30 @@ public void onBinaryMessage(WsBinaryMessageContext context) { } switch (socketMessageType) { - case SMT_DRIVERMODE -> { - // TODO: what is this event? - var data = (Boolean) entryValue; - var dmIsDriverEvent = - new IncomingWebSocketEvent( - DataChangeDestination.DCD_ACTIVEMODULE, - "isDriverMode", - data, - cameraUniqueName, - context); - - dcService.publishEvents(dmIsDriverEvent); - } - case SMT_CHANGECAMERANAME -> { - var ccnEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "cameraNickname", - (String) entryValue, - cameraUniqueName, - context); - dcService.publishEvent(ccnEvent); - } - case SMT_CHANGEPIPELINENAME -> { - var cpnEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "pipelineName", - (String) entryValue, - cameraUniqueName, - context); - dcService.publishEvent(cpnEvent); - } + case SMT_DRIVERMODE -> // TODO: what is this event? + dcService.publishEvents( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "isDriverMode", + (Boolean) entryValue, + cameraUniqueName, + context)); + case SMT_CHANGECAMERANAME -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "cameraNickname", + (String) entryValue, + cameraUniqueName, + context)); + case SMT_CHANGEPIPELINENAME -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "pipelineName", + (String) entryValue, + cameraUniqueName, + context)); case SMT_ADDNEWPIPELINE -> { // HashMap data = (HashMap) entryValue; // var type = (PipelineType) data.get("pipelineType"); @@ -168,109 +158,90 @@ public void onBinaryMessage(WsBinaryMessageContext context) { var name = (String) arr.get(0); var type = PipelineType.values()[(Integer) arr.get(1) + 2]; - var newPipelineEvent = + dcService.publishEvent( new IncomingWebSocketEvent<>( DataChangeDestination.DCD_ACTIVEMODULE, "newPipelineInfo", Pair.of(name, type), cameraUniqueName, - context); - dcService.publishEvent(newPipelineEvent); - } - case SMT_CHANGEBRIGHTNESS -> { - HardwareManager.getInstance() - .setBrightnessPercent(Integer.parseInt(entryValue.toString())); + context)); } + case SMT_CHANGEBRIGHTNESS -> + HardwareManager.getInstance() + .setBrightnessPercent(Integer.parseInt(entryValue.toString())); case SMT_DUPLICATEPIPELINE -> { var pipeIndex = (Integer) entryValue; logger.info("Duplicating pipe@index" + pipeIndex + " for camera " + cameraUniqueName); - var newPipelineEvent = + dcService.publishEvent( new IncomingWebSocketEvent<>( DataChangeDestination.DCD_ACTIVEMODULE, "duplicatePipeline", pipeIndex, cameraUniqueName, - context); - dcService.publishEvent(newPipelineEvent); - } - case SMT_DELETECURRENTPIPELINE -> { - var deleteCurrentPipelineEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "deleteCurrPipeline", - 0, - cameraUniqueName, - context); - dcService.publishEvent(deleteCurrentPipelineEvent); - } - case SMT_ROBOTOFFSETPOINT -> { - var robotOffsetPointEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "robotOffsetPoint", - (Integer) entryValue, - cameraUniqueName, - null); - dcService.publishEvent(robotOffsetPointEvent); - } - case SMT_CURRENTCAMERA -> { - var changeCurrentCameraEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_OTHER, "changeUICamera", (Integer) entryValue); - dcService.publishEvent(changeCurrentCameraEvent); - } - case SMT_CURRENTPIPELINE -> { - var changePipelineEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "changePipeline", - (Integer) entryValue, - cameraUniqueName, - context); - dcService.publishEvent(changePipelineEvent); - } - case SMT_STARTPNPCALIBRATION -> { - var changePipelineEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "startCalibration", - (Map) entryValue, - cameraUniqueName, - context); - dcService.publishEvent(changePipelineEvent); - } - case SMT_SAVEINPUTSNAPSHOT -> { - var takeInputSnapshotEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "saveInputSnapshot", - 0, - cameraUniqueName, - context); - dcService.publishEvent(takeInputSnapshotEvent); - } - case SMT_SAVEOUTPUTSNAPSHOT -> { - var takeOutputSnapshotEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "saveOutputSnapshot", - 0, - cameraUniqueName, - context); - dcService.publishEvent(takeOutputSnapshotEvent); - } - case SMT_TAKECALIBRATIONSNAPSHOT -> { - var takeCalSnapshotEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "takeCalSnapshot", - 0, - cameraUniqueName, - context); - dcService.publishEvent(takeCalSnapshotEvent); + context)); } + case SMT_DELETECURRENTPIPELINE -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "deleteCurrPipeline", + 0, + cameraUniqueName, + context)); + case SMT_ROBOTOFFSETPOINT -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "robotOffsetPoint", + (Integer) entryValue, + cameraUniqueName, + null)); + case SMT_CURRENTCAMERA -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_OTHER, "changeUICamera", (Integer) entryValue)); + case SMT_CURRENTPIPELINE -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "changePipeline", + (Integer) entryValue, + cameraUniqueName, + context)); + case SMT_STARTPNPCALIBRATION -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "startCalibration", + (Map) entryValue, + cameraUniqueName, + context)); + case SMT_SAVEINPUTSNAPSHOT -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "saveInputSnapshot", + 0, + cameraUniqueName, + context)); + case SMT_SAVEOUTPUTSNAPSHOT -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "saveOutputSnapshot", + 0, + cameraUniqueName, + context)); + case SMT_TAKECALIBRATIONSNAPSHOT -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "takeCalSnapshot", + 0, + cameraUniqueName, + context)); case SMT_PIPELINESETTINGCHANGE -> { HashMap data = (HashMap) entryValue; @@ -280,29 +251,26 @@ public void onBinaryMessage(WsBinaryMessageContext context) { if (dataEntry.getKey().equals("cameraUniqueName")) { continue; } - var pipelineSettingChangeEvent = + dcService.publishEvent( new IncomingWebSocketEvent( DataChangeDestination.DCD_ACTIVEPIPELINESETTINGS, dataEntry.getKey(), dataEntry.getValue(), cameraIndex2, - context); - dcService.publishEvent(pipelineSettingChangeEvent); + context)); } } else { logger.warn("Unknown message for PSC: " + data.keySet().iterator().next()); } } - case SMT_CHANGEPIPELINETYPE -> { - var changePipelineEvent = - new IncomingWebSocketEvent<>( - DataChangeDestination.DCD_ACTIVEMODULE, - "changePipelineType", - (Integer) entryValue, - cameraUniqueName, - context); - dcService.publishEvent(changePipelineEvent); - } + case SMT_CHANGEPIPELINETYPE -> + dcService.publishEvent( + new IncomingWebSocketEvent<>( + DataChangeDestination.DCD_ACTIVEMODULE, + "changePipelineType", + (Integer) entryValue, + cameraUniqueName, + context)); } } catch (Exception e) { logger.error("Failed to parse message!", e); diff --git a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java index 6becc00004..f734f38ef6 100644 --- a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java +++ b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java @@ -641,7 +641,7 @@ public static void onMetricsPublishRequest(Context ctx) { } public static void onCalibrationSnapshotRequest(Context ctx) { - logger.info(ctx.queryString().toString()); + logger.info(ctx.queryString()); String cameraUniqueName = ctx.queryParam("cameraUniqueName"); var width = Integer.parseInt(ctx.queryParam("width")); @@ -695,7 +695,7 @@ public static void onCalibrationSnapshotRequest(Context ctx) { } public static void onCalibrationExportRequest(Context ctx) { - logger.info(ctx.queryString().toString()); + logger.info(ctx.queryString()); String cameraUniqueName = ctx.queryParam("cameraUniqueName"); var width = Integer.parseInt(ctx.queryParam("width")); @@ -900,7 +900,7 @@ public static void onNukeOneCamera(Context ctx) { } public static void onActivateMatchedCameraRequest(Context ctx) { - logger.info(ctx.queryString().toString()); + logger.info(ctx.queryString()); String cameraUniqueName = ctx.queryParam("cameraUniqueName"); @@ -914,7 +914,7 @@ public static void onActivateMatchedCameraRequest(Context ctx) { } public static void onAssignUnmatchedCameraRequest(Context ctx) { - logger.info(ctx.queryString().toString()); + logger.info(ctx.queryString()); PVCameraInfo camera; try { @@ -934,7 +934,7 @@ public static void onAssignUnmatchedCameraRequest(Context ctx) { } public static void onUnassignCameraRequest(Context ctx) { - logger.info(ctx.queryString().toString()); + logger.info(ctx.queryString()); String cameraUniqueName = ctx.queryParam("cameraUniqueName"); diff --git a/photon-targeting/src/main/java/org/photonvision/estimation/VisionEstimation.java b/photon-targeting/src/main/java/org/photonvision/estimation/VisionEstimation.java index 6031ec337b..afd3f4c3a9 100644 --- a/photon-targeting/src/main/java/org/photonvision/estimation/VisionEstimation.java +++ b/photon-targeting/src/main/java/org/photonvision/estimation/VisionEstimation.java @@ -248,13 +248,12 @@ public static Optional estimateRobotPoseConstrainedSolvepnp( } // fx fy cx cy - double[] cameraCal = - new double[] { - cameraMatrix.get(0, 0), - cameraMatrix.get(1, 1), - cameraMatrix.get(0, 2), - cameraMatrix.get(1, 2), - }; + double[] cameraCal = { + cameraMatrix.get(0, 0), + cameraMatrix.get(1, 1), + cameraMatrix.get(0, 2), + cameraMatrix.get(1, 2), + }; var guess2 = robotPoseSeed.toPose2d(); diff --git a/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java b/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java index fd7c1f1eb1..40acdf2a95 100644 --- a/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java +++ b/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java @@ -50,10 +50,9 @@ public static void teardown() { @Test public void smoketest() { - double[] cameraCal = - new double[] { - 600, 600, 300, 150, - }; + double[] cameraCal = { + 600, 600, 300, 150, + }; var field2points = MatBuilder.fill( @@ -86,7 +85,7 @@ public void smoketest() { MatBuilder.fill(Nat.N4(), Nat.N4(), 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1); // Initial guess for optimization - double[] x_guess = new double[] {0.2, 0.1, -.05}; + double[] x_guess = {0.2, 0.1, -.05}; var ret = ConstrainedSolvepnpJni.do_optimization( diff --git a/photon-targeting/src/test/java/jni/FileLoggerTest.java b/photon-targeting/src/test/java/jni/FileLoggerTest.java index 157ee9f1e2..f974825b38 100644 --- a/photon-targeting/src/test/java/jni/FileLoggerTest.java +++ b/photon-targeting/src/test/java/jni/FileLoggerTest.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package wpiutil_extras; +package jni; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assumptions.assumeTrue; diff --git a/shared/common.gradle b/shared/common.gradle index 62aa78daed..6a0cf794ca 100644 --- a/shared/common.gradle +++ b/shared/common.gradle @@ -44,8 +44,6 @@ dependencies { implementation "commons-io:commons-io:2.11.0" implementation "commons-cli:commons-cli:1.5.0" - implementation "org.apache.commons:commons-lang3:3.12.0" - implementation "org.apache.commons:commons-collections4:4.4" implementation "org.apache.commons:commons-exec:1.3" testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'