[photon-core] [NFC] Code Cleanup, spelling, and grammar (#945)

This commit is contained in:
Sriman Achanta
2023-10-15 12:31:23 -04:00
committed by GitHub
parent 9991f8670c
commit 760de0ff86
81 changed files with 261 additions and 305 deletions

View File

@@ -28,7 +28,8 @@ import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.*;
import java.util.Date;
import java.util.List;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.file.FileUtils;
@@ -47,13 +48,13 @@ public class ConfigManager {
private final ConfigProvider m_provider;
private Thread settingsSaveThread;
private final Thread settingsSaveThread;
private long saveRequestTimestamp = -1;
enum ConfigSaveStrategy {
SQL,
LEGACY,
ATOMIC_ZIP;
ATOMIC_ZIP
}
// This logic decides which kind of ConfigManager we load as the default. If we want
@@ -115,9 +116,8 @@ public class ConfigManager {
e1.printStackTrace();
}
// So we can't save the old config, and we couldn't copy the folder
// But we've loaded the config. So just try to delete the directory so we don't try to load
// form it next time. That does mean we have no backup recourse, tho
// Delete the directory because we were successfully able to load the config but were unable
// to save or copy the folder.
if (maybeCams.exists()) FileUtils.deleteDirectory(maybeCams.toPath());
}
@@ -225,7 +225,7 @@ public class ConfigManager {
}
public Date logFnameToDate(String fname) throws ParseException {
// Strip away known unneded portions of the log file name
// Strip away known unneeded portions of the log file name
fname = fname.replace(LOG_PREFIX, "").replace(LOG_EXT, "");
DateFormat format = new SimpleDateFormat(LOG_DATE_TIME_FORMAT);
return format.parse(fname);

View File

@@ -55,7 +55,7 @@ class LegacyConfigProvider extends ConfigProvider {
final File configDirectoryFile;
private long saveRequestTimestamp = -1;
private Thread settingsSaveThread;
private final Thread settingsSaveThread;
public static void saveUploadedSettingsZip(File uploadPath) {
var folderPath = Path.of(System.getProperty("java.io.tmpdir"), "photonvision").toFile();
@@ -67,7 +67,6 @@ class LegacyConfigProvider extends ConfigProvider {
logger.info("Copied settings successfully!");
} catch (IOException e) {
logger.error("Exception copying uploaded settings!", e);
return;
}
}
@@ -371,7 +370,7 @@ class LegacyConfigProvider extends ConfigProvider {
}
public Date logFnameToDate(String fname) throws ParseException {
// Strip away known unneded portions of the log file name
// Strip away known unneeded portions of the log file name
fname = fname.replace(LOG_PREFIX, "").replace(LOG_EXT, "");
DateFormat format = new SimpleDateFormat(LOG_DATE_TIME_FORMAT);
return format.parse(fname);

View File

@@ -30,7 +30,7 @@ import org.photonvision.common.networking.NetworkUtils;
import org.photonvision.common.util.file.JacksonUtils;
public class NetworkConfig {
// Can be a integer team number, or a IP address
// Can be an integer team number, or an IP address
public String ntServerAddress = "0";
public NetworkMode connectionType = NetworkMode.DHCP;
public String staticIp = "";
@@ -58,7 +58,7 @@ public class NetworkConfig {
.orElse("Wired connection 1");
}
// We can (usually) manage networking on Linux devices, and if we can we should try to. Command
// We can (usually) manage networking on Linux devices, and if we can, we should try to. Command
// line inhibitions happen at a level above this class
setShouldManage(deviceCanManageNetwork());
}

View File

@@ -33,10 +33,10 @@ import org.photonvision.vision.processes.VisionSource;
// TODO rename this class
public class PhotonConfiguration {
private HardwareConfig hardwareConfig;
private HardwareSettings hardwareSettings;
private final HardwareConfig hardwareConfig;
private final HardwareSettings hardwareSettings;
private NetworkConfig networkConfig;
private HashMap<String, CameraConfiguration> cameraConfigurations;
private final HashMap<String, CameraConfiguration> cameraConfigurations;
public PhotonConfiguration(
HardwareConfig hardwareConfig,
@@ -113,7 +113,7 @@ public class PhotonConfiguration {
var lightingConfig = new UILightingConfig();
lightingConfig.brightness = hardwareSettings.ledBrightnessPercentage;
lightingConfig.supported = (hardwareConfig.ledPins.size() != 0);
lightingConfig.supported = !hardwareConfig.ledPins.isEmpty();
settingsSubmap.put("lighting", SerializationUtils.objectToHashMap(lightingConfig));
var generalSubmap = new HashMap<String, Object>();

View File

@@ -21,11 +21,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -255,8 +251,7 @@ public class SqlConfigProvider extends ConfigProvider {
var result = query.executeQuery();
while (result.next()) {
var contents = result.getString("contents");
return contents;
return result.getString("contents");
}
} catch (SQLException e) {
logger.error("SQL Err getting file " + filename, e);
@@ -286,7 +281,7 @@ public class SqlConfigProvider extends ConfigProvider {
statement.setString(2, JacksonUtils.serializeToString(config));
statement.setString(3, JacksonUtils.serializeToString(config.driveModeSettings));
// Serializing a list of abstract classes sucks. Instead, make it into a array
// Serializing a list of abstract classes sucks. Instead, make it into an array
// of strings, which we can later unpack back into individual settings
List<String> settings =
config.pipelineSettings.stream()
@@ -424,7 +419,7 @@ public class SqlConfigProvider extends ConfigProvider {
private HashMap<String, CameraConfiguration> loadCameraConfigs(Connection conn) {
HashMap<String, CameraConfiguration> loadedConfigurations = new HashMap<>();
// Querry every single row of the cameras db
// Query every single row of the cameras db
PreparedStatement query = null;
try {
query =

View File

@@ -21,7 +21,6 @@ import java.util.List;
import java.util.Objects;
import org.photonvision.common.dataflow.events.DataChangeEvent;
@SuppressWarnings("rawtypes")
public abstract class DataChangeSubscriber {
public final List<DataChangeSource> wantedSources;
public final List<DataChangeDestination> wantedDestinations;

View File

@@ -41,7 +41,7 @@ public class NTDataPublisher implements CVPipelineResultConsumer {
private final NetworkTable rootTable = NetworkTablesManager.getInstance().kRootTable;
private NTTopicSet ts = new NTTopicSet();
private final NTTopicSet ts = new NTTopicSet();
NTDataChangeListener pipelineIndexListener;
private final Supplier<Integer> pipelineIndexSupplier;
@@ -181,15 +181,12 @@ public class NTDataPublisher implements CVPipelineResultConsumer {
}
// Something in the result can sometimes be null -- so check probably too many things
if (result != null
&& result.inputAndOutputFrame != null
if (result.inputAndOutputFrame != null
&& result.inputAndOutputFrame.frameStaticProperties != null
&& result.inputAndOutputFrame.frameStaticProperties.cameraCalibration != null) {
var fsp = result.inputAndOutputFrame.frameStaticProperties;
if (fsp.cameraCalibration != null) {
ts.cameraIntrinsicsPublisher.accept(fsp.cameraCalibration.getIntrinsicsArr());
ts.cameraDistortionPublisher.accept(fsp.cameraCalibration.getExtrinsicsArr());
}
ts.cameraIntrinsicsPublisher.accept(fsp.cameraCalibration.getIntrinsicsArr());
ts.cameraDistortionPublisher.accept(fsp.cameraCalibration.getExtrinsicsArr());
} else {
ts.cameraIntrinsicsPublisher.accept(new double[] {});
ts.cameraDistortionPublisher.accept(new double[] {});
@@ -215,8 +212,8 @@ public class NTDataPublisher implements CVPipelineResultConsumer {
}
{
var points = t.getTargetCorners();
for (int i = 0; i < points.size(); i++) {
detectedCorners.add(new TargetCorner(points.get(i).x, points.get(i).y));
for (Point point : points) {
detectedCorners.add(new TargetCorner(point.x, point.y));
}
}

View File

@@ -121,7 +121,7 @@ public class NetworkTablesManager {
ntInstance.stopServer();
ntInstance.startClient4("photonvision");
try {
Integer t = Integer.parseInt(ntServerAddress);
int t = Integer.parseInt(ntServerAddress);
if (!isRetryingConnection) logger.info("Starting NT Client, server team is " + t);
ntInstance.setServerTeam(t);
} catch (NumberFormatException e) {

View File

@@ -17,8 +17,6 @@
package org.photonvision.common.hardware.GPIO.pi;
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.*;
import org.photonvision.common.hardware.GPIO.GPIOBase;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;

View File

@@ -18,7 +18,6 @@
package org.photonvision.common.hardware.GPIO.pi;
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.*;
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.PI_NO_WAVEFORM_ID;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -149,7 +148,7 @@ public class PigpioSocket {
// ## extension ##
// III on/off/delay * pulses
if (pulses == null || pulses.size() == 0) return 0;
if (pulses == null || pulses.isEmpty()) return 0;
try {
ByteBuffer bb = ByteBuffer.allocate(pulses.size() * 12);

View File

@@ -48,9 +48,9 @@ public class HardwareManager {
private final StatusLED statusLED;
@SuppressWarnings("FieldCanBeLocal")
private IntegerSubscriber ledModeRequest;
private final IntegerSubscriber ledModeRequest;
private IntegerPublisher ledModeState;
private final IntegerPublisher ledModeState;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private final NTDataChangeListener ledModeListener;

View File

@@ -34,7 +34,7 @@ public enum PiVersion {
private static final ShellExec shell = new ShellExec(true, false);
private static final PiVersion currentPiVersion = calcPiVersion();
private PiVersion(String s) {
PiVersion(String s) {
this.identifier = s.toLowerCase();
}

View File

@@ -17,7 +17,6 @@
package org.photonvision.common.hardware;
import com.jogamp.common.os.Platform.OSType;
import edu.wpi.first.util.RuntimeDetector;
import java.io.BufferedReader;
import java.io.IOException;

View File

@@ -46,7 +46,7 @@ public class VisionLED {
private int mappedBrightnessPercentage;
private Consumer<Integer> modeConsumer;
private final Consumer<Integer> modeConsumer;
public VisionLED(
List<Integer> ledPins,
@@ -179,11 +179,7 @@ public class VisionLED {
}
currentLedMode = newLedMode;
logger.info(
"Changing LED mode from \""
+ lastLedMode.toString()
+ "\" to \""
+ newLedMode.toString()
+ "\"");
"Changing LED mode from \"" + lastLedMode.toString() + "\" to \"" + newLedMode + "\"");
} else {
if (currentLedMode == VisionLEDMode.kDefault) {
switch (newLedMode) {

View File

@@ -37,7 +37,7 @@ public class MetricsManager {
CmdBase cmds;
private ShellExec runCommand = new ShellExec(true, true);
private final ShellExec runCommand = new ShellExec(true, true);
public void setConfig(HardwareConfig config) {
if (config.hasCommandsConfigured()) {
@@ -153,8 +153,8 @@ public class MetricsManager {
+ "\nExit code: "
+ runCommand.getExitCode()
+ "\n Exception: "
+ e.toString()
+ sw.toString());
+ e
+ sw);
return "";
}
}

View File

@@ -35,6 +35,6 @@ public class CmdBase {
public String diskUsageCommand = "";
public void initCmds(HardwareConfig config) {
return; // default - do nothing
// default - do nothing
}
}

View File

@@ -21,12 +21,7 @@ import java.io.*;
import java.nio.file.Path;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import org.photonvision.common.configuration.ConfigManager;
@@ -54,7 +49,7 @@ public class Logger {
private static final List<Pair<String, LogLevel>> uiBacklog = new ArrayList<>();
private static boolean connected = false;
private static UILogAppender uiLogAppender = new UILogAppender();
private static final UILogAppender uiLogAppender = new UILogAppender();
private final String className;
private final LogGroup group;
@@ -133,7 +128,7 @@ public class Logger {
HashMap<File, Date> logFileStartDateMap = new HashMap<>();
// Remove any files from the list for which we can't parse a start date from their name.
// Simultaneously populate our HashMap with Date objects repeseting the file-name
// Simultaneously populate our HashMap with Date objects representing the file-name
// indicated log start time.
logFileList.removeIf(
(File arg0) -> {
@@ -160,7 +155,6 @@ public class Logger {
if (logCounter < MAX_LOGS_TO_KEEP) {
// Skip over the first MAX_LOGS_TO_KEEP files
logCounter++;
continue;
} else {
// Delete this file.
file.delete();
@@ -332,7 +326,7 @@ public class Logger {
3000L);
} catch (FileNotFoundException e) {
out = null;
System.err.println("Unable to log to file " + logFilePath.toString());
System.err.println("Unable to log to file " + logFilePath);
}
}

View File

@@ -54,7 +54,7 @@ public class NetworkManager {
}
// always set hostname
if (config.hostname.length() > 0) {
if (!config.hostname.isEmpty()) {
try {
var shell = new ShellExec(true, false);
shell.executeBashCommand("cat /etc/hostname | tr -d \" \\t\\n\\r\"");
@@ -107,7 +107,7 @@ public class NetworkManager {
}
} else if (config.connectionType == NetworkMode.STATIC) {
var shell = new ShellExec();
if (config.staticIp.length() > 0) {
if (!config.staticIp.isEmpty()) {
try {
shell.executeBashCommand(
config
@@ -116,7 +116,7 @@ public class NetworkManager {
.replace(NetworkConfig.NM_IP_STRING, config.staticIp));
if (Platform.isRaspberryPi()) {
// Pi's need to manually have their interface adjusted?? and the 5 second sleep is
// Pi's need to manually have their interface adjusted?? and the 5-second sleep is
// integral in my testing (Matt)
shell.executeBashCommand(
"sh -c 'nmcli con down "
@@ -125,7 +125,7 @@ public class NetworkManager {
+ config.getEscapedInterfaceName()
+ "'");
} else {
// for now just bring down /up -- more testing needed on beelink et al
// for now just bring down /up -- more testing needed on beelink et al.
shell.executeBashCommand(
"sh -c 'nmcli con down "
+ config.getEscapedInterfaceName()

View File

@@ -31,12 +31,12 @@ import org.photonvision.common.util.ShellExec;
public class NetworkUtils {
private static final Logger logger = new Logger(NetworkUtils.class, LogGroup.General);
public static enum NMType {
public enum NMType {
NMTYPE_ETHERNET("ethernet"),
NMTYPE_WIFI("wifi"),
NMTYPE_UNKNOWN("");
private NMType(String id) {
NMType(String id) {
identifier = id;
}
@@ -59,7 +59,7 @@ public class NetworkUtils {
nmType = NMType.typeForString(type);
}
public final String connName; // Human readable name used by "nmcli con"
public final String connName; // Human-readable name used by "nmcli con"
public final String devName; // underlying device, used by dhclient
public final NMType nmType;
@@ -108,15 +108,15 @@ public class NetworkUtils {
logger.error("Could not get active NM ifaces!", e);
}
logger.debug("Found network interfaces:\n" + ret.toString());
logger.debug("Found network interfaces:\n" + ret);
allInterfaces = ret;
return ret;
}
public static List<NMDeviceInfo> getAllActiveInterfaces() {
// Seems like if a 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
// 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());

View File

@@ -42,7 +42,7 @@ public class RoborioFinder {
public void findRios() {
HashMap<String, Object> map = new HashMap<>();
var subMap = new HashMap<String, Object>();
// Seperate from the above so we don't hold stuff up
// Separate from the above so we don't hold stuff up
System.setProperty("java.net.preferIPv4Stack", "true");
subMap.put(
"deviceips",

View File

@@ -22,12 +22,13 @@ import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
/** Execute external process and optionally read output buffer. */
@SuppressWarnings({"unused", "ConstantConditions"})
@SuppressWarnings({"unused"})
public class ShellExec {
private static final Logger logger = new Logger(ShellExec.class, LogGroup.General);
private int exitCode;
private boolean readOutput, readError;
private final boolean readOutput;
private final boolean readError;
private StreamGobbler errorGobbler, outputGobbler;
public ShellExec() {
@@ -55,7 +56,7 @@ public class ShellExec {
boolean success = false;
Runtime r = Runtime.getRuntime();
// Use bash -c so we can handle things like multi commands separated by ; and
// Use bash -c, so we can handle things like multi commands separated by ; and
// things like quotes, $, |, and \. My tests show that command comes as
// one argument to bash, so we do not need to quote it to make it one thing.
// Also, exec may object if it does not have an executable file as the first thing,
@@ -160,8 +161,8 @@ public class ShellExec {
*/
@SuppressWarnings("WeakerAccess")
private static class StreamGobbler extends Thread {
private InputStream is;
private StringBuilder output;
private final InputStream is;
private final StringBuilder output;
private volatile boolean completed; // mark volatile to guarantee a thread safety
public StreamGobbler(InputStream is, boolean readStream) {

View File

@@ -245,7 +245,7 @@ public class TestUtils {
}
public static Path getResourcesFolderPath(boolean testMode) {
System.out.println("CWD: " + Path.of("").toAbsolutePath().toString());
System.out.println("CWD: " + Path.of("").toAbsolutePath());
// VSCode likes to make this path relative to the wrong root directory, so a fun hack to tell
// if it's wrong
@@ -362,7 +362,7 @@ public class TestUtils {
return getCoeffs("laptop.json", true);
}
private static int DefaultTimeoutMillis = 5000;
private static final int DefaultTimeoutMillis = 5000;
public static void showImage(Mat frame, String title, int timeoutMs) {
if (frame.empty()) return;

View File

@@ -40,9 +40,7 @@ public class TimedTaskManager {
public Thread newThread(@NotNull Runnable r) {
Thread thread = defaultThreadFactory.newThread(r);
thread.setUncaughtExceptionHandler(
(t, e) -> {
logger.error("TimedTask threw uncaught exception!", e);
});
(t, e) -> logger.error("TimedTask threw uncaught exception!", e));
return thread;
}
}

View File

@@ -20,11 +20,7 @@ package org.photonvision.common.util.math;
import edu.wpi.first.math.MatBuilder;
import edu.wpi.first.math.Nat;
import edu.wpi.first.math.VecBuilder;
import edu.wpi.first.math.geometry.CoordinateSystem;
import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Quaternion;
import edu.wpi.first.math.geometry.Rotation3d;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.math.geometry.*;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.util.WPIUtilJNI;
import java.util.Arrays;
@@ -92,7 +88,7 @@ public class MathUtils {
throw new IllegalArgumentException("invalid quantile value: " + p);
}
if (list.size() == 0) {
if (list.isEmpty()) {
return Double.NaN;
}
if (list.size() == 1) {
@@ -206,7 +202,7 @@ public class MathUtils {
new Rotation3d(VecBuilder.fill(1, 0, 0), Units.degreesToRadians(180));
/**
* Apply a 180 degree rotation about X to the rotation component of a given Apriltag pose. This
* Apply a 180-degree rotation about X to the rotation component of a given Apriltag pose. This
* aligns it with the OpenCV poses we use in other places.
*/
public static Transform3d convertApriltagtoOpenCV(Transform3d pose) {

View File

@@ -60,11 +60,7 @@ public abstract class NumberCouple<T extends Number> {
return false;
}
if (!couple.second.equals(second)) {
return false;
}
return true;
return couple.second.equals(second);
}
@JsonIgnore

View File

@@ -28,7 +28,7 @@ import org.photonvision.common.logging.Logger;
public class LibCameraJNI {
private static boolean libraryLoaded = false;
private static Logger logger = new Logger(LibCameraJNI.class, LogGroup.Camera);
private static final Logger logger = new Logger(LibCameraJNI.class, LogGroup.Camera);
public static final Object CAMERA_LOCK = new Object();
@@ -120,7 +120,7 @@ public class LibCameraJNI {
/**
* Starts the camera thresholder and display threads running. Make sure that this function is
* called syncronously with stopCamera and returnFrame!
* called synchronously with stopCamera and returnFrame!
*/
public static native boolean startCamera();
@@ -141,7 +141,7 @@ public class LibCameraJNI {
// Exposure time, in microseconds
public static native boolean setExposure(int exposureUs);
// Set brighness on [-1, 1]
// Set brightness on [-1, 1]
public static native boolean setBrightness(double brightness);
// Unknown ranges for red and blue AWB gain
@@ -164,18 +164,18 @@ public class LibCameraJNI {
// Analog gain multiplier to apply to all color channels, on [1, Big Number]
public static native boolean setAnalogGain(double analog);
/** Block until a new frame is avaliable from native code. */
/** Block until a new frame is available from native code. */
public static native boolean awaitNewFrame();
/**
* Get a pointer to the most recent color mat generated. Call this immediatly after awaitNewFrame,
* and call onlly once per new frame!
* Get a pointer to the most recent color mat generated. Call this immediately after
* awaitNewFrame, and call only once per new frame!
*/
public static native long takeColorFrame();
/**
* Get a pointer to the most recent processed mat generated. Call this immediatly after
* awaitNewFrame, and call onlly once per new frame!
* Get a pointer to the most recent processed mat generated. Call this immediately after
* awaitNewFrame, and call only once per new frame!
*/
public static native long takeProcessedFrame();
@@ -186,6 +186,6 @@ public class LibCameraJNI {
public static native int getGpuProcessType();
// /** Release a frame pointer back to the libcamera driver code to be filled again */
// Release a frame pointer back to the libcamera driver code to be filled again */
// public static native long returnFrame(long frame);
}

View File

@@ -28,7 +28,7 @@ public enum AprilTagFamily {
kTagCustom48h11;
public String getNativeName() {
// We wanna strip the leading kT and replace with "t"
// We want to strip the leading kT and replace with "t"
return this.name().replaceFirst("kT", "t");
}
}

View File

@@ -48,9 +48,9 @@ public class ArucoDetectorParams {
logger.info("Setting decimation from " + m_decimate + " to " + decimate);
// We only need to mutate the parameters -- the detector keeps a poitner to the parameters
// We only need to mutate the parameters -- the detector keeps a pointer to the parameters
// object internally, so it should automatically update
parameters.set_aprilTagQuadDecimate((float) decimate);
parameters.set_aprilTagQuadDecimate(decimate);
m_decimate = decimate;
}

View File

@@ -58,7 +58,7 @@ public class PhotonArucoDetector {
ids = new Mat();
tvecs = new Mat();
rvecs = new Mat();
corners = new ArrayList<Mat>();
corners = new ArrayList<>();
tagPose = new Pose3d();
translation = new Translation3d();
rotation = new Rotation3d();

View File

@@ -35,7 +35,7 @@ public class FileVisionSource extends VisionSource {
public FileVisionSource(CameraConfiguration cameraConfiguration) {
super(cameraConfiguration);
var calibration =
cameraConfiguration.calibrations.size() > 0
!cameraConfiguration.calibrations.isEmpty()
? cameraConfiguration.calibrations.get(0)
: null;
frameProvider =

View File

@@ -132,7 +132,7 @@ public class LibcameraGpuSettables extends VisionSourceSettables {
// If we set exposure too low, libcamera crashes or slows down
// Very weird and smelly
// For now, band-aid this by just not setting it lower than the "it breaks" limit
// Limit is different depending on camera.
// is different depending on camera.
if (sensorModel == LibCameraJNI.SensorModel.OV9281) {
if (exposure < 6.0) {
exposure = 6.0;

View File

@@ -105,7 +105,7 @@ public class QuirkyCamera {
public static QuirkyCamera getQuirkyCamera(int usbVid, int usbPid, String baseName) {
for (var qc : quirkyCameras) {
boolean hasBaseName = !qc.baseName.equals("");
boolean hasBaseName = !qc.baseName.isEmpty();
boolean matchesBaseName = qc.baseName.equals(baseName) || !hasBaseName;
if (qc.usbVid == usbVid && qc.usbPid == usbPid && matchesBaseName) {
return qc;

View File

@@ -18,7 +18,10 @@
package org.photonvision.vision.camera;
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.cscore.*;
import edu.wpi.first.cscore.CvSink;
import edu.wpi.first.cscore.UsbCamera;
import edu.wpi.first.cscore.VideoException;
import edu.wpi.first.cscore.VideoMode;
import java.util.*;
import java.util.stream.Collectors;
import org.photonvision.common.configuration.CameraConfiguration;
@@ -120,8 +123,8 @@ public class USBCameraSource extends VisionSource {
if (!cameraAutoExposure) {
// Pick a bunch of reasonable setting defaults for vision processing retroreflective
camera.getProperty("auto_exposure_bias").set(0);
camera.getProperty("iso_sensitivity_auto").set(0); // Disable auto ISO adjustement
camera.getProperty("iso_sensitivity").set(0); // Manual ISO adjustement
camera.getProperty("iso_sensitivity_auto").set(0); // Disable auto ISO adjustment
camera.getProperty("iso_sensitivity").set(0); // Manual ISO adjustment
camera.getProperty("white_balance_auto_preset").set(2); // Auto white-balance disabled
camera.getProperty("auto_exposure").set(1); // auto exposure disabled
} else {
@@ -129,7 +132,7 @@ public class USBCameraSource extends VisionSource {
// nice-for-humans
camera.getProperty("auto_exposure_bias").set(12);
camera.getProperty("iso_sensitivity_auto").set(1);
camera.getProperty("iso_sensitivity").set(1); // Manual ISO adjustement by default
camera.getProperty("iso_sensitivity").set(1); // Manual ISO adjustment by default
camera.getProperty("white_balance_auto_preset").set(1); // Auto white-balance enabled
camera.getProperty("auto_exposure").set(0); // auto exposure enabled
}
@@ -179,15 +182,14 @@ public class USBCameraSource extends VisionSource {
try {
int scaledExposure = 1;
if (cameraQuirks.hasQuirk(CameraQuirk.PiCam)) {
scaledExposure =
(int) Math.round(timeToPiCamRawExposure(pctToExposureTimeUs(exposure)));
logger.debug("Setting camera raw exposure to " + Integer.toString(scaledExposure));
scaledExposure = Math.round(timeToPiCamRawExposure(pctToExposureTimeUs(exposure)));
logger.debug("Setting camera raw exposure to " + scaledExposure);
camera.getProperty("raw_exposure_time_absolute").set(scaledExposure);
camera.getProperty("raw_exposure_time_absolute").set(scaledExposure);
} else {
scaledExposure = (int) Math.round(exposure);
logger.debug("Setting camera exposure to " + Integer.toString(scaledExposure));
logger.debug("Setting camera exposure to " + scaledExposure);
camera.setExposureManual(scaledExposure);
camera.setExposureManual(scaledExposure);
}
@@ -264,9 +266,7 @@ public class USBCameraSource extends VisionSource {
} else {
modes = camera.enumerateVideoModes();
}
for (int i = 0; i < modes.length; i++) {
var videoMode = modes[i];
for (VideoMode videoMode : modes) {
// Filter grey modes
if (videoMode.pixelFormat == VideoMode.PixelFormat.kGray
|| videoMode.pixelFormat == VideoMode.PixelFormat.kUnknown) {

View File

@@ -24,15 +24,15 @@ import org.photonvision.vision.pipe.impl.HSVPipe;
public interface FrameProvider extends Supplier<Frame> {
String getName();
/** Ask the camera to produce a certain kind of processed image (eg HSV or greyscale) */
public void requestFrameThresholdType(FrameThresholdType type);
/** Ask the camera to produce a certain kind of processed image (e.g. HSV or greyscale) */
void requestFrameThresholdType(FrameThresholdType type);
/** Ask the camera to rotate frames it outputs */
public void requestFrameRotation(ImageRotationMode rotationMode);
void requestFrameRotation(ImageRotationMode rotationMode);
/** Ask the camera to provide either the input, output, or both frames. */
public void requestFrameCopies(boolean copyInput, boolean copyOutput);
void requestFrameCopies(boolean copyInput, boolean copyOutput);
/** Ask the camera to rotate frames it outputs */
public void requestHsvSettings(HSVPipe.HSVParams params);
void requestHsvSettings(HSVPipe.HSVParams params);
}

View File

@@ -33,8 +33,8 @@ import org.photonvision.vision.opencv.CVMat;
public class FileSaveFrameConsumer implements Consumer<CVMat> {
// Formatters to generate unique, timestamped file names
private static String FILE_PATH = ConfigManager.getInstance().getImageSavePath().toString();
private static String FILE_EXTENSION = ".jpg";
private static final String FILE_PATH = ConfigManager.getInstance().getImageSavePath().toString();
private static final String FILE_EXTENSION = ".jpg";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
DateFormat tf = new SimpleDateFormat("hhmmssSS");
private final String NT_SUFFIX = "SaveImgCmd";
@@ -44,7 +44,7 @@ public class FileSaveFrameConsumer implements Consumer<CVMat> {
private final Logger logger;
private long imgSaveCountInternal = 0;
private String camNickname;
private String fnamePrefix;
private final String fnamePrefix;
private IntegerEntry entry;
public FileSaveFrameConsumer(String camNickname, String streamPrefix) {

View File

@@ -106,7 +106,6 @@ public class MJPGFrameConsumer {
private CvSource cvSource;
private MjpegServer mjpegServer;
@SuppressWarnings("FieldCanBeLocal")
private VideoListener listener;
private final NetworkTable table;

View File

@@ -30,7 +30,7 @@ import org.photonvision.vision.pipe.impl.HSVPipe;
import org.photonvision.vision.pipe.impl.RotateImagePipe;
public abstract class CpuImageProcessor implements FrameProvider {
protected class CapturedFrame {
protected static class CapturedFrame {
CVMat colorImage;
FrameStaticProperties staticProps;
long captureTimestamp;
@@ -119,6 +119,5 @@ public abstract class CpuImageProcessor implements FrameProvider {
@Override
public void requestFrameCopies(boolean copyInput, boolean copyOutput) {
// We don't actually do zero-copy, so this method is a no-op
return;
}
}

View File

@@ -63,7 +63,7 @@ public class FileFrameProvider extends CpuImageProcessor {
public FileFrameProvider(
Path path, double fov, int maxFPS, CameraCalibrationCoefficients calibration) {
if (!Files.exists(path))
throw new RuntimeException("Invalid path for image: " + path.toAbsolutePath().toString());
throw new RuntimeException("Invalid path for image: " + path.toAbsolutePath());
this.path = path;
this.millisDelay = 1000 / maxFPS;

View File

@@ -32,7 +32,7 @@ public class CVShape implements Releasable {
private MatOfPoint3f customTarget = null;
private MatOfPoint2f approxCurve = new MatOfPoint2f();
private final MatOfPoint2f approxCurve = new MatOfPoint2f();
public CVShape(Contour contour, ContourShape shape) {
this.contour = contour;

View File

@@ -21,13 +21,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import org.jetbrains.annotations.Nullable;
import org.opencv.core.CvType;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.RotatedRect;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgproc.Moments;
import org.photonvision.common.util.math.MathUtils;

View File

@@ -35,7 +35,7 @@ public enum ContourSortMode {
(Math.pow(rect.getMinAreaRect().center.y, 2)
+ Math.pow(rect.getMinAreaRect().center.x, 2))));
private Comparator<PotentialTarget> m_comparator;
private final Comparator<PotentialTarget> m_comparator;
ContourSortMode(Comparator<PotentialTarget> comparator) {
m_comparator = comparator;

View File

@@ -46,8 +46,7 @@ public class AprilTagDetectionPipeParams {
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;
return true;
return other.detectorParams == null;
} else return detectorParams.equals(other.detectorParams);
}
}

View File

@@ -46,7 +46,7 @@ public class AprilTagPoseEstimatorPipe
@Override
protected AprilTagPoseEstimate process(AprilTagDetection in) {
// Save the corner points of our detection to an array
Point corners[] = new Point[4];
Point[] corners = new Point[4];
for (int i = 0; i < 4; i++) {
corners[i] = new Point(in.getCornerX(i), in.getCornerY(i));
}
@@ -128,8 +128,7 @@ public class AprilTagPoseEstimatorPipe
if (config == null) {
if (other.config != null) return false;
} else if (!config.equals(other.config)) return false;
if (nIters != other.nIters) return false;
return true;
return nIters == other.nIters;
}
}
}

View File

@@ -23,7 +23,7 @@ import org.photonvision.vision.pipe.CVPipe;
public class CalculateFPSPipe
extends CVPipe<Void, Integer, CalculateFPSPipe.CalculateFPSPipeParams> {
private LinearFilter fpsFilter = LinearFilter.movingAverage(20);
private final LinearFilter fpsFilter = LinearFilter.movingAverage(20);
StopWatch clock = new StopWatch();
@Override

View File

@@ -24,7 +24,9 @@ import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Triple;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.*;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.Size;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
@@ -38,24 +40,24 @@ public class Calibrate3dPipe
Calibrate3dPipe.CalibratePipeParams> {
// Camera matrix stores the center of the image and focal length across the x and y-axis in a 3x3
// matrix
private Mat cameraMatrix = new Mat();
private final Mat cameraMatrix = new Mat();
// Stores the radical and tangential distortion in a 5x1 matrix
private MatOfDouble distortionCoefficients = new MatOfDouble();
private final MatOfDouble distortionCoefficients = new MatOfDouble();
// For loggging
// For logging
private static final Logger logger = new Logger(Calibrate3dPipe.class, LogGroup.General);
// Translational and rotational matrices
private List<Mat> rvecs = new ArrayList<>();
private List<Mat> tvecs = new ArrayList<>();
private final List<Mat> rvecs = new ArrayList<>();
private final List<Mat> tvecs = new ArrayList<>();
// The Standard deviation of the estimated parameters
private Mat stdDeviationsIntrinsics = new Mat();
private Mat stdDeviationsExtrinsics = new Mat();
private final Mat stdDeviationsIntrinsics = new Mat();
private final Mat stdDeviationsExtrinsics = new Mat();
// Contains the re projection error of each snapshot by re projecting the corners we found and
// finding the euclidean distance between the actual corners.
private Mat perViewErrors = new Mat();
// finding the Euclidean distance between the actual corners.
private final Mat perViewErrors = new Mat();
// RMS of the calibration
private double calibrationAccuracy;
@@ -135,7 +137,7 @@ public class Calibrate3dPipe
}
// Calculate standard deviation of the RMS error of the snapshots
private static double calculateSD(double numArray[]) {
private static double calculateSD(double[] numArray) {
double sum = 0.0, standardDeviation = 0.0;
int length = numArray.length;

View File

@@ -18,10 +18,7 @@
package org.photonvision.vision.pipe.impl;
import edu.wpi.first.math.geometry.Translation2d;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.*;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
@@ -42,18 +39,10 @@ public class CornerDetectionPipe
for (var target : targetList) {
// detect corners. Might implement more algorithms later but
// APPROX_POLY_DP_AND_EXTREME_CORNERS should be year agnostic
switch (params.cornerDetectionStrategy) {
case APPROX_POLY_DP_AND_EXTREME_CORNERS:
{
var targetCorners =
detectExtremeCornersByApproxPolyDp(target, params.calculateConvexHulls);
target.setTargetCorners(targetCorners);
break;
}
default:
{
break;
}
if (Objects.requireNonNull(params.cornerDetectionStrategy)
== DetectionStrategy.APPROX_POLY_DP_AND_EXTREME_CORNERS) {
var targetCorners = detectExtremeCornersByApproxPolyDp(target, params.calculateConvexHulls);
target.setTargetCorners(targetCorners);
}
}
return targetList;
@@ -133,7 +122,7 @@ public class CornerDetectionPipe
we want a number between 0 and 0.16 out of a percentage from 0 to 100
so take accuracy and divide by 600
Furthermore, we know that the contour is open if we haven't done convex hulls
Furthermore, we know that the contour is open if we haven't done convex hulls,
and it has subcontours.
*/
var isOpen = !convexHull && target.hasSubContours();
@@ -158,7 +147,7 @@ public class CornerDetectionPipe
var distanceToTrComparator =
Comparator.comparingDouble((Point p) -> distanceBetween(p, boundingBoxCorners.get(3)));
// top left and top right are the poly corners closest to the bouding box tl and tr
// top left and top right are the poly corners closest to the bounding box tl and tr
pointList.sort(distanceToTlComparator);
var tl = pointList.get(0);
pointList.remove(tl);

View File

@@ -17,7 +17,7 @@
package org.photonvision.vision.pipe.impl;
import java.awt.Color;
import java.awt.*;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Mat;
@@ -62,7 +62,7 @@ public class Draw2dCrosshairPipe
}
break;
case Dual:
if (in.getRight().size() >= 1) {
if (!in.getRight().isEmpty()) {
var target = in.getRight().get(0);
if (target != null) {
var area = target.getArea();

View File

@@ -22,12 +22,8 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.MatOfPoint3f;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.core.Point3;
import org.opencv.imgproc.Imgproc;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
@@ -95,7 +91,7 @@ public class Draw3dTargetsPipe
jac);
if (params.redistortPoints) {
// Distort the points so they match the image they're being overlaid on
// Distort the points, so they match the image they're being overlaid on
distortPoints(tempMat, tempMat);
}
@@ -111,7 +107,7 @@ public class Draw3dTargetsPipe
jac);
if (params.redistortPoints) {
// Distort the points so they match the image they're being overlaid on
// Distort the points, so they match the image they're being overlaid on
distortPoints(tempMat, tempMat);
}
var topPoints = tempMat.toList();
@@ -119,7 +115,7 @@ public class Draw3dTargetsPipe
dividePointList(bottomPoints);
dividePointList(topPoints);
// floor, then pillers, then top
// floor, then pillars, then top
for (int i = 0; i < bottomPoints.size(); i++) {
Imgproc.line(
in.getLeft(),
@@ -241,11 +237,11 @@ public class Draw3dTargetsPipe
double r2 = x * x + y * y; // square of the radius from center
// Radial distorsion
// Radial distortion
double xDistort = x * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2);
double yDistort = y * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2);
// Tangential distorsion
// Tangential distortion
xDistort = xDistort + (2 * p1 * x * y + p2 * (r2 + 2 * x * x));
yDistort = yDistort + (p1 * (r2 + 2 * y * y) + 2 * p2 * x * y);

View File

@@ -39,8 +39,8 @@ public class FindBoardCornersPipe
Size imageSize;
Size patternSize;
// Configure the optimizations used while using openCV's find corners algorithm
// Since we return results in real-time, we want ensure it goes as fast as possible
// Configure the optimizations used while using OpenCV's find corners algorithm
// 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 =
Calib3d.CALIB_CB_NORMALIZE_IMAGE
@@ -48,9 +48,9 @@ public class FindBoardCornersPipe
| Calib3d.CALIB_CB_FILTER_QUADS
| Calib3d.CALIB_CB_FAST_CHECK;
private MatOfPoint2f boardCorners = new MatOfPoint2f();
private final MatOfPoint2f boardCorners = new MatOfPoint2f();
// Intermedeate result mat's
// Intermediate result mat's
Mat smallerInFrame = new Mat();
MatOfPoint2f smallerBoardCorners = new MatOfPoint2f();
@@ -213,7 +213,7 @@ public class FindBoardCornersPipe
}
/**
* Find chessboard corners given a input mat and output mat to draw on
* Find chessboard corners given an input mat and output mat to draw on
*
* @return Frame resolution, object points, board corners
*/
@@ -223,7 +223,7 @@ public class FindBoardCornersPipe
var inFrame = in.getLeft();
var outFrame = in.getRight();
// Convert the inFrame to grayscale to increase contrast
// Convert the inFrame too grayscale to increase contrast
Imgproc.cvtColor(inFrame, inFrame, Imgproc.COLOR_BGR2GRAY);
boolean boardFound = false;
@@ -328,8 +328,7 @@ public class FindBoardCornersPipe
if (type != other.type) return false;
if (Double.doubleToLongBits(gridSize) != Double.doubleToLongBits(other.gridSize))
return false;
if (divisor != other.divisor) return false;
return true;
return divisor == other.divisor;
}
}
}

View File

@@ -70,7 +70,7 @@ public class FindCirclesPipe
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
// Great, we now found the center point of the circle, and it's radius, but we have no idea what
// contour it corresponds to
// Each contour can only match to one circle, so we keep a list of unmatched contours around and
// only match against them
@@ -121,7 +121,7 @@ public class FindCirclesPipe
* 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 shough normally be higher, such as 300 or normally exposed and contrasty images.
* 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.

View File

@@ -19,7 +19,6 @@ package org.photonvision.vision.pipe.impl;
import java.util.ArrayList;
import java.util.List;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.photonvision.vision.opencv.CVShape;
import org.photonvision.vision.opencv.Contour;

View File

@@ -76,7 +76,7 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
"",
"void main() {",
" vec2 uv = gl_FragCoord.xy/resolution;",
// Important! We do this .bgr swizzle because the image comes in as BGR but we pretend
// 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
@@ -230,7 +230,7 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
+ "', version '"
+ gl.glGetString(GL.GL_VERSION)
+ "', and profile '"
+ profile.toString()
+ profile
+ "'");
var fmt = GLBuffers.newDirectIntBuffer(1);
@@ -242,7 +242,7 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
// index for the generic position input)
gl.glBindAttribLocation(programId, 0, "position");
// Compile and setup our two shaders with our program
// 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);
@@ -298,7 +298,10 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(k_vertexPositions);
gl.glBindBuffer(GL_ARRAY_BUFFER, vertexVBOIds.get(0));
gl.glBufferData(
GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, GL_STATIC_DRAW);
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) {
@@ -389,12 +392,18 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
if (pboMode != PBOMode.NONE) {
gl.glBindBuffer(GLES3.GL_PIXEL_PACK_BUFFER, packPBOIds.get(0));
gl.glBufferData(
GLES3.GL_PIXEL_PACK_BUFFER, in.width() * in.height(), null, GLES3.GL_STREAM_READ);
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, in.width() * in.height(), null, GLES3.GL_STREAM_READ);
GLES3.GL_PIXEL_PACK_BUFFER,
(long) in.width() * in.height(),
null,
GLES3.GL_STREAM_READ);
}
}
}
@@ -459,14 +468,17 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
// GPU
// This causes the previous data in the PBO to be discarded
gl.glBufferData(
GLES3.GL_PIXEL_UNPACK_BUFFER, in.width() * in.height() * 3, null, GLES3.GL_STREAM_DRAW);
GLES3.GL_PIXEL_UNPACK_BUFFER,
(long) in.width() * in.height() * 3,
null,
GLES3.GL_STREAM_DRAW);
// Map the a buffer of GPU memory into a place that's accessible by us
// Map the buffer of GPU memory into a place that's accessible by us
var buf =
gl.glMapBufferRange(
GLES3.GL_PIXEL_UNPACK_BUFFER,
0,
in.width() * in.height() * 3,
(long) in.width() * in.height() * 3,
GLES3.GL_MAP_WRITE_BIT);
buf.put(inputBytes);
@@ -527,7 +539,8 @@ public class GPUAcceleratedHSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
// 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, width * height, GLES3.GL_MAP_READ_BIT);
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);

View File

@@ -40,7 +40,6 @@ public class HSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
Scalar firstLower = params.getHsvLower().clone();
Scalar firstUpper = params.getHsvUpper().clone();
firstLower.val[0] = params.getHsvUpper().val[0];
;
firstUpper.val[0] = 180;
var lowerThresholdMat = new Mat();

View File

@@ -37,7 +37,7 @@ public class SortContoursPipe
}
m_sortedContours.clear();
if (in.size() > 0) {
if (!in.isEmpty()) {
m_sortedContours.addAll(in);
if (params.getSortMode() != ContourSortMode.Centermost) {
m_sortedContours.sort(params.getSortMode().getComparator());

View File

@@ -33,7 +33,7 @@ public class SpeckleRejectPipe
}
m_despeckledContours.clear();
if (in.size() > 0) {
if (!in.isEmpty()) {
double averageArea = 0.0;
for (Contour c : in) {
averageArea += c.getArea();

View File

@@ -29,13 +29,15 @@ import org.photonvision.common.util.math.MathUtils;
import org.photonvision.vision.frame.Frame;
import org.photonvision.vision.frame.FrameThresholdType;
import org.photonvision.vision.pipe.CVPipe.CVPipeResult;
import org.photonvision.vision.pipe.impl.*;
import org.photonvision.vision.pipe.impl.AprilTagDetectionPipe;
import org.photonvision.vision.pipe.impl.AprilTagDetectionPipeParams;
import org.photonvision.vision.pipe.impl.AprilTagPoseEstimatorPipe;
import org.photonvision.vision.pipe.impl.AprilTagPoseEstimatorPipe.AprilTagPoseEstimatorPipeParams;
import org.photonvision.vision.pipe.impl.CalculateFPSPipe;
import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.TrackedTarget;
import org.photonvision.vision.target.TrackedTarget.TargetCalculationParameters;
@SuppressWarnings("DuplicatedCode")
public class AprilTagPipeline extends CVPipeline<CVPipelineResult, AprilTagPipelineSettings> {
private final AprilTagDetectionPipe aprilTagDetectionPipe = new AprilTagDetectionPipe();
private final AprilTagPoseEstimatorPipe poseEstimatorPipe = new AprilTagPoseEstimatorPipe();

View File

@@ -48,7 +48,6 @@ import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.TrackedTarget;
import org.photonvision.vision.target.TrackedTarget.TargetCalculationParameters;
@SuppressWarnings("DuplicatedCode")
public class ArucoPipeline extends CVPipeline<CVPipelineResult, ArucoPipelineSettings> {
private final RotateImagePipe rotateImagePipe = new RotateImagePipe();
private final GrayscalePipe grayscalePipe = new GrayscalePipe();

View File

@@ -40,7 +40,7 @@ public class CVPipelineSettings implements Cloneable {
public ImageRotationMode inputImageRotationMode = ImageRotationMode.DEG_0;
public String pipelineNickname = "New Pipeline";
public boolean cameraAutoExposure = false;
// manual exposure only used if cameraAutoExposure if false
// manual exposure only used if cameraAutoExposure is false
public double cameraExposure = 20;
public int cameraBrightness = 50;
// Currently only used by a few cameras (notably the zero-copy Pi Camera driver) with the Gain

View File

@@ -46,7 +46,7 @@ import org.photonvision.vision.pipeline.result.CVPipelineResult;
public class Calibrate3dPipeline
extends CVPipeline<CVPipelineResult, Calibration3dPipelineSettings> {
// For loggging
// For logging
private static final Logger logger = new Logger(Calibrate3dPipeline.class, LogGroup.General);
// Only 2 pipes needed, one for finding the board corners and one for actually calibrating
@@ -63,7 +63,7 @@ public class Calibrate3dPipeline
/// Output of the calibration, getter method is set for this.
private CVPipeResult<CameraCalibrationCoefficients> calibrationOutput;
private int minSnapshots;
private final int minSnapshots;
private boolean calibrating = false;

View File

@@ -24,14 +24,16 @@ import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Point;
import org.photonvision.vision.frame.Frame;
import org.photonvision.vision.frame.FrameThresholdType;
import org.photonvision.vision.opencv.*;
import org.photonvision.vision.opencv.CVShape;
import org.photonvision.vision.opencv.Contour;
import org.photonvision.vision.opencv.ContourShape;
import org.photonvision.vision.opencv.DualOffsetValues;
import org.photonvision.vision.pipe.CVPipe.CVPipeResult;
import org.photonvision.vision.pipe.impl.*;
import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.PotentialTarget;
import org.photonvision.vision.target.TrackedTarget;
@SuppressWarnings({"DuplicatedCode"})
public class ColoredShapePipeline
extends CVPipeline<CVPipelineResult, ColoredShapePipelineSettings> {
private final SpeckleRejectPipe speckleRejectPipe = new SpeckleRejectPipe();

View File

@@ -150,7 +150,7 @@ public class OutputStreamPipeline {
if (!(settings instanceof AprilTagPipelineSettings)
&& !(settings instanceof ArucoPipelineSettings)) {
// If we're processing anything other than Apriltags..
// If we're processing anything other than Apriltags...
var draw2dCrosshairResultOnOutput = draw2dCrosshairPipe.run(Pair.of(outMat, targetsToDraw));
sumPipeNanosElapsed += pipeProfileNanos[4] = draw2dCrosshairResultOnOutput.nanosElapsed;

View File

@@ -30,7 +30,6 @@ import org.photonvision.vision.target.TargetOrientation;
import org.photonvision.vision.target.TrackedTarget;
/** Represents a pipeline for tracking retro-reflective targets. */
@SuppressWarnings({"DuplicatedCode"})
public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectivePipelineSettings> {
private final FindContoursPipe findContoursPipe = new FindContoursPipe();
private final SpeckleRejectPipe speckleRejectPipe = new SpeckleRejectPipe();

View File

@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.opencv.aruco.Aruco;
import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.dataflow.DataChangeService;
@@ -67,7 +66,7 @@ public class PipelineManager {
this.driverModePipeline.setSettings(driverSettings);
if (userPipelines.size() < 1) addPipeline(PipelineType.Reflective);
if (userPipelines.isEmpty()) addPipeline(PipelineType.Reflective);
}
public PipelineManager(CameraConfiguration config) {
@@ -247,9 +246,9 @@ public class PipelineManager {
}
/**
* Returns whether or not driver mode is active.
* Returns whether driver mode is active.
*
* @return Whether or not driver mode is active.
* @return Whether driver mode is active.
*/
public boolean getDriverMode() {
return currentPipelineIndex == DRIVERMODE_INDEX;
@@ -261,7 +260,7 @@ public class PipelineManager {
/**
* Sorts the pipeline list by index, and reassigns their indexes to match the new order. <br>
* <br>
* I don't like this but I have no other ideas, and it works so
* I don't like this, but I have no other ideas, and it works so
*/
private void reassignIndexes() {
userPipelineSettings.sort(PipelineSettingsIndexComparator);
@@ -314,7 +313,7 @@ public class PipelineManager {
}
default:
{
logger.error("Got invalid pipeline type: " + type.toString());
logger.error("Got invalid pipeline type: " + type);
return null;
}
}
@@ -376,31 +375,31 @@ public class PipelineManager {
private static String createUniqueName(
String nickname, List<CVPipelineSettings> existingSettings) {
String uniqueName = nickname;
StringBuilder uniqueName = new StringBuilder(nickname);
while (true) {
String finalUniqueName = uniqueName; // To get around lambda capture
String finalUniqueName = uniqueName.toString(); // To get around lambda capture
var conflictingName =
existingSettings.stream().anyMatch(it -> it.pipelineNickname.equals(finalUniqueName));
if (!conflictingName) {
// If no conflict, we're done
return uniqueName;
return uniqueName.toString();
} else {
// Otherwise, we need to add a suffix to the name
// If the string doesn't already end in "([0-9]*)", we'll add it
// If it does, we'll increment the number in the suffix
if (uniqueName.matches(".*\\([0-9]*\\)")) {
if (uniqueName.toString().matches(".*\\([0-9]*\\)")) {
// Because java strings are immutable, we have to do this curstedness
// This is like doing "New pipeline (" + 2 + ")"
var parenStart = uniqueName.lastIndexOf('(');
var parenStart = uniqueName.toString().lastIndexOf('(');
var parenEnd = uniqueName.length() - 1;
var number = Integer.parseInt(uniqueName.substring(parenStart + 1, parenEnd)) + 1;
uniqueName = uniqueName.substring(0, parenStart + 1) + number + ")";
uniqueName = new StringBuilder(uniqueName.substring(0, parenStart + 1) + number + ")");
} else {
uniqueName += " (1)";
uniqueName.append(" (1)");
}
}
}
@@ -442,7 +441,7 @@ public class PipelineManager {
return;
}
logger.info("Adding new pipe of type " + type.toString() + " at idx " + idx);
logger.info("Adding new pipe of type " + type + " at idx " + idx);
newSettings.pipelineIndex = idx;
userPipelineSettings.set(idx, newSettings);
setPipelineInternal(idx);

View File

@@ -20,7 +20,10 @@ package org.photonvision.vision.processes;
import edu.wpi.first.cscore.VideoException;
import edu.wpi.first.math.util.Units;
import io.javalin.websocket.WsContext;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.function.BiConsumer;
import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.configuration.ConfigManager;
@@ -294,7 +297,7 @@ public class VisionModule {
var settables = visionSource.getSettables();
logger.trace(() -> "Setting " + settables.getConfiguration().nickname + ") FOV (" + fov + ")");
// Only set FOV if we have no vendor JSON and we aren't using a PiCAM
// Only set FOV if we have no vendor JSON, and we aren't using a PiCAM
if (isVendorCamera()) {
logger.info("Cannot set FOV on a vendor device! Ignoring...");
} else {

View File

@@ -65,18 +65,15 @@ public class VisionModuleManager {
addedModules.put(visionSource.getCameraConfiguration().streamIndex, module);
}
var sortedModulesList =
addedModules.entrySet().stream()
.sorted(Comparator.comparingInt(Map.Entry::getKey)) // sort by stream index
.map(Map.Entry::getValue) // map to Stream of VisionModule
.collect(Collectors.toList()); // collect in a List
return sortedModulesList;
return addedModules.entrySet().stream()
.sorted(Comparator.comparingInt(Map.Entry::getKey)) // sort by stream index
.map(Map.Entry::getValue) // map to Stream of VisionModule
.collect(Collectors.toList()); // collect in a List
}
private void assignCameraIndex(List<VisionSource> config) {
// We won't necessarily have already added all of the cameras we need to at this point
// But by operating on the list, we have a fairly good idea of which we need to change
// We won't necessarily have already added all the cameras we need to at this point
// But by operating on the list, we have a fairly good idea of which we need to change,
// but it's not guaranteed that we change the correct one
// The best we can do is try to avoid a case where the stream index runs away to infinity
// since we can only stream 5 cameras at once

View File

@@ -19,7 +19,10 @@ package org.photonvision.vision.processes;
import edu.wpi.first.cscore.UsbCamera;
import edu.wpi.first.cscore.UsbCameraInfo;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import java.util.stream.Collectors;

View File

@@ -33,7 +33,6 @@ public class TargetCalculations {
return -Math.toDegrees(Math.atan((offsetCenterY - targetCenterY) / verticalFocalLength));
}
@SuppressWarnings("DuplicatedCode")
public static double calculateSkew(boolean isLandscape, RotatedRect minAreaRect) {
// https://namkeenman.wordpress.com/2015/12/18/open-cv-determine-angle-of-rotatedrect-minarearect/
var angle = minAreaRect.angle;

View File

@@ -127,8 +127,8 @@ public enum TargetModel implements Releasable {
Units.inchesToMeters(3 * 2));
@JsonIgnore private MatOfPoint3f realWorldTargetCoordinates;
@JsonIgnore private MatOfPoint3f visualizationBoxBottom = new MatOfPoint3f();
@JsonIgnore private MatOfPoint3f visualizationBoxTop = new MatOfPoint3f();
@JsonIgnore private final MatOfPoint3f visualizationBoxBottom = new MatOfPoint3f();
@JsonIgnore private final MatOfPoint3f visualizationBoxTop = new MatOfPoint3f();
@JsonProperty("realWorldCoordinatesArray")
private List<Point3> realWorldCoordinatesArray;

View File

@@ -24,16 +24,14 @@ import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.math.geometry.Translation3d;
import java.util.HashMap;
import java.util.List;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.*;
import org.photonvision.common.util.math.MathUtils;
import org.photonvision.vision.aruco.ArucoDetectionResult;
import org.photonvision.vision.frame.FrameStaticProperties;
import org.photonvision.vision.opencv.*;
import org.photonvision.vision.opencv.CVShape;
import org.photonvision.vision.opencv.Contour;
import org.photonvision.vision.opencv.DualOffsetValues;
import org.photonvision.vision.opencv.Releasable;
public class TrackedTarget implements Releasable {
public final Contour m_mainContour;
@@ -126,11 +124,9 @@ public class TrackedTarget implements Releasable {
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
@@ -185,10 +181,9 @@ public class TrackedTarget implements Releasable {
var axisangle =
VecBuilder.fill(result.getRvec()[0], result.getRvec()[1], result.getRvec()[2]);
Rotation3d rotation = new Rotation3d(axisangle, axisangle.normF());
Transform3d targetPose =
MathUtils.convertOpenCVtoPhotonTransform(new Transform3d(translation, rotation));
m_bestCameraToTarget3d = targetPose;
m_bestCameraToTarget3d =
MathUtils.convertOpenCVtoPhotonTransform(new Transform3d(translation, rotation));
}
}
@@ -209,7 +204,7 @@ public class TrackedTarget implements Releasable {
}
/**
* Set the approximate bouding polygon.
* Set the approximate bounding polygon.
*
* @param boundingPolygon List of points to copy. Not modified.
*/
@@ -262,7 +257,7 @@ public class TrackedTarget implements Releasable {
params.dualOffsetValues,
params.robotOffsetPointMode);
// order of this stuff doesnt matter though
// order of this stuff doesn't matter though
m_pitch =
TargetCalculations.calculatePitch(
m_targetOffsetPoint.y, m_robotOffsetPoint.y, params.verticalFocalLength);

View File

@@ -35,7 +35,7 @@ public class SocketVideoStream implements Consumer<CVMat> {
// Gets set to true when another class reads out valid jpeg bytes at least once
// Set back to false when another frame is freshly converted
// Should eliminate synchronization issues of differeing rates of putting frames in
// Should eliminate synchronization issues of differing rates of putting frames in
// and taking them back out
boolean frameWasConsumed = false;
@@ -53,8 +53,7 @@ public class SocketVideoStream implements Consumer<CVMat> {
this.portID = portID;
oldSchoolServer =
new MJPGFrameConsumer(
CameraServerJNI.getHostname() + "_Port_" + Integer.toString(portID) + "_MJPEG_Server",
portID);
CameraServerJNI.getHostname() + "_Port_" + portID + "_MJPEG_Server", portID);
}
@Override
@@ -64,7 +63,7 @@ public class SocketVideoStream implements Consumer<CVMat> {
.tryLock()) { // we assume frames are coming in frequently. Just skip this frame if we're
// locked doing something else.
try {
// Does a single-shot frame recieve and convert to JPEG for efficency
// Does a single-shot frame receive and convert to JPEG for efficiency
// Will not capture/convert again until convertNextFrame() is called
if (image != null && !image.getMat().empty() && jpegBytes == null) {
frameWasConsumed = false;

View File

@@ -29,8 +29,8 @@ public class SocketVideoStreamManager {
private final Logger logger = new Logger(SocketVideoStreamManager.class, LogGroup.Camera);
private Map<Integer, SocketVideoStream> streams = new Hashtable<Integer, SocketVideoStream>();
private Map<WsContext, Integer> userSubscriptions = new Hashtable<WsContext, Integer>();
private final Map<Integer, SocketVideoStream> streams = new Hashtable<>();
private final Map<WsContext, Integer> userSubscriptions = new Hashtable<>();
private static class ThreadSafeSingleton {
private static final SocketVideoStreamManager INSTANCE = new SocketVideoStreamManager();
@@ -45,13 +45,13 @@ public class SocketVideoStreamManager {
// Register a new available camera stream
public void addStream(SocketVideoStream newStream) {
streams.put(newStream.portID, newStream);
logger.debug("Added new stream for port " + Integer.toString(newStream.portID));
logger.debug("Added new stream for port " + newStream.portID);
}
// Remove a previously-added camera stream, and unsubscribe all users
public void removeStream(SocketVideoStream oldStream) {
streams.remove(oldStream.portID);
logger.debug("Removed stream for port " + Integer.toString(oldStream.portID));
logger.debug("Removed stream for port " + oldStream.portID);
}
// Indicate a user would like to subscribe to a camera stream and get frames from it periodically
@@ -61,8 +61,7 @@ public class SocketVideoStreamManager {
userSubscriptions.put(user, streamPortID);
stream.addUser();
} else {
logger.error(
"User attempted to subscribe to non-existent port " + Integer.toString(streamPortID));
logger.error("User attempted to subscribe to non-existent port " + streamPortID);
}
}
@@ -92,7 +91,7 @@ public class SocketVideoStreamManager {
}
}
// Causes all streams to "re-trigger" and recieve and convert their next mjpeg frame
// Causes all streams to "re-trigger" and receive and convert their next mjpeg frame
// Only invoke this after all returned jpeg Strings have been used.
public void allStreamConvertNextFrame() {
for (SocketVideoStream stream : streams.values()) {

View File

@@ -107,13 +107,13 @@ public class ConfigTest {
Assertions.assertTrue(
reflectivePipelineSettings instanceof ReflectivePipelineSettings,
"Conig loaded pipeline settings for index 0 not of expected type ReflectivePipelineSettings!");
"Config loaded pipeline settings for index 0 not of expected type ReflectivePipelineSettings!");
Assertions.assertTrue(
coloredShapePipelineSettings instanceof ColoredShapePipelineSettings,
"Conig loaded pipeline settings for index 1 not of expected type ColoredShapePipelineSettings!");
"Config loaded pipeline settings for index 1 not of expected type ColoredShapePipelineSettings!");
Assertions.assertTrue(
apriltagPipelineSettings instanceof AprilTagPipelineSettings,
"Conig loaded pipeline settings for index 2 not of expected type AprilTagPipelineSettings!");
"Config loaded pipeline settings for index 2 not of expected type AprilTagPipelineSettings!");
}
@AfterAll

View File

@@ -21,7 +21,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import java.nio.file.Path;
import java.util.List;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.photonvision.common.util.TestUtils;
import org.photonvision.vision.camera.CameraType;
import org.photonvision.vision.pipeline.AprilTagPipelineSettings;

View File

@@ -57,17 +57,15 @@ public class LogFileManagementTest {
}
// Confirm new log files were created
Assertions.assertEquals(
true,
Logger.MAX_LOGS_TO_KEEP + 5 <= countLogFiles(testDir),
"Not enough log files discovered");
Assertions.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(
true, Logger.MAX_LOGS_TO_KEEP == countLogFiles(testDir), "Not enough log files deleted");
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));

View File

@@ -17,7 +17,8 @@
package org.photonvision.hardware;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.photonvision.common.hardware.GPIO.CustomGPIO;

View File

@@ -60,7 +60,7 @@ public class AprilTagTest {
pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera);
printTestResults(pipelineResult);
} catch (RuntimeException e) {
// For now, will throw coz rotation3d ctor
// For now, will throw because of the Rotation3d ctor
return;
}
@@ -116,7 +116,7 @@ public class AprilTagTest {
pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera);
printTestResults(pipelineResult);
} catch (RuntimeException e) {
// For now, will throw coz rotation3d ctor
// For now, will throw because of the Rotation3d ctor
return;
}

View File

@@ -59,7 +59,7 @@ public class ArucoPipelineTest {
pipelineResult = pipeline.run(frameProvider.get(), QuirkyCamera.DefaultCamera);
printTestResults(pipelineResult);
} catch (RuntimeException e) {
// For now, will throw coz rotation3d ctor
// For now, will throw because of the Rotation3d ctor
return;
}

View File

@@ -17,7 +17,8 @@
package org.photonvision.vision.pipeline;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.math.util.Units;
import java.io.File;
@@ -310,7 +311,7 @@ public class Calibrate3dPipeTest {
assertTrue(centerYErrPct < 10.0);
System.out.println("Per View Errors: " + Arrays.toString(cal.perViewErrors));
System.out.println("Camera Intrinsics: " + cal.cameraIntrinsics.toString());
System.out.println("Camera Intrinsics: " + cal.cameraIntrinsics);
System.out.println("Dist Coeffs: " + cal.distCoeffs.toString());
System.out.println("Standard Deviation: " + cal.standardDeviation);
System.out.println(

View File

@@ -17,7 +17,8 @@
package org.photonvision.vision.pipeline;
import static org.junit.jupiter.api.Assertions.*;
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;

View File

@@ -24,7 +24,9 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
@@ -169,7 +171,6 @@ public class VisionModuleManagerTest {
Arrays.toString(
modules.stream()
.map(it -> it.visionSource.getCameraConfiguration().streamIndex)
.collect(Collectors.toList())
.toArray()));
var idxs =
modules.stream()

View File

@@ -21,8 +21,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opencv.core.*;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.photonvision.common.util.TestUtils;
import org.photonvision.common.util.numbers.DoubleCouple;
@@ -31,8 +33,9 @@ import org.photonvision.vision.opencv.DualOffsetValues;
public class TargetCalculationsTest {
private static Size imageSize = new Size(800, 600);
private static Point imageCenterPoint = new Point(imageSize.width / 2, imageSize.height / 2);
private static final Size imageSize = new Size(800, 600);
private static final Point imageCenterPoint =
new Point(imageSize.width / 2, imageSize.height / 2);
private static final double diagFOV = Math.toRadians(70.0);
private static final FrameStaticProperties props =