diff --git a/chameleon-server/build.gradle b/chameleon-server/build.gradle index 73e6cb56f..539a64918 100644 --- a/chameleon-server/build.gradle +++ b/chameleon-server/build.gradle @@ -44,33 +44,6 @@ dependencies { implementation "com.moandjiezana.toml:toml4j:0.7.2" -// // javacv -// def withoutJunk = { -// exclude group: 'org.bytedeco', module: 'artoolkitplus' -// exclude group: 'org.bytedeco', module: 'artoolkitplus-platform' -// exclude group: 'org.bytedeco', module: 'flandmark' -// exclude group: 'org.bytedeco', module: 'flandmark-platform' -// exclude group: 'org.bytedeco', module: 'flycapture' -// exclude group: 'org.bytedeco', module: 'flycapture-platform' -// exclude group: 'org.bytedeco', module: 'leptonica' -// exclude group: 'org.bytedeco', module: 'leptonica-platform' -// exclude group: 'org.bytedeco', module: 'libdc1394' -// exclude group: 'org.bytedeco', module: 'libdc1394-platform' -// exclude group: 'org.bytedeco', module: 'libfreenect' -// exclude group: 'org.bytedeco', module: 'libfreenect-platform' -// exclude group: 'org.bytedeco', module: 'libfreenect2' -// exclude group: 'org.bytedeco', module: 'libfreenect2-platform' -// exclude group: 'org.bytedeco', module: 'librealsense' -// exclude group: 'org.bytedeco', module: 'librealsense-platform' -// exclude group: 'org.bytedeco', module: 'librealsense2' -// exclude group: 'org.bytedeco', module: 'librealsense2-platform' -// exclude group: 'org.bytedeco', module: 'openblas' -// exclude group: 'org.bytedeco', module: 'openblas-platform' -// exclude group: 'org.bytedeco', module: 'tesseract' -// exclude group: 'org.bytedeco', module: 'tesseract-platform' -// } -// compile 'org.bytedeco:javacv-platform:1.5.2', withoutJunk - // wpilib stuff implementation "edu.wpi.first.wpiutil:wpiutil-java:$wpilibVersion" implementation "edu.wpi.first.cameraserver:cameraserver-java:$wpilibVersion" @@ -96,6 +69,35 @@ dependencies { compile "edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:$openCVVersion:osxx86-64" compile "edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:$openCVVersion:windowsx86-64" + // javacv (ew) +// def withoutJunk = { +// exclude group: 'org.bytedeco', module: 'artoolkitplus' +// exclude group: 'org.bytedeco', module: 'artoolkitplus-platform' +// exclude group: 'org.bytedeco', module: 'flandmark' +// exclude group: 'org.bytedeco', module: 'flandmark-platform' +// exclude group: 'org.bytedeco', module: 'flycapture' +// exclude group: 'org.bytedeco', module: 'flycapture-platform' +// exclude group: 'org.bytedeco', module: 'leptonica' +// exclude group: 'org.bytedeco', module: 'leptonica-platform' +// exclude group: 'org.bytedeco', module: 'libdc1394' +// exclude group: 'org.bytedeco', module: 'libdc1394-platform' +// exclude group: 'org.bytedeco', module: 'libfreenect' +// exclude group: 'org.bytedeco', module: 'libfreenect-platform' +// exclude group: 'org.bytedeco', module: 'libfreenect2' +// exclude group: 'org.bytedeco', module: 'libfreenect2-platform' +// exclude group: 'org.bytedeco', module: 'librealsense' +// exclude group: 'org.bytedeco', module: 'librealsense-platform' +// exclude group: 'org.bytedeco', module: 'librealsense2' +// exclude group: 'org.bytedeco', module: 'librealsense2-platform' +// exclude group: 'org.bytedeco', module: 'openblas' +// exclude group: 'org.bytedeco', module: 'openblas-platform' +// exclude group: 'org.bytedeco', module: 'tesseract' +// exclude group: 'org.bytedeco', module: 'tesseract-platform' +// exclude group: 'org.bytedeco', module: 'ffmpeg' +// exclude group: 'org.bytedeco', module: 'ffmpeg-platform' +// } +// compile 'org.bytedeco:javacv-platform:1.5.2', withoutJunk + // test stuff testImplementation('org.junit.jupiter:junit-jupiter:5.6.0') } diff --git a/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/impl/StandardCVPipeline.java b/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/impl/StandardCVPipeline.java index b8e934d42..fe90e5dea 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/impl/StandardCVPipeline.java +++ b/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/impl/StandardCVPipeline.java @@ -7,6 +7,7 @@ import com.chameleonvision._2.vision.pipeline.CVPipeline; import com.chameleonvision._2.vision.pipeline.CVPipelineResult; import com.chameleonvision._2.vision.pipeline.pipes.*; import com.chameleonvision.common.util.MemoryManager; +import com.chameleonvision.common.vision.opencv.Contour; import edu.wpi.first.wpilibj.geometry.Pose2d; import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.Point; @@ -124,7 +125,7 @@ public class StandardCVPipeline extends CVPipeline, Long> findContoursResult = findContoursPipe.run(hsvResult.getLeft()); totalPipelineTimeNanos += findContoursResult.getRight(); - Pair, Long> filterContoursResult = filterContoursPipe.run(findContoursResult.getLeft()); + Pair, Long> filterContoursResult = filterContoursPipe.run(findContoursResult.getLeft()); totalPipelineTimeNanos += filterContoursResult.getRight(); + // ignore ! Pair, Long> speckleRejectResult = speckleRejectPipe.run(filterContoursResult.getLeft()); totalPipelineTimeNanos += speckleRejectResult.getRight(); diff --git a/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/pipes/FilterContoursPipe.java b/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/pipes/FilterContoursPipe.java index 6536e500a..85372b8a5 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/pipes/FilterContoursPipe.java +++ b/chameleon-server/src/main/java/com/chameleonvision/_2/vision/pipeline/pipes/FilterContoursPipe.java @@ -4,23 +4,25 @@ import com.chameleonvision._2.vision.camera.CaptureStaticProperties; import com.chameleonvision._2.vision.pipeline.Pipe; import com.chameleonvision.common.util.math.MathUtils; import com.chameleonvision.common.util.numbers.DoubleCouple; +import com.chameleonvision.common.vision.opencv.Contour; import org.apache.commons.lang3.tuple.Pair; import org.opencv.core.MatOfPoint; import org.opencv.core.MatOfPoint2f; import org.opencv.core.Rect; +import org.opencv.core.RotatedRect; import org.opencv.imgproc.Imgproc; import java.util.ArrayList; import java.util.List; -public class FilterContoursPipe implements Pipe, List> { +public class FilterContoursPipe implements Pipe, List> { private DoubleCouple area; private DoubleCouple ratio; private DoubleCouple extent; private CaptureStaticProperties camProps; - private List filteredContours = new ArrayList<>(); + private List filteredContours = new ArrayList<>(); public FilterContoursPipe(DoubleCouple area, DoubleCouple ratio, DoubleCouple extent, CaptureStaticProperties camProps) { this.area = area; @@ -36,34 +38,47 @@ public class FilterContoursPipe implements Pipe, List maxArea) { + return; + } + + // TargetFillPercentage filtering + RotatedRect minAreaRect = realContour.getMinAreaRect(); + double minExtent = (extent.getFirst() * minAreaRect.size.area()) / 100; + double maxExtent = (extent.getSecond() * minAreaRect.size.area()) / 100; + if (contourArea <= minExtent || contourArea >= maxExtent) { + return; + } + + // AspectRatio filtering + Rect boundingRect = realContour.getBoundingRect(); + double aspectRatio = ((double)boundingRect.width / boundingRect.height); + if (aspectRatio < ratio.getFirst() || aspectRatio > ratio.getSecond()) { + return; + } + + filteredContours.add(realContour); + } + @Override - public Pair, Long> run(List input) { + public Pair, Long> run(List input) { long processStartNanos = System.nanoTime(); filteredContours.clear(); if (input.size() > 0) { - for (MatOfPoint Contour : input) { + for (MatOfPoint contour : input) { try { - double contourArea = Imgproc.contourArea(Contour); - double AreaRatio = (contourArea / camProps.imageArea) * 100; - double minArea = (MathUtils.sigmoid(area.getFirst())); - double maxArea = (MathUtils.sigmoid(area.getFirst())); - if (AreaRatio < minArea || AreaRatio > maxArea) { - continue; - } - var rect = Imgproc.minAreaRect(new MatOfPoint2f(Contour.toArray())); - double minExtent = (extent.getFirst() * rect.size.area()) / 100; - double maxExtent = (extent.getSecond() * rect.size.area()) / 100; - if (contourArea <= minExtent || contourArea >= maxExtent) { - continue; - } - Rect bb = Imgproc.boundingRect(Contour); - double aspectRatio = ((double)bb.width / bb.height); - if (aspectRatio < ratio.getFirst() || aspectRatio > ratio.getSecond()) { - continue; - } - filteredContours.add(Contour); + filterContour(contour); } catch (Exception e) { System.err.println("Error while filtering contours"); e.printStackTrace(); diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/util/numbers/NumberCouple.java b/chameleon-server/src/main/java/com/chameleonvision/common/util/numbers/NumberCouple.java index 3fd0ee3cc..8535a713e 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/util/numbers/NumberCouple.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/util/numbers/NumberCouple.java @@ -1,6 +1,6 @@ package com.chameleonvision.common.util.numbers; -public class NumberCouple { +public abstract class NumberCouple { private T first; private T second; @@ -30,4 +30,26 @@ public class NumberCouple { this.first = first; this.second = second; } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof NumberCouple)) { + return false; + } + + var couple = (NumberCouple) obj; + if (!couple.first.equals(first)) { + return false; + } + + if (!couple.second.equals(second)) { + return false; + } + + return true; + } + + public boolean isEmpty() { + return first.intValue() == 0 && second.intValue() == 0; + } } diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/camera/USBCamera.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/camera/USBCamera.java deleted file mode 100644 index 16f25d83b..000000000 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/camera/USBCamera.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.chameleonvision.common.vision.base.camera; - -import com.chameleonvision.common.vision.base.frame.provider.USBFrameProvider; - -public class USBCamera extends USBFrameProvider { -} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/Frame.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/Frame.java deleted file mode 100644 index b8950c68b..000000000 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/Frame.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.chameleonvision.common.vision.base.frame; - -import org.opencv.core.Mat; -import org.opencv.core.Size; - -public class Frame { - public long timestamp; - public Mat image; - public Size imageSize; -} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/ResizeImagePipe.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/ResizeImagePipe.java deleted file mode 100644 index e6346031d..000000000 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/ResizeImagePipe.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.chameleonvision.common.vision.base.pipeline.pipe; - -import com.chameleonvision.common.vision.base.pipeline.CVPipe; -import com.chameleonvision.common.vision.base.pipeline.pipe.params.ResizeImageParams; -import org.opencv.core.Mat; -import org.opencv.imgproc.Imgproc; - -/** - * Pipe that resizes an image to a given resolution - */ -public class ResizeImagePipe extends CVPipe { - - public ResizeImagePipe() { - setParams(ResizeImageParams.DEFAULT); - } - - public ResizeImagePipe(ResizeImageParams params) { - setParams(params); - } - - /** - * Process this pipe - * @param in {@link Mat} to be resized - * @return Resized {@link Mat} - */ - @Override - protected Mat process(Mat in) { - Imgproc.resize(in, in, params.getSize()); - return in; - } -} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/RotateImagePipe.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/RotateImagePipe.java deleted file mode 100644 index 9b1747693..000000000 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/RotateImagePipe.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.chameleonvision.common.vision.base.pipeline.pipe; - -import com.chameleonvision.common.vision.base.pipeline.CVPipe; -import com.chameleonvision.common.vision.base.pipeline.pipe.params.RotateImageParams; -import org.opencv.core.Core; -import org.opencv.core.Mat; - -/** - * Pipe that rotates an image to a given orientation - */ -public class RotateImagePipe extends CVPipe { - - public RotateImagePipe() { - setParams(RotateImageParams.DEFAULT); - } - - public RotateImagePipe(RotateImageParams params) { - setParams(params); - } - - /** - * Process this pipe - * @param in {@link Mat} to be rotated - * @return Rotated {@link Mat} - */ - @Override - protected Mat process(Mat in) { - Core.rotate(in, in, params.rotation.value); - return in; - } -} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/params/ResizeImageParams.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/params/ResizeImageParams.java deleted file mode 100644 index 98973b513..000000000 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/params/ResizeImageParams.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.chameleonvision.common.vision.base.pipeline.pipe.params; - -import org.opencv.core.Size; - -public class ResizeImageParams { - - public static ResizeImageParams DEFAULT = new ResizeImageParams(320, 240); - - private Size size; - public int width; - public int height; - - public ResizeImageParams() { - this(DEFAULT.width, DEFAULT.height); - } - - public ResizeImageParams(int width, int height) { - this.width = width; - this.height = height; - size = new Size(new double[]{width, height}); - } - - public Size getSize() { - return size; - } -} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/params/RotateImageParams.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/params/RotateImageParams.java deleted file mode 100644 index 49872a834..000000000 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/pipe/params/RotateImageParams.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.chameleonvision.common.vision.base.pipeline.pipe.params; - -public class RotateImageParams { - - public static RotateImageParams DEFAULT = new RotateImageParams(ImageRotation.DEG_0); - - public ImageRotation rotation; - - public RotateImageParams() { - rotation = DEFAULT.rotation; - } - - public RotateImageParams(ImageRotation rotation) { - this.rotation = rotation; - } - - public enum ImageRotation { - DEG_0(-1), - DEG_90(0), - DEG_180(1), - DEG_270(2); - - public final int value; - - ImageRotation(int value) { - this.value = value; - } - - public boolean isRotated() { - return this.value==DEG_90.value || this.value==DEG_270.value; - } - } -} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/camera/USBCamera.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/camera/USBCamera.java new file mode 100644 index 000000000..d8a21be9d --- /dev/null +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/camera/USBCamera.java @@ -0,0 +1,6 @@ +package com.chameleonvision.common.vision.camera; + +import com.chameleonvision.common.vision.frame.provider.USBFrameProvider; + +public class USBCamera extends USBFrameProvider { +} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/Frame.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/Frame.java new file mode 100644 index 000000000..1723ede82 --- /dev/null +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/Frame.java @@ -0,0 +1,19 @@ +package com.chameleonvision.common.vision.frame; + +import org.opencv.core.Mat; +import org.opencv.core.Size; + +public class Frame { + public long timestampNanos; + public Mat image; + + public Frame(Mat image) { + this.image = image; + timestampNanos = System.nanoTime(); + } + + public Frame(Mat image, long timestampNanos) { + this.image = image; + this.timestampNanos = timestampNanos; + } +} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/FrameConsumer.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/FrameConsumer.java similarity index 55% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/FrameConsumer.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/FrameConsumer.java index 57fd4351c..aa2ae4e8b 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/FrameConsumer.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/FrameConsumer.java @@ -1,4 +1,4 @@ -package com.chameleonvision.common.vision.base.frame; +package com.chameleonvision.common.vision.frame; public interface FrameConsumer { void consume(Frame frame); diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/FrameProvider.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/FrameProvider.java similarity index 51% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/FrameProvider.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/FrameProvider.java index be8ce43e0..37cd24078 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/FrameProvider.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/FrameProvider.java @@ -1,4 +1,4 @@ -package com.chameleonvision.common.vision.base.frame; +package com.chameleonvision.common.vision.frame; public interface FrameProvider { Frame getFrame(); diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/consumer/MJPGFrameConsumer.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/consumer/MJPGFrameConsumer.java similarity index 54% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/consumer/MJPGFrameConsumer.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/consumer/MJPGFrameConsumer.java index 92f719263..8bb4c1e5e 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/consumer/MJPGFrameConsumer.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/consumer/MJPGFrameConsumer.java @@ -1,7 +1,7 @@ -package com.chameleonvision.common.vision.base.frame.consumer; +package com.chameleonvision.common.vision.frame.consumer; -import com.chameleonvision.common.vision.base.frame.Frame; -import com.chameleonvision.common.vision.base.frame.FrameConsumer; +import com.chameleonvision.common.vision.frame.Frame; +import com.chameleonvision.common.vision.frame.FrameConsumer; import org.apache.commons.lang3.NotImplementedException; public class MJPGFrameConsumer implements FrameConsumer { diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/FileFrameProvider.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/FileFrameProvider.java similarity index 53% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/FileFrameProvider.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/FileFrameProvider.java index 0747388cc..2209df245 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/FileFrameProvider.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/FileFrameProvider.java @@ -1,7 +1,7 @@ -package com.chameleonvision.common.vision.base.frame.provider; +package com.chameleonvision.common.vision.frame.provider; -import com.chameleonvision.common.vision.base.frame.Frame; -import com.chameleonvision.common.vision.base.frame.FrameProvider; +import com.chameleonvision.common.vision.frame.Frame; +import com.chameleonvision.common.vision.frame.FrameProvider; import org.apache.commons.lang3.NotImplementedException; public class FileFrameProvider implements FrameProvider { diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/NetworkFrameProvider.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/NetworkFrameProvider.java similarity index 53% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/NetworkFrameProvider.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/NetworkFrameProvider.java index f28340aa1..ad63a283c 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/NetworkFrameProvider.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/NetworkFrameProvider.java @@ -1,7 +1,7 @@ -package com.chameleonvision.common.vision.base.frame.provider; +package com.chameleonvision.common.vision.frame.provider; -import com.chameleonvision.common.vision.base.frame.Frame; -import com.chameleonvision.common.vision.base.frame.FrameProvider; +import com.chameleonvision.common.vision.frame.Frame; +import com.chameleonvision.common.vision.frame.FrameProvider; import org.apache.commons.lang3.NotImplementedException; public class NetworkFrameProvider implements FrameProvider { diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/USBFrameProvider.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/USBFrameProvider.java similarity index 53% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/USBFrameProvider.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/USBFrameProvider.java index 78462479c..e942429d4 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/frame/provider/USBFrameProvider.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/frame/provider/USBFrameProvider.java @@ -1,7 +1,7 @@ -package com.chameleonvision.common.vision.base.frame.provider; +package com.chameleonvision.common.vision.frame.provider; -import com.chameleonvision.common.vision.base.frame.Frame; -import com.chameleonvision.common.vision.base.frame.FrameProvider; +import com.chameleonvision.common.vision.frame.Frame; +import com.chameleonvision.common.vision.frame.FrameProvider; import org.apache.commons.lang3.NotImplementedException; public class USBFrameProvider implements FrameProvider { diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/opencv/Contour.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/opencv/Contour.java new file mode 100644 index 000000000..64e09cc96 --- /dev/null +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/opencv/Contour.java @@ -0,0 +1,44 @@ +package com.chameleonvision.common.vision.opencv; + +import org.opencv.core.*; +import org.opencv.imgproc.Imgproc; + +public class Contour { + + private final MatOfPoint points; + + private Double area = Double.NaN; + private RotatedRect minAreaRect = null; + private Rect boundingRect = null; + + public Contour(MatOfPoint points) { + this.points = points; + } + + public double getArea() { + if (Double.isNaN(area)) { + area = Imgproc.contourArea(points); + } + return area; + } + + public RotatedRect getMinAreaRect() { + if (minAreaRect == null) { + MatOfPoint2f temp = new MatOfPoint2f(points.toArray()); + minAreaRect = Imgproc.minAreaRect(temp); + temp.release(); + } + return minAreaRect; + } + + public Rect getBoundingRect() { + if (boundingRect == null) { + boundingRect = Imgproc.boundingRect(points); + } + return boundingRect; + } + + public Point getCenterPoint() { + return getMinAreaRect().center; + } +} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/CVPipe.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/CVPipe.java similarity index 91% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/CVPipe.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/CVPipe.java index 6fe77a4d6..8ed6eb1c0 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/CVPipe.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/CVPipe.java @@ -1,4 +1,4 @@ -package com.chameleonvision.common.vision.base.pipeline; +package com.chameleonvision.common.vision.pipeline; import java.util.function.Function; @@ -8,6 +8,7 @@ import java.util.function.Function; * * @param Input type for the pipe * @param Output type for the pipe + * @param

Parameters type for the pipe */ public abstract class CVPipe implements Function> { diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/DummyPipeline.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/DummyPipeline.java similarity index 83% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/DummyPipeline.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/DummyPipeline.java index 1c5d74089..4666f8d52 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/DummyPipeline.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/DummyPipeline.java @@ -1,7 +1,7 @@ -package com.chameleonvision.common.vision.base.pipeline; +package com.chameleonvision.common.vision.pipeline; -import com.chameleonvision.common.vision.base.pipeline.pipe.ResizeImagePipe; -import com.chameleonvision.common.vision.base.pipeline.pipe.RotateImagePipe; +import com.chameleonvision.common.vision.pipeline.pipe.ResizeImagePipe; +import com.chameleonvision.common.vision.pipeline.pipe.RotateImagePipe; import edu.wpi.cscore.CameraServerCvJNI; import org.opencv.core.CvType; import org.opencv.core.Mat; diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/PipeResult.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/PipeResult.java similarity index 54% rename from chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/PipeResult.java rename to chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/PipeResult.java index dfdb9b576..451b172eb 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/base/pipeline/PipeResult.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/PipeResult.java @@ -1,4 +1,4 @@ -package com.chameleonvision.common.vision.base.pipeline; +package com.chameleonvision.common.vision.pipeline; public class PipeResult { O result; diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/pipe/ResizeImagePipe.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/pipe/ResizeImagePipe.java new file mode 100644 index 000000000..133952048 --- /dev/null +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/pipe/ResizeImagePipe.java @@ -0,0 +1,53 @@ +package com.chameleonvision.common.vision.pipeline.pipe; + +import com.chameleonvision.common.vision.pipeline.CVPipe; +import org.opencv.core.Mat; +import org.opencv.core.Size; +import org.opencv.imgproc.Imgproc; + +/** + * Pipe that resizes an image to a given resolution + */ +public class ResizeImagePipe extends CVPipe { + + public ResizeImagePipe() { + setParams(ResizeImageParams.DEFAULT); + } + + public ResizeImagePipe(ResizeImageParams params) { + setParams(params); + } + + /** + * Process this pipe + * @param in {@link Mat} to be resized + * @return Resized {@link Mat} + */ + @Override + protected Mat process(Mat in) { + Imgproc.resize(in, in, params.getSize()); + return in; + } + + public static class ResizeImageParams { + public static ResizeImageParams DEFAULT = new ResizeImageParams(320, 240); + + private Size size; + public int width; + public int height; + + public ResizeImageParams() { + this(DEFAULT.width, DEFAULT.height); + } + + public ResizeImageParams(int width, int height) { + this.width = width; + this.height = height; + size = new Size(new double[]{width, height}); + } + + public Size getSize() { + return size; + } + } +} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/pipe/RotateImagePipe.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/pipe/RotateImagePipe.java new file mode 100644 index 000000000..73bff9d70 --- /dev/null +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/pipeline/pipe/RotateImagePipe.java @@ -0,0 +1,61 @@ +package com.chameleonvision.common.vision.pipeline.pipe; + +import com.chameleonvision.common.vision.pipeline.CVPipe; +import org.opencv.core.Core; +import org.opencv.core.Mat; + +/** + * Pipe that rotates an image to a given orientation + */ +public class RotateImagePipe extends CVPipe { + + public RotateImagePipe() { + setParams(RotateImageParams.DEFAULT); + } + + public RotateImagePipe(RotateImageParams params) { + setParams(params); + } + + /** + * Process this pipe + * @param in {@link Mat} to be rotated + * @return Rotated {@link Mat} + */ + @Override + protected Mat process(Mat in) { + Core.rotate(in, in, params.rotation.value); + return in; + } + + public static class RotateImageParams { + public static RotateImageParams DEFAULT = new RotateImageParams(ImageRotation.DEG_0); + + public ImageRotation rotation; + + public RotateImageParams() { + rotation = DEFAULT.rotation; + } + + public RotateImageParams(ImageRotation rotation) { + this.rotation = rotation; + } + + public enum ImageRotation { + DEG_0(-1), + DEG_90(0), + DEG_180(1), + DEG_270(2); + + public final int value; + + ImageRotation(int value) { + this.value = value; + } + + public boolean isRotated() { + return this.value==DEG_90.value || this.value==DEG_270.value; + } + } + } +} diff --git a/chameleon-server/src/main/java/com/chameleonvision/common/vision/target/TrackedTarget.java b/chameleon-server/src/main/java/com/chameleonvision/common/vision/target/TrackedTarget.java index 169950a7d..77c57b722 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/common/vision/target/TrackedTarget.java +++ b/chameleon-server/src/main/java/com/chameleonvision/common/vision/target/TrackedTarget.java @@ -1,4 +1,116 @@ package com.chameleonvision.common.vision.target; +import com.chameleonvision.common.util.numbers.DoubleCouple; +import com.chameleonvision.common.vision.opencv.Contour; +import org.apache.commons.math3.util.FastMath; +import org.opencv.core.Point; +import org.opencv.core.RotatedRect; + +import java.util.List; + +// TODO: banks fix public class TrackedTarget { +// final Contour externalContour; +// +// private Point targetOffsetPoint = null; +// private Point robotOffsetPoint = null; +// +// // Single Grouped +// public TrackedTarget(Contour inputContour) { +// this.externalContour = inputContour; +// +// } +// +// public TrackedTarget(List subContours) { +// +// } +// +// +// private Point calculateOffsetPoint(boolean isLandscape, TargetOffsetPointRegion offsetRegion) { +// Point[] vertices = new Point[4]; +// +// RotatedRect minRect = externalContour.getMinAreaRect(); +// minRect.points(vertices); +// +// Point bl = getMiddle(vertices[0], vertices[1]); +// Point tl = getMiddle(vertices[1], vertices[2]); +// Point tr = getMiddle(vertices[2], vertices[3]); +// Point br = getMiddle(vertices[3], vertices[0]); +// boolean orientation; +// if (isLandscape) { +// orientation = minRect.size.width > minRect.size.height; +// } else { +// orientation = minRect.size.width < minRect.size.height; +// } +// +// Point result = minRect.center; +// switch (offsetRegion) { +// case Top: { +// result = orientation ? tl : tr; +// break; +// } +// case Bottom: { +// result = orientation ? br : bl; +// break; +// } +// case Left: { +// result = orientation ? bl : tl; +// break; +// } +// case Right: { +// result = orientation ? tr : br; +// break; +// } +// } +// return result; +// } +// +// public Point getTargetOffsetPoint(boolean isLandscape, TargetOffsetPointRegion offsetRegion) { +// if (targetOffsetPoint == null) { +// targetOffsetPoint = calculateOffsetPoint(isLandscape, offsetRegion); +// } +// return targetOffsetPoint; +// } +// +// private Point calculateRobotOffsetPoint(DoubleCouple offsetPoint, DoubleCouple offsetEquationValues, RobotOffsetPointMode offsetMode) { +// switch (offsetMode) { +// case Single: +// if (offsetPoint.isEmpty()) { +// offsetPoint.set(camProps.centerX, camProps.centerY); +// } +// +// t.calibratedX = offsetPoint.getFirst(); +// t.calibratedY = offsetPoint.getSecond(); +// break; +// case None: +// t.calibratedX = camProps.centerX; +// t.calibratedY = camProps.centerY; +// break; +// case Dual: +// t.calibratedX = (t.point.x - this.calibrationB) / this.calibrationM; +// t.calibratedY = (t.point.y * this.calibrationM) + this.calibrationB; +// break; +// } +// } +// +// private double calculatePitch(double pixelY, double centerY, double verticalFocalLength) { +// double pitch = FastMath.toDegrees(FastMath.atan((pixelY - centerY) / verticalFocalLength)); +// return (pitch * -1); +// } +// +// private double calculateYaw(double pixelX, double centerX, double horizontalFocalLength) { +// return FastMath.toDegrees(FastMath.atan((pixelX - centerX) / horizontalFocalLength)); +// } +// +// private Point getMiddle(Point p1, Point p2) { +// return new Point(((p1.x + p2.x) / 2), ((p1.y + p2.y) / 2)); +// } +// +// public enum TargetOffsetPointRegion { +// Center, Top, Bottom, Left, Right +// } +// +// public enum RobotOffsetPointMode { +// None, Single, Dual +// } }