mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-06 03:31:41 +00:00
Pipeline Bringup (#94)
* Refactor package structure, various cleanups * Add pipeline classes, settings, separate enums * updated Largest ContourSortMode and added centermost * Add DriverPipeline classes, apply spotless * Add crosshair to DriverMode, cleanups * Add FrameStaticProperties as member in Frame Add FrameStaticProperties as member in Frame * Finish ReflectivePipeline, various tweaks * Apply Spotless * Move test images * add Releasable interface, implement in classes * add TestUtils class, move testimages * Refactor CVPipeline, add ReflectivePipelineTest * Fix ConcurrentModificationException bug in group contours pipe with potential targets * Resolve memory leaks due to unnecessary instantiation of Points * Apply spotless * Add CVMat, ReflectionUtils to help track rogue Mats * various cleanups, add DummyFrameConsumer * Add logback * Add slv4j logger to replace the current debugLogger I'm waiting on stuff to be less skeletoned to add more * Add perimeter, MatOfPoint2f getters to Contour * Create CornerDetectionPipe based on old solvePNPPipe * Add ContourShape class for approxPolyDp Start on ColoredShape tracking * Add point detection, fix convex hull calculation in Contour * Make Draw2dContours pipe respect showMultiple * Update Contour.java * Clean up draw 3d, fix convex hull bug in corner detection * Update geometry classes * Add lifecam calibration data * Implement solvePNP, bounding box top and bottom * Fix JSON mat bug and lifecam default calibration for tests, fix 3d drawing * run spotless * Refactor calibration into `common.calibration` * Update .gitignore * Add offset method to get2020Target * Various cleanups, add PipelineType enum * Apply spotless Co-authored-by: ori agranat <oriagranat9@gmail.com> Co-authored-by: Matt <matthew.morley.ca@gmail.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package com.chameleonvision.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.chameleonvision.common.util;
|
||||
|
||||
import edu.wpi.cscore.CameraServerCvJNI;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.highgui.HighGui;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public enum WPI2019Image {
|
||||
kCargoAngledDark48in(1.2192),
|
||||
kCargoSideStraightDark36in(0.9144),
|
||||
kCargoSideStraightDark60in(1.524),
|
||||
kCargoSideStraightDark72in(1.8288),
|
||||
kCargoSideStraightPanelDark36in(0.9144),
|
||||
kCargoStraightDark19in(0.4826),
|
||||
kCargoStraightDark24in(0.6096),
|
||||
kCargoStraightDark48in(1.2192),
|
||||
kCargoStraightDark72in(1.8288),
|
||||
kCargoStraightDark72in_HighRes(1.8288),
|
||||
kCargoStraightDark90in(2.286);
|
||||
|
||||
public static double FOV = 68.5;
|
||||
|
||||
public final double distanceMeters;
|
||||
public final String path;
|
||||
|
||||
String getPath() {
|
||||
var filename = this.toString().substring(1);
|
||||
return "\\2019\\WPI\\" + filename + ".jpg";
|
||||
}
|
||||
|
||||
WPI2019Image(double distanceMeters) {
|
||||
this.distanceMeters = distanceMeters;
|
||||
this.path = getPath();
|
||||
}
|
||||
}
|
||||
|
||||
public enum WPI2020Image {
|
||||
kBlueGoal_060in_Center(1.524),
|
||||
kBlueGoal_084in_Center(2.1336),
|
||||
kBlueGoal_108in_Center(2.7432),
|
||||
kBlueGoal_132in_Center(3.3528),
|
||||
kBlueGoal_156in_Center(3.9624),
|
||||
kBlueGoal_180in_Center(4.572),
|
||||
kBlueGoal_156in_Left(3.9624),
|
||||
kBlueGoal_224in_Left(5.6896),
|
||||
kBlueGoal_228in_ProtectedZone(5.7912),
|
||||
kBlueGoal_330in_ProtectedZone(8.382),
|
||||
kBlueGoal_Far_ProtectedZone(10.668), // TODO: find a more accurate distance
|
||||
kRedLoading_016in_Down(0.4064),
|
||||
kRedLoading_030in_Down(0.762),
|
||||
kRedLoading_048in_Down(1.2192),
|
||||
kRedLoading_048in(1.2192),
|
||||
kRedLoading_060in(1.524),
|
||||
kRedLoading_084in(2.1336),
|
||||
kRedLoading_108in(2.7432);
|
||||
|
||||
public static double FOV = 68.5;
|
||||
|
||||
public final double distanceMeters;
|
||||
public final String path;
|
||||
|
||||
String getPath() {
|
||||
var filename = this.toString().substring(1).replace('_', '-');
|
||||
return "\\2020\\WPI\\" + filename + ".jpg";
|
||||
}
|
||||
|
||||
WPI2020Image(double distanceMeters) {
|
||||
this.distanceMeters = distanceMeters;
|
||||
this.path = getPath();
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getTestImagesPath() {
|
||||
var folder = TestUtils.class.getClassLoader().getResource("testimages");
|
||||
return Optional.ofNullable(folder).map(url -> new File(url.getFile()).toPath()).orElse(null);
|
||||
}
|
||||
|
||||
public static Path getCalibrationPath() {
|
||||
var folder = TestUtils.class.getClassLoader().getResource("calibration");
|
||||
return Optional.ofNullable(folder).map(url -> new File(url.getFile()).toPath()).orElse(null);
|
||||
}
|
||||
|
||||
public static Path getWPIImagePath(WPI2020Image image) {
|
||||
return Path.of(getTestImagesPath().toString(), image.path);
|
||||
}
|
||||
|
||||
public static Path getWPIImagePath(WPI2019Image image) {
|
||||
return Path.of(getTestImagesPath().toString(), image.path);
|
||||
}
|
||||
|
||||
public static void loadLibraries() {
|
||||
try {
|
||||
CameraServerCvJNI.forceLoad();
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static int DefaultTimeoutMillis = 5000;
|
||||
|
||||
public static void showImage(Mat frame, String title, int timeoutMs) {
|
||||
HighGui.imshow(title, frame);
|
||||
HighGui.waitKey(timeoutMs);
|
||||
HighGui.destroyAllWindows();
|
||||
}
|
||||
|
||||
public static void showImage(Mat frame, int timeoutMs) {
|
||||
showImage(frame, "", timeoutMs);
|
||||
}
|
||||
|
||||
public static void showImage(Mat frame, String title) {
|
||||
showImage(frame, title, DefaultTimeoutMillis);
|
||||
}
|
||||
|
||||
public static void showImage(Mat frame) {
|
||||
showImage(frame, DefaultTimeoutMillis);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.chameleonvision.common.util.file;
|
||||
|
||||
import com.chameleonvision.common.logging.DebugLogger;
|
||||
import com.chameleonvision.common.util.Platform;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -11,9 +10,14 @@ import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FileUtils {
|
||||
private static DebugLogger logger = new DebugLogger(true);
|
||||
|
||||
private FileUtils() {}
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(FileUtils.class);
|
||||
private static final Set<PosixFilePermission> allReadWriteExecutePerms =
|
||||
new HashSet<>(Arrays.asList(PosixFilePermission.values()));
|
||||
|
||||
@@ -23,7 +27,7 @@ public class FileUtils {
|
||||
Set<PosixFilePermission> perms =
|
||||
Files.readAttributes(path, PosixFileAttributes.class).permissions();
|
||||
if (!perms.equals(allReadWriteExecutePerms)) {
|
||||
logger.printInfo("Setting perms on" + path.toString());
|
||||
logger.info("Setting perms on" + path.toString());
|
||||
Files.setPosixFilePermissions(path, perms);
|
||||
if (thisFile.isDirectory()) {
|
||||
for (File subfile : thisFile.listFiles()) {
|
||||
@@ -46,8 +50,7 @@ public class FileUtils {
|
||||
}
|
||||
} else {
|
||||
// TODO file perms on Windows
|
||||
System.out.println(
|
||||
"File permission setting not available on Windows. Not changing file permissions.");
|
||||
logger.info("Cannot set directory permissions on Windows!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,8 @@ public class MathUtils {
|
||||
double toMult = Math.pow(10, to);
|
||||
return (double) Math.round(value * toMult) / toMult;
|
||||
}
|
||||
|
||||
public static double nanosToMillis(long nanos) {
|
||||
return nanos / 1000000.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.chameleonvision.common.util.numbers;
|
||||
|
||||
import org.opencv.core.Point;
|
||||
|
||||
public class DoubleCouple extends NumberCouple<Double> {
|
||||
|
||||
public DoubleCouple() {
|
||||
@@ -9,4 +11,17 @@ public class DoubleCouple extends NumberCouple<Double> {
|
||||
public DoubleCouple(Double first, Double second) {
|
||||
super(first, second);
|
||||
}
|
||||
|
||||
public DoubleCouple(Point point) {
|
||||
super(point.x, point.y);
|
||||
}
|
||||
|
||||
public Point toPoint() {
|
||||
return new Point(first, second);
|
||||
}
|
||||
|
||||
public void fromPoint(Point point) {
|
||||
first = point.x;
|
||||
second = point.y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.chameleonvision.common.util.numbers;
|
||||
|
||||
public abstract class NumberCouple<T extends Number> {
|
||||
|
||||
private T first;
|
||||
private T second;
|
||||
protected T first;
|
||||
protected T second;
|
||||
|
||||
public NumberCouple(T first, T second) {
|
||||
this.first = first;
|
||||
|
||||
Reference in New Issue
Block a user