mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-20 00:51:41 +00:00
Add MutatingPipe (#44)
* Add MutatingPipe, use references in MutatingPipes * Apply spotless * Fix NPE in ColoredShapePipeline
This commit is contained in:
@@ -17,8 +17,6 @@
|
||||
|
||||
package org.photonvision.vision.pipe;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Defines a pipe. A pipe is a single step in a pipeline. This class is to be extended, never used
|
||||
* on its own.
|
||||
@@ -27,7 +25,7 @@ import java.util.function.Function;
|
||||
* @param <O> Output type for the pipe
|
||||
* @param <P> Parameters type for the pipe
|
||||
*/
|
||||
public abstract class CVPipe<I, O, P> implements Function<I, CVPipeResult<O>> {
|
||||
public abstract class CVPipe<I, O, P> {
|
||||
|
||||
protected CVPipeResult<O> result = new CVPipeResult<>();
|
||||
protected P params;
|
||||
@@ -48,11 +46,15 @@ public abstract class CVPipe<I, O, P> implements Function<I, CVPipeResult<O>> {
|
||||
* @param in Input for pipe processing.
|
||||
* @return Result of processing.
|
||||
*/
|
||||
@Override
|
||||
public CVPipeResult<O> apply(I in) {
|
||||
public CVPipeResult<O> run(I in) {
|
||||
long pipeStartNanos = System.nanoTime();
|
||||
result.result = process(in);
|
||||
result.output = process(in);
|
||||
result.nanosElapsed = System.nanoTime() - pipeStartNanos;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class CVPipeResult<O> {
|
||||
public O output;
|
||||
public long nanosElapsed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,4 @@
|
||||
|
||||
package org.photonvision.vision.pipe;
|
||||
|
||||
public class CVPipeResult<O> {
|
||||
public O result;
|
||||
public long nanosElapsed;
|
||||
}
|
||||
public abstract class MutatingPipe<I, P> extends CVPipe<I, Void, P> {}
|
||||
@@ -20,10 +20,10 @@ package org.photonvision.vision.pipe.impl;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
|
||||
/** Represents a pipeline that blurs the image. */
|
||||
public class BlurPipe extends CVPipe<Mat, Mat, BlurPipe.BlurParams> {
|
||||
public class BlurPipe extends MutatingPipe<Mat, BlurPipe.BlurParams> {
|
||||
/**
|
||||
* Processes this pipe.
|
||||
*
|
||||
@@ -31,9 +31,9 @@ public class BlurPipe extends CVPipe<Mat, Mat, BlurPipe.BlurParams> {
|
||||
* @return The processed frame.
|
||||
*/
|
||||
@Override
|
||||
protected Mat process(Mat in) {
|
||||
protected Void process(Mat in) {
|
||||
Imgproc.blur(in, in, params.getBlurSize());
|
||||
return in;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class BlurParams {
|
||||
|
||||
@@ -25,15 +25,16 @@ import org.opencv.core.Point;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.common.util.ColorHelper;
|
||||
import org.photonvision.common.util.numbers.DoubleCouple;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
import org.photonvision.vision.target.RobotOffsetPointMode;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
public class Draw2dCrosshairPipe
|
||||
extends CVPipe<Pair<Mat, List<TrackedTarget>>, Mat, Draw2dCrosshairPipe.Draw2dCrosshairParams> {
|
||||
extends MutatingPipe<
|
||||
Pair<Mat, List<TrackedTarget>>, Draw2dCrosshairPipe.Draw2dCrosshairParams> {
|
||||
|
||||
@Override
|
||||
protected Mat process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
protected Void process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
Mat image = in.getLeft();
|
||||
|
||||
if (params.m_showCrosshair) {
|
||||
@@ -61,7 +62,7 @@ public class Draw2dCrosshairPipe
|
||||
Imgproc.line(image, xMax, xMin, ColorHelper.colorToScalar(params.m_crosshairColor));
|
||||
Imgproc.line(image, yMax, yMin, ColorHelper.colorToScalar(params.m_crosshairColor));
|
||||
}
|
||||
return image;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Draw2dCrosshairParams {
|
||||
|
||||
@@ -24,16 +24,16 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.opencv.core.*;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.common.util.ColorHelper;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
public class Draw2dTargetsPipe
|
||||
extends CVPipe<Pair<Mat, List<TrackedTarget>>, Mat, Draw2dTargetsPipe.Draw2dContoursParams> {
|
||||
extends MutatingPipe<Pair<Mat, List<TrackedTarget>>, Draw2dTargetsPipe.Draw2dContoursParams> {
|
||||
|
||||
private List<MatOfPoint> m_drawnContours = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected Mat process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
protected Void process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
if (!in.getRight().isEmpty()
|
||||
&& (params.showCentroid
|
||||
|| params.showMaximumBox
|
||||
@@ -115,7 +115,7 @@ public class Draw2dTargetsPipe
|
||||
}
|
||||
}
|
||||
|
||||
return in.getLeft();
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Draw2dContoursParams {
|
||||
|
||||
@@ -28,15 +28,15 @@ import org.opencv.core.MatOfPoint2f;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.common.util.ColorHelper;
|
||||
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
import org.photonvision.vision.target.TargetModel;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
public class Draw3dTargetsPipe
|
||||
extends CVPipe<Pair<Mat, List<TrackedTarget>>, Mat, Draw3dTargetsPipe.Draw3dContoursParams> {
|
||||
extends MutatingPipe<Pair<Mat, List<TrackedTarget>>, Draw3dTargetsPipe.Draw3dContoursParams> {
|
||||
|
||||
@Override
|
||||
protected Mat process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
protected Void process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
for (var target : in.getRight()) {
|
||||
|
||||
// draw convex hull
|
||||
@@ -121,7 +121,7 @@ public class Draw3dTargetsPipe
|
||||
}
|
||||
}
|
||||
|
||||
return in.getLeft();
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Draw3dContoursParams {
|
||||
|
||||
@@ -22,14 +22,14 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
public class DrawCornerDetectionPipe
|
||||
extends CVPipe<Pair<Mat, List<TrackedTarget>>, Mat, DrawCornerDetectionPipe.DrawCornerParams> {
|
||||
extends MutatingPipe<Pair<Mat, List<TrackedTarget>>, DrawCornerDetectionPipe.DrawCornerParams> {
|
||||
|
||||
@Override
|
||||
protected Mat process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
protected Void process(Pair<Mat, List<TrackedTarget>> in) {
|
||||
Mat image = in.getLeft();
|
||||
|
||||
for (var target : in.getRight()) {
|
||||
@@ -39,7 +39,7 @@ public class DrawCornerDetectionPipe
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class DrawCornerParams {
|
||||
|
||||
@@ -20,18 +20,18 @@ package org.photonvision.vision.pipe.impl;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
|
||||
public class ErodeDilatePipe extends CVPipe<Mat, Mat, ErodeDilatePipe.ErodeDilateParams> {
|
||||
public class ErodeDilatePipe extends MutatingPipe<Mat, ErodeDilatePipe.ErodeDilateParams> {
|
||||
@Override
|
||||
protected Mat process(Mat in) {
|
||||
protected Void process(Mat in) {
|
||||
if (params.shouldErode()) {
|
||||
Imgproc.erode(in, in, params.getKernel());
|
||||
}
|
||||
if (params.shouldDilate()) {
|
||||
Imgproc.dilate(in, in, params.getKernel());
|
||||
}
|
||||
return in;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class ErodeDilateParams {
|
||||
|
||||
@@ -19,15 +19,15 @@ package org.photonvision.vision.pipe.impl;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
|
||||
public class OutputMatPipe extends CVPipe<Mat, Mat, OutputMatPipe.OutputMatParams> {
|
||||
public class OutputMatPipe extends MutatingPipe<Mat, OutputMatPipe.OutputMatParams> {
|
||||
|
||||
@Override
|
||||
protected Mat process(Mat in) {
|
||||
protected Void process(Mat in) {
|
||||
// convert input mat
|
||||
Imgproc.cvtColor(in, in, Imgproc.COLOR_GRAY2BGR, 3);
|
||||
return in;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class OutputMatParams {}
|
||||
|
||||
@@ -21,10 +21,10 @@ import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.vision.frame.FrameDivisor;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
|
||||
/** Pipe that resizes an image to a given resolution */
|
||||
public class ResizeImagePipe extends CVPipe<Mat, Mat, ResizeImagePipe.ResizeImageParams> {
|
||||
public class ResizeImagePipe extends MutatingPipe<Mat, ResizeImagePipe.ResizeImageParams> {
|
||||
|
||||
public ResizeImagePipe() {
|
||||
setParams(ResizeImageParams.DEFAULT);
|
||||
@@ -34,10 +34,9 @@ public class ResizeImagePipe extends CVPipe<Mat, Mat, ResizeImagePipe.ResizeImag
|
||||
* Process this pipe
|
||||
*
|
||||
* @param in {@link Mat} to be resized
|
||||
* @return Resized {@link Mat}
|
||||
*/
|
||||
@Override
|
||||
protected Mat process(Mat in) {
|
||||
protected Void process(Mat in) {
|
||||
|
||||
// if a divisor is set, use that instead of a size.
|
||||
if (params.getDivisor() != null) {
|
||||
@@ -47,7 +46,7 @@ public class ResizeImagePipe extends CVPipe<Mat, Mat, ResizeImagePipe.ResizeImag
|
||||
}
|
||||
|
||||
Imgproc.resize(in, in, params.getSize());
|
||||
return in;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class ResizeImageParams {
|
||||
|
||||
@@ -20,10 +20,10 @@ package org.photonvision.vision.pipe.impl;
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.Mat;
|
||||
import org.photonvision.vision.opencv.ImageRotationMode;
|
||||
import org.photonvision.vision.pipe.CVPipe;
|
||||
import org.photonvision.vision.pipe.MutatingPipe;
|
||||
|
||||
/** Pipe that rotates an image to a given orientation */
|
||||
public class RotateImagePipe extends CVPipe<Mat, Mat, RotateImagePipe.RotateImageParams> {
|
||||
public class RotateImagePipe extends MutatingPipe<Mat, RotateImagePipe.RotateImageParams> {
|
||||
|
||||
public RotateImagePipe() {
|
||||
setParams(RotateImageParams.DEFAULT);
|
||||
@@ -40,9 +40,9 @@ public class RotateImagePipe extends CVPipe<Mat, Mat, RotateImagePipe.RotateImag
|
||||
* @return Rotated {@link Mat}
|
||||
*/
|
||||
@Override
|
||||
protected Mat process(Mat in) {
|
||||
protected Void process(Mat in) {
|
||||
Core.rotate(in, in, params.rotation.value);
|
||||
return in;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class RotateImageParams {
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
|
||||
import org.photonvision.vision.frame.Frame;
|
||||
import org.photonvision.vision.frame.FrameStaticProperties;
|
||||
import org.photonvision.vision.opencv.CVMat;
|
||||
import org.photonvision.vision.pipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.CVPipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.impl.Calibrate3dPipe;
|
||||
import org.photonvision.vision.pipe.impl.FindBoardCornersPipe;
|
||||
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||
@@ -86,11 +86,11 @@ public class Calibration3dPipeline
|
||||
|
||||
/*Pass the board corners to the pipe, which will check again to see if all boards are valid
|
||||
and returns the corresponding image and object points*/
|
||||
findCornersPipeOutput = findBoardCornersPipe.apply(boardSnapshots);
|
||||
findCornersPipeOutput = findBoardCornersPipe.run(boardSnapshots);
|
||||
// Increment the time it took to process all board pics to total elapsed time
|
||||
sumPipeNanosElapsed += findCornersPipeOutput.nanosElapsed;
|
||||
|
||||
calibrationOutput = calibrate3dPipe.apply(findCornersPipeOutput.result);
|
||||
calibrationOutput = calibrate3dPipe.run(findCornersPipeOutput.output);
|
||||
sumPipeNanosElapsed += calibrationOutput.nanosElapsed;
|
||||
|
||||
calibrate = false;
|
||||
@@ -131,10 +131,10 @@ public class Calibration3dPipeline
|
||||
}
|
||||
|
||||
public double[] perViewErrors() {
|
||||
return calibrationOutput.result.perViewErrors;
|
||||
return calibrationOutput.output.perViewErrors;
|
||||
}
|
||||
|
||||
public CameraCalibrationCoefficients cameraCalibrationCoefficients() {
|
||||
return calibrationOutput.result;
|
||||
return calibrationOutput.output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ import org.photonvision.common.util.math.MathUtils;
|
||||
import org.photonvision.vision.frame.Frame;
|
||||
import org.photonvision.vision.frame.FrameStaticProperties;
|
||||
import org.photonvision.vision.opencv.*;
|
||||
import org.photonvision.vision.pipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.CVPipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.impl.*;
|
||||
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||
import org.photonvision.vision.target.PotentialTarget;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
@SuppressWarnings({"DuplicatedCode", "UnusedAssignment"})
|
||||
@SuppressWarnings({"DuplicatedCode"})
|
||||
public class ColoredShapePipeline
|
||||
extends CVPipeline<CVPipelineResult, ColoredShapePipelineSettings> {
|
||||
|
||||
@@ -56,7 +56,6 @@ public class ColoredShapePipeline
|
||||
private final Draw3dTargetsPipe draw3dTargetsPipe = new Draw3dTargetsPipe();
|
||||
|
||||
private final Mat rawInputMat = new Mat();
|
||||
private final DualMat outputMats = new DualMat();
|
||||
private final Point[] rectPoints = new Point[4];
|
||||
|
||||
public ColoredShapePipeline() {
|
||||
@@ -180,123 +179,110 @@ public class ColoredShapePipeline
|
||||
|
||||
long sumPipeNanosElapsed = 0L;
|
||||
|
||||
CVPipeResult<Mat> rotateImageResult = rotateImagePipe.apply(frame.image.getMat());
|
||||
var rotateImageResult = rotateImagePipe.run(frame.image.getMat());
|
||||
sumPipeNanosElapsed += rotateImageResult.nanosElapsed;
|
||||
|
||||
rawInputMat.release();
|
||||
frame.image.getMat().copyTo(rawInputMat);
|
||||
|
||||
CVPipeResult<Mat> erodeDilateResult = erodeDilatePipe.apply(rotateImageResult.result);
|
||||
var erodeDilateResult = erodeDilatePipe.run(rawInputMat);
|
||||
sumPipeNanosElapsed += erodeDilateResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> hsvPipeResult = hsvPipe.apply(erodeDilateResult.result);
|
||||
CVPipeResult<Mat> hsvPipeResult = hsvPipe.run(rawInputMat);
|
||||
sumPipeNanosElapsed += hsvPipeResult.nanosElapsed;
|
||||
|
||||
// the first is the raw input mat, the second is the HSVPipe result
|
||||
outputMats.first = rawInputMat;
|
||||
outputMats.second = hsvPipeResult.result;
|
||||
|
||||
CVPipeResult<List<Contour>> findContoursResult = findContoursPipe.apply(hsvPipeResult.result);
|
||||
CVPipeResult<List<Contour>> findContoursResult = findContoursPipe.run(hsvPipeResult.output);
|
||||
sumPipeNanosElapsed += findContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<Contour>> speckleRejectResult =
|
||||
speckleRejectPipe.apply(findContoursResult.result);
|
||||
speckleRejectPipe.run(findContoursResult.output);
|
||||
sumPipeNanosElapsed += speckleRejectResult.nanosElapsed;
|
||||
|
||||
List<CVShape> shapes;
|
||||
if (settings.desiredShape == ContourShape.Circle) {
|
||||
CVPipeResult<List<CVShape>> findCirclesResult =
|
||||
findCirclesPipe.apply(Pair.of(hsvPipeResult.result, speckleRejectResult.result));
|
||||
findCirclesPipe.run(Pair.of(hsvPipeResult.output, speckleRejectResult.output));
|
||||
sumPipeNanosElapsed += findCirclesResult.nanosElapsed;
|
||||
shapes = findCirclesResult.result;
|
||||
shapes = findCirclesResult.output;
|
||||
} else {
|
||||
CVPipeResult<List<CVShape>> findPolygonsResult =
|
||||
findPolygonPipe.apply(speckleRejectResult.result);
|
||||
findPolygonPipe.run(speckleRejectResult.output);
|
||||
sumPipeNanosElapsed += findPolygonsResult.nanosElapsed;
|
||||
shapes = findPolygonsResult.result;
|
||||
shapes = findPolygonsResult.output;
|
||||
}
|
||||
|
||||
CVPipeResult<List<CVShape>> filterShapeResult = filterShapesPipe.apply(shapes);
|
||||
CVPipeResult<List<CVShape>> filterShapeResult = filterShapesPipe.run(shapes);
|
||||
sumPipeNanosElapsed += filterShapeResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<PotentialTarget>> groupContoursResult =
|
||||
groupContoursPipe.apply(
|
||||
filterShapeResult.result.stream()
|
||||
groupContoursPipe.run(
|
||||
filterShapeResult.output.stream()
|
||||
.map(CVShape::getContour)
|
||||
.collect(Collectors.toList()));
|
||||
sumPipeNanosElapsed += groupContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<PotentialTarget>> sortContoursResult =
|
||||
sortContoursPipe.apply(groupContoursResult.result);
|
||||
sortContoursPipe.run(groupContoursResult.output);
|
||||
sumPipeNanosElapsed += sortContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<TrackedTarget>> collect2dTargetsResult =
|
||||
collect2dTargetsPipe.apply(sortContoursResult.result);
|
||||
collect2dTargetsPipe.run(sortContoursResult.output);
|
||||
sumPipeNanosElapsed += collect2dTargetsResult.nanosElapsed;
|
||||
|
||||
List<TrackedTarget> targetList;
|
||||
|
||||
if (settings.solvePNPEnabled && settings.desiredShape == ContourShape.Circle) {
|
||||
var cornerDetectionResult = cornerDetectionPipe.apply(collect2dTargetsResult.result);
|
||||
collect2dTargetsResult.result.forEach(
|
||||
var cornerDetectionResult = cornerDetectionPipe.run(collect2dTargetsResult.output);
|
||||
collect2dTargetsResult.output.forEach(
|
||||
shape -> {
|
||||
shape.getMinAreaRect().points(rectPoints);
|
||||
shape.setCorners(Arrays.asList(rectPoints));
|
||||
});
|
||||
sumPipeNanosElapsed += cornerDetectionResult.nanosElapsed;
|
||||
|
||||
var solvePNPResult = solvePNPPipe.apply(cornerDetectionResult.result);
|
||||
var solvePNPResult = solvePNPPipe.run(cornerDetectionResult.output);
|
||||
sumPipeNanosElapsed += solvePNPResult.nanosElapsed;
|
||||
|
||||
targetList = solvePNPResult.result;
|
||||
targetList = solvePNPResult.output;
|
||||
} else {
|
||||
targetList = collect2dTargetsResult.result;
|
||||
targetList = collect2dTargetsResult.output;
|
||||
}
|
||||
|
||||
// the first is the raw input mat, the second is the HSVPipe result
|
||||
CVPipeResult<Mat> drawOnInputResult, drawOnOutputResult;
|
||||
|
||||
CVPipeResult<Mat> draw2dCrosshairResultOnInput =
|
||||
draw2dCrosshairPipe.apply(Pair.of(outputMats.first, targetList));
|
||||
// Draw 2D Crosshair on input and output
|
||||
var draw2dCrosshairResultOnInput = draw2dCrosshairPipe.run(Pair.of(rawInputMat, targetList));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnInput.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> draw2dCrosshairResultOnOutput =
|
||||
draw2dCrosshairPipe.apply(Pair.of(outputMats.second, targetList));
|
||||
var draw2dCrosshairResultOnOutput =
|
||||
draw2dCrosshairPipe.run(Pair.of(hsvPipeResult.output, targetList));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnOutput.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> draw2dContoursResultOnInput =
|
||||
draw2DTargetsPipe.apply(
|
||||
Pair.of(draw2dCrosshairResultOnInput.result, collect2dTargetsResult.result));
|
||||
// Draw 2D contours on input and output
|
||||
var draw2dContoursResultOnInput =
|
||||
draw2DTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += draw2dContoursResultOnInput.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> draw2dContoursResultOnOutput =
|
||||
draw2DTargetsPipe.apply(
|
||||
Pair.of(draw2dCrosshairResultOnOutput.result, collect2dTargetsResult.result));
|
||||
var draw2dContoursResultOnOutput =
|
||||
draw2DTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += draw2dContoursResultOnOutput.nanosElapsed;
|
||||
|
||||
if (settings.solvePNPEnabled && settings.desiredShape == ContourShape.Circle) {
|
||||
drawOnInputResult =
|
||||
draw3dTargetsPipe.apply(
|
||||
Pair.of(draw2dContoursResultOnInput.result, collect2dTargetsResult.result));
|
||||
var drawOnInputResult =
|
||||
draw3dTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += drawOnInputResult.nanosElapsed;
|
||||
|
||||
drawOnOutputResult =
|
||||
draw3dTargetsPipe.apply(
|
||||
Pair.of(draw2dContoursResultOnOutput.result, collect2dTargetsResult.result));
|
||||
var drawOnOutputResult =
|
||||
draw3dTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += drawOnOutputResult.nanosElapsed;
|
||||
} else {
|
||||
drawOnInputResult = draw2dContoursResultOnInput;
|
||||
drawOnOutputResult = draw2dContoursResultOnOutput;
|
||||
}
|
||||
|
||||
// Convert single-channel HSV output mat to 3-channel BGR in preparation for streaming
|
||||
CVPipeResult<Mat> outputMatPipeResult = outputMatPipe.apply(outputMats.second);
|
||||
var outputMatPipeResult = outputMatPipe.run(hsvPipeResult.output);
|
||||
sumPipeNanosElapsed += outputMatPipeResult.nanosElapsed;
|
||||
|
||||
return new CVPipelineResult(
|
||||
MathUtils.nanosToMillis(sumPipeNanosElapsed),
|
||||
targetList,
|
||||
new Frame(new CVMat(outputMats.second), frame.frameStaticProperties),
|
||||
new Frame(new CVMat(outputMats.first), frame.frameStaticProperties));
|
||||
new Frame(new CVMat(hsvPipeResult.output), frame.frameStaticProperties),
|
||||
new Frame(new CVMat(rawInputMat), frame.frameStaticProperties));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +53,16 @@ public class DriverModePipeline
|
||||
@Override
|
||||
public DriverModePipelineResult process(Frame frame, DriverModePipelineSettings settings) {
|
||||
// apply pipes
|
||||
var rotateImageResult = rotateImagePipe.apply(frame.image.getMat());
|
||||
var draw2dCrosshairResult =
|
||||
draw2dCrosshairPipe.apply(Pair.of(rotateImageResult.result, List.of()));
|
||||
var inputMat = frame.image.getMat();
|
||||
|
||||
var rotateImageResult = rotateImagePipe.run(inputMat);
|
||||
var draw2dCrosshairResult = draw2dCrosshairPipe.run(Pair.of(inputMat, List.of()));
|
||||
|
||||
// calculate elapsed nanoseconds
|
||||
long totalNanos = rotateImageResult.nanosElapsed + draw2dCrosshairResult.nanosElapsed;
|
||||
|
||||
return new DriverModePipelineResult(
|
||||
MathUtils.nanosToMillis(totalNanos),
|
||||
new Frame(new CVMat(draw2dCrosshairResult.result), frame.frameStaticProperties));
|
||||
new Frame(new CVMat(inputMat), frame.frameStaticProperties));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ import org.photonvision.vision.frame.Frame;
|
||||
import org.photonvision.vision.frame.FrameStaticProperties;
|
||||
import org.photonvision.vision.opencv.CVMat;
|
||||
import org.photonvision.vision.opencv.Contour;
|
||||
import org.photonvision.vision.opencv.DualMat;
|
||||
import org.photonvision.vision.pipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.CVPipe.CVPipeResult;
|
||||
import org.photonvision.vision.pipe.impl.Collect2dTargetsPipe;
|
||||
import org.photonvision.vision.pipe.impl.CornerDetectionPipe;
|
||||
import org.photonvision.vision.pipe.impl.Draw2dCrosshairPipe;
|
||||
@@ -47,7 +46,7 @@ import org.photonvision.vision.target.PotentialTarget;
|
||||
import org.photonvision.vision.target.TrackedTarget;
|
||||
|
||||
/** Represents a pipeline for tracking retro-reflective targets. */
|
||||
@SuppressWarnings({"UnusedAssignment", "DuplicatedCode"})
|
||||
@SuppressWarnings({"DuplicatedCode"})
|
||||
public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectivePipelineSettings> {
|
||||
|
||||
private final RotateImagePipe rotateImagePipe = new RotateImagePipe();
|
||||
@@ -67,7 +66,6 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
private final Draw3dTargetsPipe draw3dTargetsPipe = new Draw3dTargetsPipe();
|
||||
|
||||
private final Mat rawInputMat = new Mat();
|
||||
private final DualMat outputMats = new DualMat();
|
||||
|
||||
public ReflectivePipeline() {
|
||||
settings = new ReflectivePipelineSettings();
|
||||
@@ -167,107 +165,92 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
|
||||
long sumPipeNanosElapsed = 0L;
|
||||
|
||||
CVPipeResult<Mat> rotateImageResult = rotateImagePipe.apply(frame.image.getMat());
|
||||
var rotateImageResult = rotateImagePipe.run(frame.image.getMat());
|
||||
sumPipeNanosElapsed += rotateImageResult.nanosElapsed;
|
||||
|
||||
rawInputMat.release();
|
||||
frame.image.getMat().copyTo(rawInputMat);
|
||||
|
||||
CVPipeResult<Mat> erodeDilateResult = erodeDilatePipe.apply(rotateImageResult.result);
|
||||
var erodeDilateResult = erodeDilatePipe.run(rawInputMat);
|
||||
sumPipeNanosElapsed += erodeDilateResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> hsvPipeResult = hsvPipe.apply(erodeDilateResult.result);
|
||||
CVPipeResult<Mat> hsvPipeResult = hsvPipe.run(rawInputMat);
|
||||
sumPipeNanosElapsed += hsvPipeResult.nanosElapsed;
|
||||
|
||||
// the first is the raw input mat, the second is the HSVPipe result
|
||||
outputMats.first = rawInputMat;
|
||||
outputMats.second = hsvPipeResult.result;
|
||||
|
||||
CVPipeResult<List<Contour>> findContoursResult = findContoursPipe.apply(hsvPipeResult.result);
|
||||
CVPipeResult<List<Contour>> findContoursResult = findContoursPipe.run(hsvPipeResult.output);
|
||||
sumPipeNanosElapsed += findContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<Contour>> speckleRejectResult =
|
||||
speckleRejectPipe.apply(findContoursResult.result);
|
||||
speckleRejectPipe.run(findContoursResult.output);
|
||||
sumPipeNanosElapsed += speckleRejectResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<Contour>> filterContoursResult =
|
||||
filterContoursPipe.apply(speckleRejectResult.result);
|
||||
filterContoursPipe.run(speckleRejectResult.output);
|
||||
sumPipeNanosElapsed += filterContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<PotentialTarget>> groupContoursResult =
|
||||
groupContoursPipe.apply(filterContoursResult.result);
|
||||
groupContoursPipe.run(filterContoursResult.output);
|
||||
sumPipeNanosElapsed += groupContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<PotentialTarget>> sortContoursResult =
|
||||
sortContoursPipe.apply(groupContoursResult.result);
|
||||
sortContoursPipe.run(groupContoursResult.output);
|
||||
sumPipeNanosElapsed += sortContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<TrackedTarget>> collect2dTargetsResult =
|
||||
collect2dTargetsPipe.apply(sortContoursResult.result);
|
||||
collect2dTargetsPipe.run(sortContoursResult.output);
|
||||
sumPipeNanosElapsed += collect2dTargetsResult.nanosElapsed;
|
||||
|
||||
List<TrackedTarget> targetList;
|
||||
|
||||
// 3d stuff
|
||||
if (settings.solvePNPEnabled) {
|
||||
var cornerDetectionResult = cornerDetectionPipe.apply(collect2dTargetsResult.result);
|
||||
var cornerDetectionResult = cornerDetectionPipe.run(collect2dTargetsResult.output);
|
||||
sumPipeNanosElapsed += cornerDetectionResult.nanosElapsed;
|
||||
|
||||
var solvePNPResult = solvePNPPipe.apply(cornerDetectionResult.result);
|
||||
var solvePNPResult = solvePNPPipe.run(cornerDetectionResult.output);
|
||||
sumPipeNanosElapsed += solvePNPResult.nanosElapsed;
|
||||
|
||||
targetList = solvePNPResult.result;
|
||||
targetList = solvePNPResult.output;
|
||||
} else {
|
||||
targetList = collect2dTargetsResult.result;
|
||||
targetList = collect2dTargetsResult.output;
|
||||
}
|
||||
|
||||
// the first is the raw input mat, the second is the HSVPipe result
|
||||
CVPipeResult<Mat> drawOnInputResult, drawOnOutputResult;
|
||||
|
||||
// Draw 2D Crosshair on input and output
|
||||
CVPipeResult<Mat> draw2dCrosshairResultOnInput =
|
||||
draw2dCrosshairPipe.apply(Pair.of(outputMats.first, targetList));
|
||||
var draw2dCrosshairResultOnInput = draw2dCrosshairPipe.run(Pair.of(rawInputMat, targetList));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnInput.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> draw2dCrosshairResultOnOutput =
|
||||
draw2dCrosshairPipe.apply(Pair.of(outputMats.second, targetList));
|
||||
var draw2dCrosshairResultOnOutput =
|
||||
draw2dCrosshairPipe.run(Pair.of(hsvPipeResult.output, targetList));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnOutput.nanosElapsed;
|
||||
|
||||
// Draw 2D contours on input and output
|
||||
CVPipeResult<Mat> draw2dContoursResultOnInput =
|
||||
draw2DTargetsPipe.apply(
|
||||
Pair.of(draw2dCrosshairResultOnInput.result, collect2dTargetsResult.result));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnInput.nanosElapsed;
|
||||
var draw2dContoursResultOnInput =
|
||||
draw2DTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += draw2dContoursResultOnInput.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> draw2dContoursResultOnOutput =
|
||||
draw2DTargetsPipe.apply(
|
||||
Pair.of(draw2dCrosshairResultOnOutput.result, collect2dTargetsResult.result));
|
||||
var draw2dContoursResultOnOutput =
|
||||
draw2DTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += draw2dContoursResultOnOutput.nanosElapsed;
|
||||
|
||||
// Draw 3D Targets on input and output if necessary
|
||||
if (settings.solvePNPEnabled) {
|
||||
drawOnInputResult =
|
||||
draw3dTargetsPipe.apply(
|
||||
Pair.of(draw2dContoursResultOnInput.result, collect2dTargetsResult.result));
|
||||
var drawOnInputResult =
|
||||
draw3dTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += drawOnInputResult.nanosElapsed;
|
||||
|
||||
drawOnOutputResult =
|
||||
draw3dTargetsPipe.apply(
|
||||
Pair.of(draw2dContoursResultOnOutput.result, collect2dTargetsResult.result));
|
||||
var drawOnOutputResult =
|
||||
draw3dTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += drawOnOutputResult.nanosElapsed;
|
||||
} else {
|
||||
drawOnInputResult = draw2dContoursResultOnInput;
|
||||
drawOnOutputResult = draw2dContoursResultOnOutput;
|
||||
}
|
||||
|
||||
// Convert single-channel HSV output mat to 3-channel BGR in preparation for streaming
|
||||
CVPipeResult<Mat> outputMatPipeResult = outputMatPipe.apply(outputMats.second);
|
||||
var outputMatPipeResult = outputMatPipe.run(hsvPipeResult.output);
|
||||
sumPipeNanosElapsed += outputMatPipeResult.nanosElapsed;
|
||||
|
||||
return new CVPipelineResult(
|
||||
MathUtils.nanosToMillis(sumPipeNanosElapsed),
|
||||
targetList,
|
||||
new Frame(new CVMat(outputMats.second), frame.frameStaticProperties),
|
||||
new Frame(new CVMat(outputMats.first), frame.frameStaticProperties));
|
||||
new Frame(new CVMat(hsvPipeResult.output), frame.frameStaticProperties),
|
||||
new Frame(new CVMat(rawInputMat), frame.frameStaticProperties));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user