mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-24 01:31:44 +00:00
Make pipe params into records
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<CVMat, List<AprilTagDetection>, AprilTagDetectionPipeParams>
|
||||
extends CVPipe<
|
||||
CVMat, List<AprilTagDetection>, 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) {}
|
||||
}
|
||||
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,21 +38,22 @@ public class Draw2dCrosshairPipe
|
||||
Pair<Mat, List<TrackedTarget>>, Draw2dCrosshairPipe.Draw2dCrosshairParams> {
|
||||
@Override
|
||||
protected Void process(Pair<Mat, List<TrackedTarget>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class DrawCalibrationPipe
|
||||
|
||||
@Override
|
||||
protected Void process(Pair<Mat, List<TrackedTarget>> 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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -49,9 +49,9 @@ public class FindCirclesPipe
|
||||
circles.release();
|
||||
List<CVShape> 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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -32,24 +32,24 @@ public class HSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
|
||||
// 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<Mat, Mat, HSVPipe.HSVParams> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ public class MultiTargetPNPPipe
|
||||
@Override
|
||||
protected Optional<MultiTargetPNPResult> process(List<TrackedTarget> 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<Short>();
|
||||
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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -42,9 +42,9 @@ public class ObjectDetectionPipe
|
||||
@Override
|
||||
protected List<NeuralNetworkPipeResult> 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<String> getClassNames() {
|
||||
return detector.getClasses();
|
||||
|
||||
@@ -32,22 +32,12 @@ public class ResizeImagePipe extends MutatingPipe<Mat, ResizeImagePipe.ResizeIma
|
||||
*/
|
||||
@Override
|
||||
protected Void process(Mat in) {
|
||||
int width = in.cols() / params.getDivisor().value;
|
||||
int height = in.rows() / params.getDivisor().value;
|
||||
int width = in.cols() / params.divisor().value;
|
||||
int height = in.rows() / params.divisor().value;
|
||||
Imgproc.resize(in, in, new Size(width, height));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class ResizeImageParams {
|
||||
private final FrameDivisor divisor;
|
||||
|
||||
public ResizeImageParams(FrameDivisor divisor) {
|
||||
this.divisor = divisor;
|
||||
}
|
||||
|
||||
public FrameDivisor getDivisor() {
|
||||
return divisor;
|
||||
}
|
||||
}
|
||||
public static record ResizeImageParams(FrameDivisor divisor) {}
|
||||
}
|
||||
|
||||
@@ -40,21 +40,15 @@ public class RotateImagePipe extends MutatingPipe<Mat, RotateImagePipe.RotateIma
|
||||
*/
|
||||
@Override
|
||||
protected Void process(Mat in) {
|
||||
Core.rotate(in, in, params.rotation.value);
|
||||
Core.rotate(in, in, params.rotation().value);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class RotateImageParams {
|
||||
public static record RotateImageParams(ImageRotationMode rotation) {
|
||||
public static RotateImageParams DEFAULT = new RotateImageParams(ImageRotationMode.DEG_0);
|
||||
|
||||
public ImageRotationMode rotation;
|
||||
|
||||
public RotateImageParams() {
|
||||
rotation = DEFAULT.rotation;
|
||||
}
|
||||
|
||||
public RotateImageParams(ImageRotationMode rotation) {
|
||||
this.rotation = rotation;
|
||||
this(DEFAULT.rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ public class SolvePNPPipe
|
||||
|
||||
@Override
|
||||
protected List<TrackedTarget> process(List<TrackedTarget> 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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -56,9 +56,6 @@ public class ObjectDetectionPipeline
|
||||
|
||||
@Override
|
||||
protected void setPipeParamsImpl() {
|
||||
var params = new ObjectDetectionPipeParams();
|
||||
params.confidence = settings.confidence;
|
||||
params.nms = settings.nms;
|
||||
Optional<Model> 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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user