From 1e7f380f07236a47454e5fd95186dd9b5fafe9fa Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 7 Nov 2019 16:53:31 -0800 Subject: [PATCH] Rename StreamDivisor enum and work on CameraStreamer --- .../camera/CameraProcess.java | 14 +++++ .../camera/CameraProperties.java | 6 +- .../camera/CameraStaticProperties.java | 32 +++++------ .../camera/CameraStreamer.java | 55 ++++++++++++++++++- .../camera/USBCameraProcess.java | 10 ++-- .../pipeline/pipes/Collect2dTargetsPipe.java | 4 +- .../pipeline/pipes/FilterContoursPipe.java | 2 +- .../vision/camera/CameraDeserializer.java | 2 +- .../vision/camera/StreamDivisor.java | 8 +-- .../vision/camera/USBCamera.java | 2 +- 10 files changed, 101 insertions(+), 34 deletions(-) diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java index d8474979c..bab9235fd 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java @@ -6,8 +6,22 @@ import org.opencv.core.Mat; public interface CameraProcess { CameraProperties getProperties(); + /** + * Get the next camera frame + * @param frame the frame to copy the image into + * @return a Pair of the captured image and how long it took to grab the frame (in uS) + */ Pair getFrame(Mat frame); + /** + * Set the exposure of the camera + * @param exposure the new exposure to set the camera to + */ void setExposure(int exposure); + + /** + * Set the exposure of the camera + * @param brightness the new brightness to set the camera to + */ void setBrightness(int brightness); } diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProperties.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProperties.java index 4e0ab8a4d..2d7589d5d 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProperties.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProperties.java @@ -21,7 +21,7 @@ public class CameraProperties { private static final List ALLOWED_PIXEL_FORMATS = Arrays.asList(VideoMode.PixelFormat.kYUYV, VideoMode.PixelFormat.kMJPEG); private static final Predicate kMinFPSPredicate = (videoMode -> videoMode.fps >= MINIMUM_FPS); - private static final Predicate kMinSizePredicate = (videoMode -> videoMode.width >= MINIMUM_FPS && videoMode.height >= MINIMUM_FPS); + private static final Predicate kMinSizePredicate = (videoMode -> videoMode.width >= MINIMUM_WIDTH && videoMode.height >= MINIMUM_HEIGHT); private static final Predicate kPixelFormatPredicate = (videoMode -> ALLOWED_PIXEL_FORMATS.contains(videoMode.pixelFormat)); public CameraStaticProperties staticProperties; @@ -46,11 +46,11 @@ public class CameraProperties { } public double CalculatePitch(double PixelY, double centerY) { - double pitch = FastMath.toDegrees(FastMath.atan((PixelY - centerY) / staticProperties.VerticalFocalLength)); + double pitch = FastMath.toDegrees(FastMath.atan((PixelY - centerY) / staticProperties.verticalFocalLength)); return (pitch * -1); } public double CalculateYaw(double PixelX, double centerX) { - return FastMath.toDegrees(FastMath.atan((PixelX - centerX) / staticProperties.HorizontalFocalLength)); + return FastMath.toDegrees(FastMath.atan((PixelX - centerX) / staticProperties.horizontalFocalLength)); } } diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java index 5f9e9faee..d31b582c0 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java @@ -5,32 +5,32 @@ import org.apache.commons.math3.util.FastMath; public class CameraStaticProperties { - public final int ImageWidth; - public final int ImageHeight; - public final double FOV; - public final double ImageArea; + public final int imageWidth; + public final int imageHeight; + public final double fov; + public final double imageArea; public final double centerX; public final double centerY; - public final double HorizontalFocalLength; - public final double VerticalFocalLength; + public final double horizontalFocalLength; + public final double verticalFocalLength; public CameraStaticProperties(int imageWidth, int imageHeight, double fov) { - ImageWidth = imageWidth; - ImageHeight = imageHeight; - FOV = fov; - ImageArea = ImageWidth * ImageHeight; - centerX = ((double) ImageWidth / 2) - 0.5; - centerY = ((double) ImageHeight / 2) - 0.5; + this.imageWidth = imageWidth; + this.imageHeight = imageHeight; + this.fov = fov; + imageArea = this.imageWidth * this.imageHeight; + centerX = ((double) this.imageWidth / 2) - 0.5; + centerY = ((double) this.imageHeight / 2) - 0.5; // pinhole model calculations - double diagonalView = FastMath.toRadians(FOV); - Fraction aspectFraction = new Fraction(ImageWidth, ImageHeight); + double diagonalView = FastMath.toRadians(this.fov); + Fraction aspectFraction = new Fraction(this.imageWidth, this.imageHeight); int horizontalRatio = aspectFraction.getNumerator(); int verticalRatio = aspectFraction.getDenominator(); double diagonalAspect = FastMath.hypot(horizontalRatio, verticalRatio); double horizontalView = FastMath.atan(FastMath.tan(diagonalView / 2) * (horizontalRatio / diagonalAspect)) * 2; double verticalView = FastMath.atan(FastMath.tan(diagonalView / 2) * (verticalRatio / diagonalAspect)) * 2; - HorizontalFocalLength = ImageWidth / (2 * FastMath.tan(horizontalView /2)); - VerticalFocalLength = ImageHeight / (2 * FastMath.tan(verticalView /2)); + horizontalFocalLength = this.imageWidth / (2 * FastMath.tan(horizontalView /2)); + verticalFocalLength = this.imageHeight / (2 * FastMath.tan(verticalView /2)); } } diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java index fc3dc2a16..2f98f37c8 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java @@ -1,7 +1,58 @@ package com.chameleonvision.classabstraction.camera; +import com.chameleonvision.vision.camera.CameraManager; +import com.chameleonvision.vision.camera.StreamDivisor; +import com.chameleonvision.web.ServerHandler; +import edu.wpi.cscore.CvSource; +import edu.wpi.first.cameraserver.CameraServer; +import org.opencv.core.CvType; import org.opencv.core.Mat; +import org.opencv.core.Size; +import org.opencv.imgproc.Imgproc; + +public class CameraStreamer { + + private final CameraProcess cameraProcess; + private final String name; + private StreamDivisor divisor = StreamDivisor.NONE; + private CvSource cvSource; + private final Object streamBufferLock = new Object(); + private Mat streamBuffer = new Mat(); + + public CameraStreamer(CameraProcess cameraProcess, String name) { + this.cameraProcess = cameraProcess; + this.name = name; + this.cvSource = CameraServer.getInstance().putVideo(name, + cameraProcess.getProperties().staticProperties.imageWidth / divisor.value, + cameraProcess.getProperties().staticProperties.imageHeight / divisor.value); + } + + + public void setDivisor(StreamDivisor newDivisor) { + this.divisor = newDivisor; + var camValues = cameraProcess.getProperties(); + var newWidth = camValues.staticProperties.imageWidth / newDivisor.value; + var newHeight = camValues.staticProperties.imageHeight / newDivisor.value; + synchronized (streamBufferLock) { + this.streamBuffer = new Mat(newWidth, newHeight, CvType.CV_8UC3); + this.cvSource = CameraServer.getInstance().putVideo(this.name, + cameraProcess.getProperties().staticProperties.imageWidth / divisor.value, + cameraProcess.getProperties().staticProperties.imageHeight / divisor.value); + } + ServerHandler.sendFullSettings(); + } + + public void runStream() { + var newFrame = cameraProcess.getFrame(streamBuffer); + var image = newFrame.getLeft(); + if (divisor.value != 1) { + var camVal = cameraProcess.getProperties().staticProperties; + var newWidth = camVal.imageWidth / divisor.value; + var newHeight = camVal.imageHeight / divisor.value; + Size newSize = new Size(newWidth, newHeight); + Imgproc.resize(image, image, newSize); + } + cvSource.putFrame(image); + } -public interface CameraStreamer { - void streamFrame(Mat frame); } diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java index fcaea50e6..37b259315 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCameraProcess.java @@ -28,10 +28,12 @@ public class USBCameraProcess implements CameraProcess { @Override public Pair getFrame(Mat frame) { - var timestamp = System.nanoTime(); - cvSink.grabFrame(imageBuffer); - imageBuffer.copyTo(frame); - return Pair.of(frame, timestamp - System.nanoTime()); + Long deltaTime; + synchronized (cvSink) { + deltaTime = cvSink.grabFrame(imageBuffer) * 1000L; + imageBuffer.copyTo(frame); + } + return Pair.of(frame, deltaTime); } @Override diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/pipes/Collect2dTargetsPipe.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/pipes/Collect2dTargetsPipe.java index 40c528b1a..abf90f969 100644 --- a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/pipes/Collect2dTargetsPipe.java +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/pipes/Collect2dTargetsPipe.java @@ -61,11 +61,11 @@ public class Collect2dTargetsPipe implements Pipe, List, List maxArea) { diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java index 50bf15ecd..06cf6a539 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraDeserializer.java @@ -31,7 +31,7 @@ public class CameraDeserializer implements JsonDeserializer { boolean isDriver = isDriverObj != null && isDriverObj.getAsBoolean(); int driverExposure = driverExposureObj == null ? USBCamera.DEFAULT_EXPOSURE : driverExposureObj.getAsInt(); int driverBrightness = driverBrightnessObj == null ? USBCamera.DEFAULT_BRIGHTNESS : driverBrightnessObj.getAsInt(); - StreamDivisor divisor = divisorObj == null ? StreamDivisor.none : StreamDivisor.values()[divisorObj.getAsInt()]; + StreamDivisor divisor = divisorObj == null ? StreamDivisor.NONE : StreamDivisor.values()[divisorObj.getAsInt()]; var pipelines = jsonObj.get("pipelines"); List actualPipelines = new ArrayList<>(); diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/StreamDivisor.java b/Main/src/main/java/com/chameleonvision/vision/camera/StreamDivisor.java index 8edb165e2..f621945b4 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/StreamDivisor.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/StreamDivisor.java @@ -1,10 +1,10 @@ package com.chameleonvision.vision.camera; public enum StreamDivisor { - none(1), - half(2), - quarter(4), - sixth(6); + NONE(1), + HALF(2), + QUARTER(4), + SIXTH(6); public final Integer value; diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/USBCamera.java b/Main/src/main/java/com/chameleonvision/vision/camera/USBCamera.java index 726a1712e..28f2db192 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/USBCamera.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/USBCamera.java @@ -16,7 +16,7 @@ import java.util.stream.IntStream; public class USBCamera { private static final double DEFAULT_FOV = 60.8; - private static final StreamDivisor DEFAULT_STREAMDIVISOR = StreamDivisor.none; + private static final StreamDivisor DEFAULT_STREAMDIVISOR = StreamDivisor.NONE; public static final int DEFAULT_EXPOSURE = 50; public static final int DEFAULT_BRIGHTNESS = 50; private static final int MINIMUM_FPS = 30;