mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-20 00:51:41 +00:00
Pipe profiling (#50)
This class helps profile pipelines by measuring individual pipe processing times
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.pipeline;
|
||||
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
import org.photonvision.common.util.math.MathUtils;
|
||||
|
||||
public class PipelineProfiler {
|
||||
private static final Logger reflectiveLogger =
|
||||
new Logger(ReflectivePipeline.class, LogGroup.VisionModule);
|
||||
private static final Logger coloredShapeLogger =
|
||||
new Logger(ColoredShapePipeline.class, LogGroup.VisionModule);
|
||||
|
||||
public static final int ReflectivePipeCount = 19;
|
||||
|
||||
/**
|
||||
* Indices for Reflective profiling 0 - rotateImagePipe 1 - inputCopy (not a pipe) 2 -
|
||||
* erodeDilatePipe 3 - hsvPipe 4 - findContoursPipe 5 - speckleRejectPipe 6 - filterContoursPipe 7
|
||||
* - groupContoursPipe 8 - sortContoursPipe 9 - collect2dTargetsPipe 10 - cornerDetectionPipe
|
||||
* (OPTIONAL) 11 - solvePNPPipe (OPTIONAL) 12 - outputMatPipe 13 - draw2dCrosshairPipe (on input)
|
||||
* 14 - draw2dCrosshairPipe (on output) 15 - draw2dTargetsPipe (on input) 16 - draw2dTargetsPipe
|
||||
* (on output) 17 - draw3dTargetsPipe (OPTIONAL, on input) 18 - draw3dTargetsPipe (OPTIONAL, on
|
||||
* output)
|
||||
*/
|
||||
private static final String[] ReflectivePipeNames =
|
||||
new String[] {
|
||||
"RotateImage",
|
||||
"InputCopy",
|
||||
"ErodeDilate",
|
||||
"HSV",
|
||||
"FindContours",
|
||||
"SpeckleReject",
|
||||
"FilterContours",
|
||||
"GroupContours",
|
||||
"SortContours",
|
||||
"Collect2dTargets",
|
||||
"CornerDetection",
|
||||
"SolvePNP",
|
||||
"OutputConversion",
|
||||
"Draw2dCrosshairInput",
|
||||
"Draw2dCrosshairOutput",
|
||||
"Draw2dTargetsInput",
|
||||
"Draw2dTargetsOutput",
|
||||
"Draw3dTargetsInput",
|
||||
"Draw3dTargetsOutput",
|
||||
};
|
||||
|
||||
protected static String getReflectiveProfileString(long[] nanos) {
|
||||
if (nanos.length != ReflectivePipeCount) {
|
||||
return "Invalid data";
|
||||
}
|
||||
|
||||
var sb = new StringBuilder("Profiling - ");
|
||||
double totalMs = 0;
|
||||
for (int i = 0; i < nanos.length; i++) {
|
||||
if ((i == 10 || i == 11 || i == 17 || i == 18) && nanos[i] == 0) {
|
||||
continue; // skip empty pipe profiles
|
||||
}
|
||||
|
||||
sb.append(ReflectivePipeNames[i]);
|
||||
sb.append(": ");
|
||||
var ms = MathUtils.roundTo(nanos[i] / 1e+6, 3);
|
||||
totalMs += ms;
|
||||
sb.append(ms);
|
||||
sb.append("ms");
|
||||
// boolean isLast = (i + 1 == 17 && nanos[i+1] == 0) || i == 18;
|
||||
// if (isLast) {
|
||||
// var foo = "bar";
|
||||
// } else {
|
||||
sb.append(", ");
|
||||
// }
|
||||
}
|
||||
|
||||
sb.append("Total: ");
|
||||
sb.append(MathUtils.roundTo(totalMs, 3));
|
||||
sb.append("ms");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void printReflectiveProfile(long[] nanos) {
|
||||
reflectiveLogger.trace(() -> getReflectiveProfileString(nanos));
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,6 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
private final RotateImagePipe rotateImagePipe = new RotateImagePipe();
|
||||
private final ErodeDilatePipe erodeDilatePipe = new ErodeDilatePipe();
|
||||
private final HSVPipe hsvPipe = new HSVPipe();
|
||||
private final OutputMatPipe outputMatPipe = new OutputMatPipe();
|
||||
private final FindContoursPipe findContoursPipe = new FindContoursPipe();
|
||||
private final SpeckleRejectPipe speckleRejectPipe = new SpeckleRejectPipe();
|
||||
private final FilterContoursPipe filterContoursPipe = new FilterContoursPipe();
|
||||
@@ -61,11 +60,13 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
private final Collect2dTargetsPipe collect2dTargetsPipe = new Collect2dTargetsPipe();
|
||||
private final CornerDetectionPipe cornerDetectionPipe = new CornerDetectionPipe();
|
||||
private final SolvePNPPipe solvePNPPipe = new SolvePNPPipe();
|
||||
private final OutputMatPipe outputMatPipe = new OutputMatPipe();
|
||||
private final Draw2dCrosshairPipe draw2dCrosshairPipe = new Draw2dCrosshairPipe();
|
||||
private final Draw2dTargetsPipe draw2DTargetsPipe = new Draw2dTargetsPipe();
|
||||
private final Draw2dTargetsPipe draw2dTargetsPipe = new Draw2dTargetsPipe();
|
||||
private final Draw3dTargetsPipe draw3dTargetsPipe = new Draw3dTargetsPipe();
|
||||
|
||||
private final Mat rawInputMat = new Mat();
|
||||
private final long[] pipeProfileNanos = new long[PipelineProfiler.ReflectivePipeCount];
|
||||
|
||||
public ReflectivePipeline() {
|
||||
settings = new ReflectivePipelineSettings();
|
||||
@@ -141,7 +142,7 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
|
||||
Draw2dTargetsPipe.Draw2dContoursParams draw2dContoursParams =
|
||||
new Draw2dTargetsPipe.Draw2dContoursParams(settings.outputShowMultipleTargets);
|
||||
draw2DTargetsPipe.setParams(draw2dContoursParams);
|
||||
draw2dTargetsPipe.setParams(draw2dContoursParams);
|
||||
|
||||
Draw2dCrosshairPipe.Draw2dCrosshairParams draw2dCrosshairParams =
|
||||
new Draw2dCrosshairPipe.Draw2dCrosshairParams(
|
||||
@@ -166,87 +167,99 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
|
||||
long sumPipeNanosElapsed = 0L;
|
||||
|
||||
var rotateImageResult = rotateImagePipe.run(frame.image.getMat());
|
||||
sumPipeNanosElapsed += rotateImageResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[0] = rotateImageResult.nanosElapsed;
|
||||
|
||||
// TODO: make this a pipe?
|
||||
long inputCopyStartNanos = System.nanoTime();
|
||||
rawInputMat.release();
|
||||
frame.image.getMat().copyTo(rawInputMat);
|
||||
long inputCopyElapsedNanos = System.nanoTime() - inputCopyStartNanos;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[1] = inputCopyElapsedNanos;
|
||||
|
||||
var erodeDilateResult = erodeDilatePipe.run(rawInputMat);
|
||||
sumPipeNanosElapsed += erodeDilateResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[2] = erodeDilateResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<Mat> hsvPipeResult = hsvPipe.run(rawInputMat);
|
||||
sumPipeNanosElapsed += hsvPipeResult.nanosElapsed;
|
||||
pipeProfileNanos[3] = pipeProfileNanos[3] = hsvPipeResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<Contour>> findContoursResult = findContoursPipe.run(hsvPipeResult.output);
|
||||
sumPipeNanosElapsed += findContoursResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[4] = findContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<Contour>> speckleRejectResult =
|
||||
speckleRejectPipe.run(findContoursResult.output);
|
||||
sumPipeNanosElapsed += speckleRejectResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[5] = speckleRejectResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<Contour>> filterContoursResult =
|
||||
filterContoursPipe.run(speckleRejectResult.output);
|
||||
sumPipeNanosElapsed += filterContoursResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[6] = filterContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<PotentialTarget>> groupContoursResult =
|
||||
groupContoursPipe.run(filterContoursResult.output);
|
||||
sumPipeNanosElapsed += groupContoursResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[7] = groupContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<PotentialTarget>> sortContoursResult =
|
||||
sortContoursPipe.run(groupContoursResult.output);
|
||||
sumPipeNanosElapsed += sortContoursResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[8] = sortContoursResult.nanosElapsed;
|
||||
|
||||
CVPipeResult<List<TrackedTarget>> collect2dTargetsResult =
|
||||
collect2dTargetsPipe.run(sortContoursResult.output);
|
||||
sumPipeNanosElapsed += collect2dTargetsResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[9] = collect2dTargetsResult.nanosElapsed;
|
||||
|
||||
List<TrackedTarget> targetList;
|
||||
|
||||
// 3d stuff
|
||||
if (settings.solvePNPEnabled) {
|
||||
var cornerDetectionResult = cornerDetectionPipe.run(collect2dTargetsResult.output);
|
||||
sumPipeNanosElapsed += cornerDetectionResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[10] = cornerDetectionResult.nanosElapsed;
|
||||
|
||||
var solvePNPResult = solvePNPPipe.run(cornerDetectionResult.output);
|
||||
sumPipeNanosElapsed += solvePNPResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[11] = solvePNPResult.nanosElapsed;
|
||||
|
||||
targetList = solvePNPResult.output;
|
||||
} else {
|
||||
pipeProfileNanos[10] = 0;
|
||||
pipeProfileNanos[11] = 0;
|
||||
targetList = collect2dTargetsResult.output;
|
||||
}
|
||||
|
||||
// Convert single-channel HSV output mat to 3-channel BGR in preparation for streaming
|
||||
var outputMatPipeResult = outputMatPipe.run(hsvPipeResult.output);
|
||||
sumPipeNanosElapsed += outputMatPipeResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[12] = outputMatPipeResult.nanosElapsed;
|
||||
|
||||
// Draw 2D Crosshair on input and output
|
||||
var draw2dCrosshairResultOnInput = draw2dCrosshairPipe.run(Pair.of(rawInputMat, targetList));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnInput.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[13] = draw2dCrosshairResultOnInput.nanosElapsed;
|
||||
|
||||
var draw2dCrosshairResultOnOutput =
|
||||
draw2dCrosshairPipe.run(Pair.of(hsvPipeResult.output, targetList));
|
||||
sumPipeNanosElapsed += draw2dCrosshairResultOnOutput.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[14] = draw2dCrosshairResultOnOutput.nanosElapsed;
|
||||
|
||||
// Draw 2D contours on input and output
|
||||
var draw2dContoursResultOnInput =
|
||||
draw2DTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += draw2dContoursResultOnInput.nanosElapsed;
|
||||
var draw2dTargetsOnInput =
|
||||
draw2dTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += pipeProfileNanos[15] = draw2dTargetsOnInput.nanosElapsed;
|
||||
|
||||
var draw2dContoursResultOnOutput =
|
||||
draw2DTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += draw2dContoursResultOnOutput.nanosElapsed;
|
||||
var draw2dTargetsOnOutput =
|
||||
draw2dTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += pipeProfileNanos[16] = draw2dTargetsOnOutput.nanosElapsed;
|
||||
|
||||
// Draw 3D Targets on input and output if necessary
|
||||
if (settings.solvePNPEnabled) {
|
||||
var drawOnInputResult =
|
||||
draw3dTargetsPipe.run(Pair.of(rawInputMat, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += drawOnInputResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[17] = drawOnInputResult.nanosElapsed;
|
||||
|
||||
var drawOnOutputResult =
|
||||
draw3dTargetsPipe.run(Pair.of(hsvPipeResult.output, collect2dTargetsResult.output));
|
||||
sumPipeNanosElapsed += drawOnOutputResult.nanosElapsed;
|
||||
sumPipeNanosElapsed += pipeProfileNanos[18] = drawOnOutputResult.nanosElapsed;
|
||||
} else {
|
||||
pipeProfileNanos[17] = 0;
|
||||
pipeProfileNanos[18] = 0;
|
||||
}
|
||||
|
||||
PipelineProfiler.printReflectiveProfile(pipeProfileNanos);
|
||||
|
||||
return new CVPipelineResult(
|
||||
MathUtils.nanosToMillis(sumPipeNanosElapsed),
|
||||
targetList,
|
||||
|
||||
Reference in New Issue
Block a user