From a42aed1e7f4141173b377cbdd768452b8a8885d8 Mon Sep 17 00:00:00 2001 From: Gold856 <117957790+Gold856@users.noreply.github.com> Date: Sun, 30 Mar 2025 01:43:03 -0400 Subject: [PATCH] Make pipe params into records --- .../frame/provider/CpuImageProcessor.java | 2 +- .../provider/LibcameraGpuFrameProvider.java | 14 +-- .../vision/objects/Letterbox.java | 5 +- .../pipe/impl/AprilTagDetectionPipe.java | 15 ++- .../impl/AprilTagDetectionPipeParams.java | 62 ---------- .../pipe/impl/AprilTagPoseEstimatorPipe.java | 45 ++----- .../pipe/impl/ArucoPoseEstimatorPipe.java | 22 ++-- .../pipe/impl/Collect2dTargetsPipe.java | 42 ++----- .../vision/pipe/impl/CornerDetectionPipe.java | 36 ++---- .../vision/pipe/impl/Draw2dCrosshairPipe.java | 95 ++++++++------- .../vision/pipe/impl/DrawCalibrationPipe.java | 15 +-- .../vision/pipe/impl/FilterContoursPipe.java | 67 +++-------- .../pipe/impl/FilterObjectDetectionsPipe.java | 45 ++----- .../vision/pipe/impl/FilterShapesPipe.java | 48 +++----- .../pipe/impl/FindBoardCornersPipe.java | 112 +++++------------- .../vision/pipe/impl/FindCirclesPipe.java | 78 ++++++------ .../vision/pipe/impl/FindPolygonPipe.java | 16 ++- .../vision/pipe/impl/GroupContoursPipe.java | 28 +---- .../vision/pipe/impl/HSVPipe.java | 42 ++----- .../vision/pipe/impl/MultiTargetPNPPipe.java | 34 ++---- .../pipe/impl/NeuralNetworkPipeResult.java | 12 +- .../vision/pipe/impl/ObjectDetectionPipe.java | 15 +-- .../vision/pipe/impl/ResizeImagePipe.java | 16 +-- .../vision/pipe/impl/RotateImagePipe.java | 12 +- .../vision/pipe/impl/SolvePNPPipe.java | 30 ++--- .../vision/pipe/impl/SortContoursPipe.java | 37 ++---- .../vision/pipe/impl/SpeckleRejectPipe.java | 14 +-- .../vision/pipeline/AprilTagPipeline.java | 2 +- .../pipeline/ObjectDetectionPipeline.java | 7 +- .../vision/target/PotentialTarget.java | 6 +- 30 files changed, 292 insertions(+), 682 deletions(-) delete mode 100644 photon-core/src/main/java/org/photonvision/vision/pipe/impl/AprilTagDetectionPipeParams.java 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 0ceb96c19..1a9e13e60 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 abstract class CpuImageProcessor extends FrameProvider { 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 6a354257b..2fa04fba2 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 class LibcameraGpuFrameProvider extends FrameProvider { 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 bbbae5269..51cf48915 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 class Letterbox { for (var t : unscaled) { var scale = 1.0 / this.scale; - var boundingBox = t.bbox; + var boundingBox = t.bbox(); double x = (boundingBox.x - this.dx) * scale; double y = (boundingBox.y - this.dy) * scale; double width = boundingBox.width * scale; double height = boundingBox.height * scale; ret.add( - new NeuralNetworkPipeResult(new Rect2d(x, y, width, height), t.classIdx, t.confidence)); + new NeuralNetworkPipeResult( + new Rect2d(x, y, width, height), t.classIdx(), t.confidence())); } return ret; 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 e4737ce95..01e237c41 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 @@ package org.photonvision.vision.pipe.impl; 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 @@ public class AprilTagDetectionPipe @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 class AprilTagDetectionPipe 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 773a0d299..000000000 --- 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 3ddc2f3de..f2c713799 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 @@ public class AprilTagPoseEstimatorPipe 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 @@ public class AprilTagPoseEstimatorPipe 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 class AprilTagPoseEstimatorPipe 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/ArucoPoseEstimatorPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ArucoPoseEstimatorPipe.java index ff9a89319..f036bfbfd 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 @@ public class ArucoPoseEstimatorPipe Calib3d.solvePnPGeneric( objectPoints, imagePoints, - params.calibration.getCameraIntrinsicsMat(), - params.calibration.getDistCoeffsMat(), + params.calibration().getCameraIntrinsicsMat(), + params.calibration().getDistCoeffsMat(), rvecs, tvecs, false, @@ -120,8 +120,8 @@ public class ArucoPoseEstimatorPipe @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 class ArucoPoseEstimatorPipe 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/Collect2dTargetsPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/Collect2dTargetsPipe.java index d5e4bda99..836e04fc7 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 @@ public class Collect2dTargetsPipe 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 @@ public class Collect2dTargetsPipe 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 660a11203..def6aeda1 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 @@ -121,12 +121,12 @@ public class CornerDetectionPipe 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); @@ -177,29 +177,15 @@ public class CornerDetectionPipe 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 fb22c6615..b7a3335af 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 @@ -38,21 +38,22 @@ 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(); - 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 -> { @@ -61,7 +62,7 @@ public class Draw2dCrosshairPipe 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,45 +70,30 @@ public class Draw2dCrosshairPipe } } - 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 Draw2dCrosshairParams( - 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; - } - + 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, @@ -116,13 +102,30 @@ public class Draw2dCrosshairPipe 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( + shouldDraw, + robotOffsetPointMode, + singleOffsetPoint, + dualOffsetValues, + frameStaticProperties, + divisor, + rotMode, + true, + Color.GREEN); + } + + public Draw2dCrosshairParams( + FrameStaticProperties frameStaticProperties, + FrameDivisor divisor, + ImageRotationMode 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/DrawCalibrationPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/DrawCalibrationPipe.java index 925000aa7..7005d66e8 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 @@ -43,7 +43,7 @@ public class DrawCalibrationPipe @Override protected Void process(Pair> in) { - if (!params.drawAllSnapshots) return null; + if (!params.drawAllSnapshots()) return null; var image = in.getLeft(); @@ -65,7 +65,8 @@ public class DrawCalibrationPipe 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 +83,5 @@ public class DrawCalibrationPipe 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/FilterContoursPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterContoursPipe.java index 1e7616c44..12f2ac913 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 @@ public class FilterContoursPipe } // 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; } @@ -81,66 +81,31 @@ public class FilterContoursPipe // 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 d22556668..03479dc51 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 @@ public class FilterObjectDetectionsPipe } 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 1802d6971..4f2489a92 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 @@ public class FilterShapesPipe } 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 a85c57a3e..93a5511bb 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 @@ -91,30 +91,30 @@ public class FindBoardCornersPipe * 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 class FindBoardCornersPipe 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 @@ public class FindBoardCornersPipe * @return */ private double getFindCornersScaleFactor(Mat inFrame) { - return 1.0 / params.divisor.value; + return 1.0 / params.divisor().value; } /** @@ -185,8 +185,8 @@ public class FindBoardCornersPipe * @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 +222,7 @@ public class FindBoardCornersPipe */ 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); @@ -254,7 +254,7 @@ public class FindBoardCornersPipe // 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 +295,10 @@ public class FindBoardCornersPipe // 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 +329,7 @@ public class FindBoardCornersPipe // 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 +371,15 @@ public class FindBoardCornersPipe 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 07ec9ecd8..6631a032e 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 @@ -49,9 +49,9 @@ public class FindCirclesPipe 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(), @@ -65,9 +65,9 @@ public class FindCirclesPipe 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 @@ -91,8 +91,8 @@ public class FindCirclesPipe // 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 @@ public class FindCirclesPipe 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/FindPolygonPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindPolygonPipe.java index 4cfc15259..fd32a9152 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 @@ public class FindPolygonPipe 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/GroupContoursPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/GroupContoursPipe.java index 7711467dd..184215beb 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 @@ public class GroupContoursPipe 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 @@ public class GroupContoursPipe 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 @@ public class GroupContoursPipe // 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 @@ public class GroupContoursPipe 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 e0ba36ce0..e58a20f89 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 @@ public class HSVPipe extends CVPipe { // 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 @@ public class HSVPipe extends CVPipe { 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 d0c338db1..b795da581 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 @@ public class MultiTargetPNPPipe var tagIDsUsed = new ArrayList(); 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 @@ public class MultiTargetPNPPipe var estimatedPose = VisionEstimation.estimateCamPosePNP( - params.cameraCoefficients.cameraIntrinsics.getAsWpilibMat(), - params.cameraCoefficients.distCoeffs.getAsWpilibMat(), + params.cameraCoefficients().cameraIntrinsics.getAsWpilibMat(), + params.cameraCoefficients().distCoeffs.getAsWpilibMat(), TrackedTarget.simpleFromTrackedTargets(targetList), - params.atfl, - params.targetModel); + params.atfl(), + params.targetModel()); if (estimatedPose.isPresent()) { return Optional.of(new MultiTargetPNPResult(estimatedPose.get(), tagIDsUsed)); @@ -85,18 +85,8 @@ public class MultiTargetPNPPipe } } - public static class MultiTargetPNPPipeParams { - private final CameraCalibrationCoefficients cameraCoefficients; - private final AprilTagFieldLayout atfl; - private final TargetModel targetModel; - - public MultiTargetPNPPipeParams( - CameraCalibrationCoefficients cameraCoefficients, - AprilTagFieldLayout atfl, - TargetModel targetModel) { - this.cameraCoefficients = cameraCoefficients; - this.atfl = atfl; - this.targetModel = targetModel; - } - } + public static record MultiTargetPNPPipeParams( + CameraCalibrationCoefficients cameraCoefficients, + AprilTagFieldLayout atfl, + TargetModel targetModel) {} } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java index 4fce74955..40a56e8d3 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java @@ -19,14 +19,4 @@ package org.photonvision.vision.pipe.impl; import org.opencv.core.Rect2d; -public class NeuralNetworkPipeResult { - public NeuralNetworkPipeResult(Rect2d boundingBox, int classIdx, double confidence) { - bbox = boundingBox; - this.classIdx = classIdx; - this.confidence = confidence; - } - - public final int classIdx; - public final Rect2d bbox; - public final double confidence; -} +public record NeuralNetworkPipeResult(Rect2d bbox, int classIdx, double confidence) {} diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ObjectDetectionPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ObjectDetectionPipe.java index fad36a5b8..079ee7926 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ObjectDetectionPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/ObjectDetectionPipe.java @@ -42,9 +42,9 @@ public class ObjectDetectionPipe @Override protected 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 @@ public class ObjectDetectionPipe 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 3d9c03043..7a65b2709 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 @@ public class SolvePNPPipe 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 @@ public class SolvePNPPipe 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 @@ public class SolvePNPPipe 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 b084c75c4..e9abc1ae9 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 @@ public class SortContoursPipe 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)); + Math.pow(params.frameStaticProperties().centerX - tgt.getMinAreaRect().center.x, 2) + + Math.pow(params.frameStaticProperties().centerY - tgt.getMinAreaRect().center.y, 2)); } - 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 4f4c5ce54..8f0a79cd6 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 @@ public class SpeckleRejectPipe } 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 @@ public class SpeckleRejectPipe 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 5cc9cc98f..f5cd52c26 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.Frame; 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; 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 684fdd024..c0e9fa424 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 @@ -56,9 +56,6 @@ public class ObjectDetectionPipeline @Override protected void setPipeParamsImpl() { - var params = new ObjectDetectionPipeParams(); - params.confidence = settings.confidence; - params.nms = settings.nms; Optional selectedModel = NeuralNetworkModelManager.getInstance().getModel(settings.model); @@ -71,8 +68,8 @@ public class ObjectDetectionPipeline if (selectedModel.isEmpty()) { selectedModel = Optional.of(NullModel.getInstance()); } - - params.model = selectedModel.get(); + var params = + new ObjectDetectionPipeParams(settings.confidence, settings.nms, selectedModel.get()); objectDetectorPipe.setParams(params); 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 520f1d454..a7c00e62e 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 class PotentialTarget implements Releasable { } 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) {