Add MutatingPipe (#44)

* Add MutatingPipe, use references in MutatingPipes

* Apply spotless

* Fix NPE in ColoredShapePipeline
This commit is contained in:
Banks T
2020-07-18 20:15:58 -04:00
committed by GitHub
parent d8d6c13679
commit 1b7ece994a
16 changed files with 127 additions and 161 deletions

View File

@@ -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;
}
}

View File

@@ -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> {}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}