From d9f99f9c9b4678017bcff95ced1fb5fd06a9e7ca Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Jan 2023 20:23:14 -0500 Subject: [PATCH] Add calibration decimate dropdown (#739) * Increase resized size to 640 * Add calibration decimation dropdown * Update Calibrate3dPipeTest.java * Only allow decimation down to >=320x240 * Update CamerasView.vue --- photon-client/src/views/CamerasView.vue | 36 ++++++++++ .../pipe/impl/FindBoardCornersPipe.java | 66 +++++++++++-------- .../vision/pipeline/Calibrate3dPipeline.java | 8 ++- .../Calibration3dPipelineSettings.java | 2 + .../vision/pipeline/Calibrate3dPipeTest.java | 4 +- 5 files changed, 86 insertions(+), 30 deletions(-) diff --git a/photon-client/src/views/CamerasView.vue b/photon-client/src/views/CamerasView.vue index 29a549112..dcc5bd4a4 100644 --- a/photon-client/src/views/CamerasView.vue +++ b/photon-client/src/views/CamerasView.vue @@ -72,6 +72,14 @@ :disabled="isCalibrating" tooltip="Resolution to calibrate at (you will have to calibrate every resolution you use 3D mode on)" /> + { + var res = this.stringResolutionList[this.selectedFilteredResIndex].split(" X ").map(it => parseInt(it)); + console.log(res); + console.log(item); + // Realistically, we need more than 320x240, but lower than this is + // basically unusable. For now, don't allow decimations that take us + // below that + const ret = ((res[0] / item) >= 300 && (res[1] / item) >= 220) || (item === 1); + console.log(ret); + return ret; + }) + } + }, + // Makes sure there's only one entry per resolution filteredResolutionList: { get() { @@ -466,6 +491,17 @@ export default { this.$store.commit('cameraSettings', value); } }, + + streamingFrameDivisor: { + get() { + return this.$store.getters.currentPipelineSettings.streamingFrameDivisor; + }, + set(val) { + this.$store.commit("mutatePipeline", {"streamingFrameDivisor": val}); + this.handlePipelineUpdate("streamingFrameDivisor", val); + } + }, + boardType: { get() { return this.calibrationData.boardType diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java index 60a018032..9a5e38fac 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FindBoardCornersPipe.java @@ -17,7 +17,6 @@ package org.photonvision.vision.pipe.impl; -import java.util.Objects; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.opencv.calib3d.Calib3d; @@ -25,6 +24,7 @@ import org.opencv.core.*; import org.opencv.imgproc.Imgproc; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; +import org.photonvision.vision.frame.FrameDivisor; import org.photonvision.vision.pipe.CVPipe; import org.photonvision.vision.pipeline.UICalibrationData; @@ -39,10 +39,6 @@ public class FindBoardCornersPipe Size imageSize; Size patternSize; - // Tune to taste for a reasonable tradeoff between making - // the findCorners portion work hard, versus the subpixel refinement work hard. - final int FIND_CORNERS_WIDTH_PX = 320; - // Configure the optimizations used while using openCV's find corners algorithm // Since we return results in real-time, we want ensure it goes as fast as possible // and fails as fast as possible. @@ -125,17 +121,13 @@ public class FindBoardCornersPipe /** * Figures out how much a frame or point cloud must be scaled down by to match the desired size at - * which to run FindCorners + * which to run FindCorners. Should usually be > 1. * * @param inFrame * @return */ private double getFindCornersScaleFactor(Mat inFrame) { - if (inFrame.width() > FIND_CORNERS_WIDTH_PX) { - return ((double) FIND_CORNERS_WIDTH_PX) / inFrame.width(); - } else { - return 1.0; - } + return 1.0 / params.divisor.value; } /** @@ -174,9 +166,10 @@ public class FindBoardCornersPipe * findBoardCorners * @return the size to scale the input mat to */ - private Size getFindCornersImgSize(Mat inFrame) { - var findcorners_height = Math.round(inFrame.height() * getFindCornersScaleFactor(inFrame)); - return new Size(FIND_CORNERS_WIDTH_PX, findcorners_height); + private Size getFindCornersImgSize(Mat in) { + int width = in.cols() / params.divisor.value; + int height = in.rows() / params.divisor.value; + return new Size(width, height); } /** @@ -295,29 +288,48 @@ public class FindBoardCornersPipe private final int boardWidth; private final UICalibrationData.BoardType type; private final double gridSize; + private final FrameDivisor divisor; public FindCornersPipeParams( - int boardHeight, int boardWidth, UICalibrationData.BoardType type, double gridSize) { + int boardHeight, + int boardWidth, + UICalibrationData.BoardType type, + double gridSize, + FrameDivisor divisor) { this.boardHeight = boardHeight; this.boardWidth = boardWidth; this.type = type; this.gridSize = gridSize; // mm - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - FindCornersPipeParams that = (FindCornersPipeParams) o; - return boardHeight == that.boardHeight - && boardWidth == that.boardWidth - && Double.compare(that.gridSize, gridSize) == 0 - && type == that.type; + this.divisor = divisor; } @Override public int hashCode() { - return Objects.hash(boardHeight, boardWidth, type, gridSize); + 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 (type != other.type) return false; + if (Double.doubleToLongBits(gridSize) != Double.doubleToLongBits(other.gridSize)) + return false; + if (divisor != other.divisor) return false; + return true; } } } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java index 7c87f2a2d..fecb36d07 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibrate3dPipeline.java @@ -87,7 +87,11 @@ public class Calibrate3dPipeline protected void setPipeParamsImpl() { FindBoardCornersPipe.FindCornersPipeParams findCornersPipeParams = new FindBoardCornersPipe.FindCornersPipeParams( - settings.boardHeight, settings.boardWidth, settings.boardType, settings.gridSize); + settings.boardHeight, + settings.boardWidth, + settings.boardType, + settings.gridSize, + settings.streamingFrameDivisor); findBoardCornersPipe.setParams(findCornersPipeParams); Calibrate3dPipe.CalibratePipeParams calibratePipeParams = @@ -105,7 +109,7 @@ public class Calibrate3dPipeline protected CVPipelineResult process(Frame frame, Calibration3dPipelineSettings settings) { Mat inputColorMat = frame.colorImage.getMat(); - if (this.calibrating) { + if (this.calibrating || inputColorMat.empty()) { return new CVPipelineResult(0, 0, null, frame); } diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibration3dPipelineSettings.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibration3dPipelineSettings.java index 196c9e7d6..1d5e57df2 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibration3dPipelineSettings.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/Calibration3dPipelineSettings.java @@ -19,6 +19,7 @@ package org.photonvision.vision.pipeline; import edu.wpi.first.math.util.Units; import org.opencv.core.Size; +import org.photonvision.vision.frame.FrameDivisor; public class Calibration3dPipelineSettings extends AdvancedPipelineSettings { public int boardHeight = 8; @@ -33,5 +34,6 @@ public class Calibration3dPipelineSettings extends AdvancedPipelineSettings { this.cameraAutoExposure = true; this.inputShouldShow = true; this.outputShouldShow = true; + this.streamingFrameDivisor = FrameDivisor.HALF; } } diff --git a/photon-core/src/test/java/org/photonvision/vision/pipeline/Calibrate3dPipeTest.java b/photon-core/src/test/java/org/photonvision/vision/pipeline/Calibrate3dPipeTest.java index 6f54d2303..bec81b2c4 100644 --- a/photon-core/src/test/java/org/photonvision/vision/pipeline/Calibrate3dPipeTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/pipeline/Calibrate3dPipeTest.java @@ -37,6 +37,7 @@ import org.photonvision.common.util.TestUtils; import org.photonvision.vision.calibration.CameraCalibrationCoefficients; import org.photonvision.vision.camera.QuirkyCamera; import org.photonvision.vision.frame.Frame; +import org.photonvision.vision.frame.FrameDivisor; import org.photonvision.vision.frame.FrameStaticProperties; import org.photonvision.vision.frame.FrameThresholdType; import org.photonvision.vision.opencv.CVMat; @@ -62,7 +63,7 @@ public class Calibrate3dPipeTest { FindBoardCornersPipe findBoardCornersPipe = new FindBoardCornersPipe(); findBoardCornersPipe.setParams( new FindBoardCornersPipe.FindCornersPipeParams( - 11, 4, UICalibrationData.BoardType.DOTBOARD, 15)); + 11, 4, UICalibrationData.BoardType.DOTBOARD, 15, FrameDivisor.NONE)); List> foundCornersList = new ArrayList<>(); @@ -264,6 +265,7 @@ public class Calibrate3dPipeTest { calibration3dPipeline.getSettings().boardHeight = (int) Math.round(boardDim.height); calibration3dPipeline.getSettings().boardWidth = (int) Math.round(boardDim.width); calibration3dPipeline.getSettings().gridSize = boardGridSize_m; + calibration3dPipeline.getSettings().streamingFrameDivisor = FrameDivisor.NONE; for (var file : directoryListing) { if (file.isFile()) {