2019-11-23 11:55:20 -05:00
|
|
|
package com.chameleonvision.vision.pipeline;
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-25 05:34:04 -05:00
|
|
|
import com.chameleonvision.vision.camera.CameraCapture;
|
|
|
|
|
import com.chameleonvision.vision.camera.CaptureStaticProperties;
|
2019-11-23 11:55:20 -05:00
|
|
|
import com.chameleonvision.vision.pipeline.pipes.*;
|
|
|
|
|
import com.chameleonvision.vision.enums.ImageRotation;
|
2019-11-07 11:15:54 -05:00
|
|
|
import org.apache.commons.lang3.tuple.Pair;
|
2019-11-05 07:47:15 -08:00
|
|
|
import org.opencv.core.*;
|
|
|
|
|
import org.opencv.imgproc.Imgproc;
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
2019-11-23 11:55:20 -05:00
|
|
|
import static com.chameleonvision.vision.pipeline.CVPipeline2d.*;
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-10 11:47:56 -05:00
|
|
|
@SuppressWarnings("WeakerAccess")
|
|
|
|
|
public class CVPipeline2d extends CVPipeline<CVPipeline2dResult, CVPipeline2dSettings> {
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
private Mat rawCameraMat = new Mat();
|
2019-11-25 16:40:23 -05:00
|
|
|
|
2019-11-24 16:54:10 -08:00
|
|
|
private RotateFlipPipe rotateFlipPipe;
|
|
|
|
|
private BlurPipe blurPipe;
|
|
|
|
|
private ErodeDilatePipe erodeDilatePipe;
|
|
|
|
|
private HsvPipe hsvPipe;
|
|
|
|
|
private FindContoursPipe findContoursPipe;
|
|
|
|
|
private FilterContoursPipe filterContoursPipe;
|
|
|
|
|
private SpeckleRejectPipe speckleRejectPipe;
|
|
|
|
|
private GroupContoursPipe groupContoursPipe;
|
|
|
|
|
private SortContoursPipe sortContoursPipe;
|
|
|
|
|
private Collect2dTargetsPipe collect2dTargetsPipe;
|
2019-11-25 16:40:23 -05:00
|
|
|
private Draw2dContoursPipe.Draw2dContoursSettings draw2dContoursSettings;
|
|
|
|
|
private Draw2dContoursPipe draw2dContoursPipe;
|
|
|
|
|
private OutputMatPipe outputMatPipe;
|
|
|
|
|
|
|
|
|
|
private StringBuilder pipelineTimeStringBuilder = new StringBuilder();
|
|
|
|
|
private CaptureStaticProperties camProps;
|
|
|
|
|
private Scalar hsvLower, hsvUpper;
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
public CVPipeline2d() {
|
|
|
|
|
super(new CVPipeline2dSettings());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CVPipeline2d(String name) {
|
|
|
|
|
super(name, new CVPipeline2dSettings());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CVPipeline2d(CVPipeline2dSettings settings) {
|
|
|
|
|
super(settings);
|
2019-11-05 07:47:15 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-24 16:54:10 -08:00
|
|
|
@Override
|
2019-11-25 05:34:04 -05:00
|
|
|
public void initPipeline(CameraCapture process) {
|
2019-11-24 16:54:10 -08:00
|
|
|
super.initPipeline(process);
|
|
|
|
|
|
2019-11-25 16:40:23 -05:00
|
|
|
camProps = cameraCapture.getProperties().getStaticProperties();
|
|
|
|
|
hsvLower = new Scalar(settings.hue.get(0).intValue(), settings.saturation.get(0).intValue(), settings.value.get(0).intValue());
|
|
|
|
|
hsvUpper = new Scalar(settings.hue.get(1).intValue(), settings.saturation.get(1).intValue(), settings.value.get(1).intValue());
|
2019-11-24 16:54:10 -08:00
|
|
|
|
|
|
|
|
rotateFlipPipe = new RotateFlipPipe(ImageRotation.DEG_0, settings.flipMode);
|
|
|
|
|
blurPipe = new BlurPipe(5);
|
|
|
|
|
erodeDilatePipe = new ErodeDilatePipe(settings.erode, settings.dilate, 7);
|
|
|
|
|
hsvPipe = new HsvPipe(hsvLower, hsvUpper);
|
|
|
|
|
findContoursPipe = new FindContoursPipe();
|
|
|
|
|
filterContoursPipe = new FilterContoursPipe(settings.area, settings.ratio, settings.extent, camProps);
|
|
|
|
|
speckleRejectPipe = new SpeckleRejectPipe(settings.speckle.doubleValue());
|
|
|
|
|
groupContoursPipe = new GroupContoursPipe(settings.targetGroup, settings.targetIntersection);
|
|
|
|
|
sortContoursPipe = new SortContoursPipe(settings.sortMode, camProps);
|
|
|
|
|
collect2dTargetsPipe = new Collect2dTargetsPipe(settings.calibrationMode, settings.point,
|
|
|
|
|
settings.dualTargetCalibrationM, settings.dualTargetCalibrationB, camProps);
|
2019-11-25 16:40:23 -05:00
|
|
|
draw2dContoursSettings = new Draw2dContoursPipe.Draw2dContoursSettings();
|
|
|
|
|
// TODO: make settable from UI? config?
|
|
|
|
|
draw2dContoursSettings.showCentroid = false;
|
|
|
|
|
draw2dContoursSettings.showCrosshair = true;
|
|
|
|
|
draw2dContoursSettings.boxOutlineSize = 2;
|
|
|
|
|
draw2dContoursSettings.showRotatedBox = true;
|
|
|
|
|
draw2dContoursSettings.showMaximumBox = true;
|
|
|
|
|
draw2dContoursPipe = new Draw2dContoursPipe(draw2dContoursSettings, camProps);
|
|
|
|
|
outputMatPipe = new OutputMatPipe(settings.isBinary);
|
2019-11-24 16:54:10 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-05 07:47:15 -08:00
|
|
|
@Override
|
2019-11-10 11:47:56 -05:00
|
|
|
public CVPipeline2dResult runPipeline(Mat inputMat) {
|
2019-11-25 16:06:21 -05:00
|
|
|
long totalPipelineTimeNanos = 0;
|
|
|
|
|
long pipelineStartTimeNanos = System.nanoTime();
|
2019-11-20 17:06:18 -05:00
|
|
|
|
2019-11-25 05:34:04 -05:00
|
|
|
if (cameraCapture == null) {
|
2019-11-20 17:06:18 -05:00
|
|
|
throw new RuntimeException("Pipeline was not initialized before being run!");
|
|
|
|
|
}
|
2019-11-26 02:55:05 -05:00
|
|
|
if (inputMat.cols() <= 1) {
|
2019-11-24 21:07:22 -05:00
|
|
|
throw new RuntimeException("Input Mat is empty!");
|
2019-11-23 20:06:37 -08:00
|
|
|
}
|
2019-11-20 17:06:18 -05:00
|
|
|
|
2019-11-25 16:40:23 -05:00
|
|
|
pipelineTimeStringBuilder = new StringBuilder();
|
2019-11-07 11:15:54 -05:00
|
|
|
|
2019-11-24 19:31:45 -05:00
|
|
|
inputMat.copyTo(rawCameraMat);
|
|
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
// prepare pipes
|
2019-11-25 16:40:23 -05:00
|
|
|
hsvLower = new Scalar(settings.hue.get(0).intValue(), settings.saturation.get(0).intValue(), settings.value.get(0).intValue());
|
|
|
|
|
hsvUpper = new Scalar(settings.hue.get(1).intValue(), settings.saturation.get(1).intValue(), settings.value.get(1).intValue());
|
2019-11-24 16:54:10 -08:00
|
|
|
rotateFlipPipe.setConfig(ImageRotation.DEG_0, settings.flipMode);
|
2019-11-25 05:34:04 -05:00
|
|
|
blurPipe.setConfig(0);
|
2019-11-24 16:54:10 -08:00
|
|
|
erodeDilatePipe.setConfig(settings.erode, settings.dilate, 7);
|
|
|
|
|
hsvPipe.setConfig(hsvLower, hsvUpper);
|
|
|
|
|
filterContoursPipe.setConfig(settings.area, settings.ratio, settings.extent, camProps);
|
|
|
|
|
speckleRejectPipe.setConfig(settings.speckle.doubleValue());
|
|
|
|
|
groupContoursPipe.setConfig(settings.targetGroup, settings.targetIntersection);
|
|
|
|
|
sortContoursPipe.setConfig(settings.sortMode, camProps);
|
|
|
|
|
collect2dTargetsPipe.setConfig(settings.calibrationMode, settings.point,
|
2019-11-07 11:15:54 -05:00
|
|
|
settings.dualTargetCalibrationM, settings.dualTargetCalibrationB, camProps);
|
2019-11-25 16:40:23 -05:00
|
|
|
draw2dContoursPipe.setConfig(camProps);
|
|
|
|
|
outputMatPipe.setConfig(settings.isBinary);
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-25 16:06:21 -05:00
|
|
|
long pipeInitTimeNanos = System.nanoTime() - pipelineStartTimeNanos;
|
2019-11-24 19:31:45 -05:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
// run pipes
|
|
|
|
|
Pair<Mat, Long> rotateFlipResult = rotateFlipPipe.run(inputMat);
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += rotateFlipResult.getRight();
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
Pair<Mat, Long> blurResult = blurPipe.run(rotateFlipResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += blurResult.getRight();
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
Pair<Mat, Long> erodeDilateResult = erodeDilatePipe.run(blurResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += erodeDilateResult.getRight();
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
Pair<Mat, Long> hsvResult = hsvPipe.run(erodeDilateResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += hsvResult.getRight();
|
2019-11-24 19:31:45 -05:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
Pair<List<MatOfPoint>, Long> findContoursResult = findContoursPipe.run(hsvResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += findContoursResult.getRight();
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
Pair<List<MatOfPoint>, Long> filterContoursResult = filterContoursPipe.run(findContoursResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += filterContoursResult.getRight();
|
2019-11-05 07:47:15 -08:00
|
|
|
|
2019-11-07 11:15:54 -05:00
|
|
|
Pair<List<MatOfPoint>, Long> speckleRejectResult = speckleRejectPipe.run(filterContoursResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += speckleRejectResult.getRight();
|
2019-11-07 11:15:54 -05:00
|
|
|
|
|
|
|
|
Pair<List<RotatedRect>, Long> groupContoursResult = groupContoursPipe.run(speckleRejectResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += groupContoursResult.getRight();
|
2019-11-07 11:15:54 -05:00
|
|
|
|
|
|
|
|
Pair<List<RotatedRect>, Long> sortContoursResult = sortContoursPipe.run(groupContoursResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += sortContoursResult.getRight();
|
2019-11-07 11:15:54 -05:00
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
Pair<List<Target2d>, Long> collect2dTargetsResult = collect2dTargetsPipe.run(sortContoursResult.getLeft());
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += collect2dTargetsResult.getRight();
|
2019-11-07 11:15:54 -05:00
|
|
|
|
2019-11-26 23:03:07 -05:00
|
|
|
// takes pair of (Mat of original camera image (8UC3), Mat of HSV thresholded image(8UC1))
|
|
|
|
|
Pair<Mat, Long> outputMatResult = outputMatPipe.run(Pair.of(rawCameraMat, hsvResult.getLeft()));
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += outputMatResult.getRight();
|
2019-11-07 11:15:54 -05:00
|
|
|
|
|
|
|
|
// takes pair of (Mat to draw on, List<RotatedRect> of sorted contours)
|
|
|
|
|
Pair<Mat, Long> draw2dContoursResult = draw2dContoursPipe.run(Pair.of(outputMatResult.getLeft(), sortContoursResult.getLeft()));
|
2019-11-25 16:06:21 -05:00
|
|
|
totalPipelineTimeNanos += draw2dContoursResult.getRight();
|
2019-11-25 16:40:23 -05:00
|
|
|
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("PipeInit: %.2fms, ", pipeInitTimeNanos / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("RotateFlip: %.2fms, ", rotateFlipResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("Blur: %.2fms, ", blurResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("ErodeDilate: %.2fms, ", erodeDilateResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("HSV: %.2fms, ", hsvResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("FindContours: %.2fms, ", findContoursResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("FilterContours: %.2fms, ", filterContoursResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("SpeckleReject: %.2fms, ", speckleRejectResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("GroupContours: %.2fms, ", groupContoursResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("SortContours: %.2fms, ", sortContoursResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("Collect2dTargets: %.2fms, ", collect2dTargetsResult.getRight() / 1000000.0));
|
|
|
|
|
pipelineTimeStringBuilder.append(String.format("OutputMat: %.2fms, ", outputMatResult.getRight() / 1000000.0));
|
2019-11-25 16:06:21 -05:00
|
|
|
pipelineTimeStringBuilder.append(String.format("Draw2dContours: %.2fms, ", draw2dContoursResult.getRight() / 1000000.0));
|
|
|
|
|
|
2019-11-26 23:03:07 -05:00
|
|
|
if (true) {
|
|
|
|
|
System.out.println(pipelineTimeStringBuilder.toString());
|
|
|
|
|
double totalPipelineTimeMillis = totalPipelineTimeNanos / 1000000.0;
|
|
|
|
|
double totalPipelineTimeFPS = 1.0 / (totalPipelineTimeMillis / 1000.0);
|
|
|
|
|
double truePipelineTimeMillis = (System.nanoTime() - pipelineStartTimeNanos) / 1000000.0;
|
|
|
|
|
double truePipelineFPS = 1.0 / (truePipelineTimeMillis / 1000.0);
|
|
|
|
|
System.out.printf("Pipeline processed in %.3fms (%.2fFPS), ", totalPipelineTimeMillis, totalPipelineTimeFPS);
|
|
|
|
|
System.out.printf("full pipeline run time was %.3fms (%.2fFPS)\n", truePipelineTimeMillis, truePipelineFPS);
|
|
|
|
|
}
|
2019-11-25 16:06:21 -05:00
|
|
|
|
|
|
|
|
return new CVPipeline2dResult(collect2dTargetsResult.getLeft(), draw2dContoursResult.getLeft(), totalPipelineTimeNanos);
|
2019-11-05 07:47:15 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-25 00:32:57 -05:00
|
|
|
public static class CVPipeline2dResult extends CVPipelineResult<Target2d> {
|
2019-11-24 19:31:45 -05:00
|
|
|
public CVPipeline2dResult(List<Target2d> targets, Mat outputMat, long processTimeNanos) {
|
|
|
|
|
super(targets, outputMat, processTimeNanos);
|
2019-11-05 07:47:15 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
public static class Target2d {
|
2019-11-05 07:47:15 -08:00
|
|
|
public double calibratedX = 0.0;
|
|
|
|
|
public double calibratedY = 0.0;
|
|
|
|
|
public double pitch = 0.0;
|
|
|
|
|
public double yaw = 0.0;
|
|
|
|
|
public double area = 0.0;
|
2019-11-07 11:15:54 -05:00
|
|
|
public RotatedRect rawPoint;
|
2019-11-05 07:47:15 -08:00
|
|
|
}
|
|
|
|
|
}
|