diff --git a/build.gradle b/build.gradle index bbdbad091..e42347284 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ ext { javalinVersion = "6.7.0" libcameraDriverVersion = "v2026.0.0" rknnVersion = "v2026.0.1" - rubikVersion = "v2026.0.1" + rubikVersion = "dev-v2026.0.1-3-g977bb2e" frcYear = "2026" mrcalVersion = "v2026.0.0"; diff --git a/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java b/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java index 51cf48915..57a161884 100644 --- a/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java +++ b/photon-core/src/main/java/org/photonvision/vision/objects/Letterbox.java @@ -21,7 +21,8 @@ import java.util.ArrayList; import java.util.List; import org.opencv.core.Core; import org.opencv.core.Mat; -import org.opencv.core.Rect2d; +import org.opencv.core.Point; +import org.opencv.core.RotatedRect; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.imgproc.Imgproc; @@ -86,21 +87,26 @@ public class Letterbox { * @return The resized detections */ public List resizeDetections(List unscaled) { - var ret = new ArrayList(); + var ret = new ArrayList(unscaled.size()); for (var t : unscaled) { var scale = 1.0 / this.scale; var boundingBox = t.bbox(); - double x = (boundingBox.x - this.dx) * scale; - double y = (boundingBox.y - this.dy) * scale; - double width = boundingBox.width * scale; - double height = boundingBox.height * scale; + + double cx = (boundingBox.center.x - this.dx) * scale; + double cy = (boundingBox.center.y - this.dy) * scale; + double width = boundingBox.size.width * scale; + double height = boundingBox.size.height * scale; + + Point center = new Point(cx, cy); + Size size = new Size(width, height); + + // angle is unchanged from letterbox transformation ret.add( new NeuralNetworkPipeResult( - new Rect2d(x, y, width, height), t.classIdx(), t.confidence())); + new RotatedRect(center, size, boundingBox.angle), t.classIdx(), t.confidence())); } - return ret; } } diff --git a/photon-core/src/main/java/org/photonvision/vision/objects/RubikObjectDetector.java b/photon-core/src/main/java/org/photonvision/vision/objects/RubikObjectDetector.java index 72662d4a4..38502ba8b 100644 --- a/photon-core/src/main/java/org/photonvision/vision/objects/RubikObjectDetector.java +++ b/photon-core/src/main/java/org/photonvision/vision/objects/RubikObjectDetector.java @@ -65,7 +65,9 @@ public class RubikObjectDetector implements ObjectDetector { // Create the detector try { - ptr = RubikJNI.create(model.modelFile.getPath().toString()); + ptr = + RubikJNI.create( + model.modelFile.getPath().toString(), model.properties.version().ordinal()); } catch (Exception e) { logger.error("Failed to create detector from path " + model.modelFile.getPath(), e); throw new RuntimeException( diff --git a/photon-core/src/main/java/org/photonvision/vision/opencv/Contour.java b/photon-core/src/main/java/org/photonvision/vision/opencv/Contour.java index 260d98428..82cb5fce3 100644 --- a/photon-core/src/main/java/org/photonvision/vision/opencv/Contour.java +++ b/photon-core/src/main/java/org/photonvision/vision/opencv/Contour.java @@ -57,6 +57,17 @@ public class Contour implements Releasable { new Point(box.x, box.y + box.height)); } + public Contour(RotatedRect obb) { + Point[] pts = new Point[4]; + for (int i = 0; i < 4; ++i) pts[i] = new Point(); + + obb.points(pts); + + // target: tl tr br bl + // pts array: "The order is bottomLeft, topLeft, topRight, bottomRight." + this.mat = new MatOfPoint(pts[1], pts[2], pts[3], pts[0]); + } + public MatOfPoint2f getMat2f() { if (mat2f == null) { mat2f = new MatOfPoint2f(mat.toArray()); diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java index 03479dc51..4f82231a3 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/FilterObjectDetectionsPipe.java @@ -22,6 +22,7 @@ import java.util.List; import org.photonvision.common.util.numbers.DoubleCouple; import org.photonvision.vision.frame.FrameStaticProperties; import org.photonvision.vision.pipe.CVPipe; +import org.photonvision.vision.target.TargetCalculations; public class FilterObjectDetectionsPipe extends CVPipe< @@ -44,13 +45,13 @@ public class FilterObjectDetectionsPipe var boc = contour.bbox(); // Area filtering - double areaPercentage = boc.area() / params.frameStaticProperties().imageArea * 100.0; + double areaPercentage = boc.size.area() / params.frameStaticProperties().imageArea * 100.0; double minAreaPercentage = params.area().getFirst(); double maxAreaPercentage = params.area().getSecond(); if (areaPercentage < minAreaPercentage || areaPercentage > maxAreaPercentage) return; - // Aspect ratio filtering; much simpler since always axis-aligned - double aspectRatio = boc.width / boc.height; + // Aspect ratio filtering + double aspectRatio = TargetCalculations.getAspectRatio(boc, params.isLandscape()); if (aspectRatio < params.ratio().getFirst() || aspectRatio > params.ratio().getSecond()) return; m_filteredContours.add(contour); diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java index 40a56e8d3..a10a6d166 100644 --- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java +++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/NeuralNetworkPipeResult.java @@ -17,6 +17,20 @@ package org.photonvision.vision.pipe.impl; +import org.opencv.core.Point; import org.opencv.core.Rect2d; +import org.opencv.core.RotatedRect; +import org.opencv.core.Size; -public record NeuralNetworkPipeResult(Rect2d bbox, int classIdx, double confidence) {} +public record NeuralNetworkPipeResult(RotatedRect bbox, int classIdx, double confidence) { + public NeuralNetworkPipeResult(Rect2d rect, int classIdx, double confidence) { + // turn the axis-aligned rect into a RotatedRect with angle 0 degrees + this( + new RotatedRect( + new Point(rect.x + (rect.width) / 2, rect.y + (rect.height) / 2), + new Size(rect.width, rect.height), + 0.0), + classIdx, + confidence); + } +}