diff --git a/Main/chameleon-vision.iml b/Main/chameleon-vision.iml index 13d0e774e..bb72d8934 100644 --- a/Main/chameleon-vision.iml +++ b/Main/chameleon-vision.iml @@ -10,9 +10,6 @@ - - - diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java new file mode 100644 index 000000000..fe5777c0c --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProcess.java @@ -0,0 +1,11 @@ +package com.chameleonvision.classabstraction.camera; + +import org.apache.commons.lang3.tuple.Pair; +import org.opencv.core.Mat; + +public interface CameraProcess { + Pair getFrame(); + + void setExposure(int exposure); + 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 new file mode 100644 index 000000000..57a78d2fb --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraProperties.java @@ -0,0 +1,57 @@ +package com.chameleonvision.classabstraction.camera; + +import edu.wpi.cscore.UsbCamera; +import edu.wpi.cscore.VideoMode; +import org.apache.commons.math3.util.FastMath; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CameraProperties { + private static final double DEFAULT_FOV = 70; + private static final int DEFAULT_EXPOSURE = 50; + private static final int DEFAULT_BRIGHTNESS = 50; + private static final int MINIMUM_FPS = 30; + private static final int MINIMUM_WIDTH = 320; + private static final int MINIMUM_HEIGHT = 200; + private static final int MAX_INIT_MS = 1500; + 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 kPixelFormatPredicate = (videoMode -> ALLOWED_PIXEL_FORMATS.contains(videoMode.pixelFormat)); + + public CameraStaticProperties staticProperties; + public final double FOV; + public final List videoModes; + + public CameraProperties(UsbCamera baseCamera, double fov) { + FOV = fov; + + videoModes = filterVideoModes(baseCamera.enumerateVideoModes()); + + + } + + private List filterVideoModes(VideoMode[] videoModes) { + Predicate fullPredicate = kMinFPSPredicate.and(kMinSizePredicate).and(kPixelFormatPredicate); + Stream validModes = Arrays.stream(videoModes).filter(fullPredicate); + return validModes.collect(Collectors.toList()); + } + + public void updateVideoMode(VideoMode videoMode) { + staticProperties = new CameraStaticProperties(videoMode.width, videoMode.height, FOV); + } + + public double CalculatePitch(double PixelY, double centerY) { + 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)); + } +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java new file mode 100644 index 000000000..7242fb3c4 --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStaticProperties.java @@ -0,0 +1,36 @@ +package com.chameleonvision.classabstraction.camera; + +import org.apache.commons.math3.fraction.Fraction; +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 double CenterX; + public final double CenterY; + 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; + + // pinhole model calculations + double diagonalView = FastMath.toRadians(FOV); + Fraction aspectFraction = new Fraction(ImageWidth, 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)); + } +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java new file mode 100644 index 000000000..fc3dc2a16 --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/CameraStreamer.java @@ -0,0 +1,7 @@ +package com.chameleonvision.classabstraction.camera; + +import org.opencv.core.Mat; + +public interface CameraStreamer { + void streamFrame(Mat frame); +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCamera.java b/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCamera.java new file mode 100644 index 000000000..e2212f8f2 --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/camera/USBCamera.java @@ -0,0 +1,15 @@ +package com.chameleonvision.classabstraction.camera; + +import edu.wpi.cscore.UsbCamera; +import edu.wpi.cscore.VideoMode; + +public class USBCamera { + private final UsbCamera baseCamera; + private final CameraProperties properties; + + public USBCamera(UsbCamera camera) { + baseCamera = camera; + VideoMode vidMode = new VideoMode(VideoMode.PixelFormat.kYUYV, 640, 480, 60); + properties = new CameraProperties(baseCamera, 75); + } +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline.java new file mode 100644 index 000000000..fc057b790 --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline.java @@ -0,0 +1,21 @@ +package com.chameleonvision.classabstraction.pipeline; + +import org.opencv.core.Mat; + +/** + * + * @param Pipeline result type + */ +public abstract class CVPipeline { + private CVPipelineSettings settings; + private Mat inputMat; + protected Mat outputMat; + + public CVPipeline(CVPipelineSettings settings) { + this.settings = settings; + } + + abstract void initPipeline(); + abstract R runPipeline(Mat inputMat); + abstract Mat getOutputMat(); +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline2dSettings.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline2dSettings.java new file mode 100644 index 000000000..20dd868ba --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline2dSettings.java @@ -0,0 +1,4 @@ +package com.chameleonvision.classabstraction.pipeline; + +public class CVPipeline2dSettings extends CVPipelineSettings { +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline3dSettings.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline3dSettings.java new file mode 100644 index 000000000..b18a2e048 --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipeline3dSettings.java @@ -0,0 +1,4 @@ +package com.chameleonvision.classabstraction.pipeline; + +public abstract class CVPipeline3dSettings extends CVPipelineSettings { +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineSettings.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineSettings.java new file mode 100644 index 000000000..c5f3281ae --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/CVPipelineSettings.java @@ -0,0 +1,30 @@ +package com.chameleonvision.classabstraction.pipeline; + +import com.chameleonvision.vision.CalibrationMode; +import com.chameleonvision.vision.SortMode; +import com.chameleonvision.vision.TargetGroup; +import com.chameleonvision.vision.TargetIntersection; + +import java.util.Arrays; +import java.util.List; + +public abstract class CVPipelineSettings { + List hue = Arrays.asList(50, 180); + List saturation = Arrays.asList(50, 255); + List value = Arrays.asList(50, 255); + boolean erode = false; + boolean dilate = false; + List area = Arrays.asList(0.0, 100.0); + List ratio = Arrays.asList(0.0, 20.0); + List extent = Arrays.asList(0, 100); + Number speckle = 5; + boolean isBinary = false; + SortMode sortMode = SortMode.Largest; + TargetGroup targetGroup = TargetGroup.Single; + TargetIntersection targetIntersection = TargetIntersection.Up; + double m = 1; + double b = 0; + List point = Arrays.asList(0,0); + CalibrationMode calibrationMode = CalibrationMode.None; + String nickname = ""; +} diff --git a/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/DriverVisionPipeline.java b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/DriverVisionPipeline.java new file mode 100644 index 000000000..200c38eb9 --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/classabstraction/pipeline/DriverVisionPipeline.java @@ -0,0 +1,25 @@ +package com.chameleonvision.classabstraction.pipeline; + +import org.opencv.core.Mat; + +public class DriverVisionPipeline extends CVPipeline { + public DriverVisionPipeline(CVPipelineSettings settings) { + super(settings); + } + + @Override + void initPipeline() { + // set exposure/brightness of camera? + } + + @Override + Void runPipeline(Mat inputMat) { + this.outputMat = inputMat; + return null; + } + + @Override + Mat getOutputMat() { + return this.outputMat; + } +} diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java index a4855feec..d43f82ee4 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java @@ -43,7 +43,7 @@ public class CameraManager { public static HashMap getAllCamerasByName() { return allCamerasByName; } - public static List getAllCameraByNickname(){ + public static List getAllCameraByNickname() { var cameras = getAllCamerasByName(); return cameras.values().stream().map(USBCamera::getNickname).collect(Collectors.toList()); } @@ -101,6 +101,7 @@ public class CameraManager { if (curCam == null) throw new CameraException(CameraException.CameraExceptionType.BAD_CAMERA); return curCam; } + public static Integer getCurrentCameraIndex() throws CameraException { if (allCamerasByName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA); List arr = new ArrayList<>(allCamerasByName.keySet()); @@ -118,6 +119,7 @@ public class CameraManager { SettingsManager.generalSettings.currentCamera = cameraName; SettingsManager.updateCameraSetting(cameraName, getCurrentCamera().getCurrentPipelineIndex()); } + public static void setCurrentCamera(int cameraIndex) throws CameraException { List s = new ArrayList(allCamerasByName.keySet()); setCurrentCamera(s.get(cameraIndex)); diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraValues.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraValues.java index 50dcde294..8335f3bd6 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraValues.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraValues.java @@ -3,7 +3,6 @@ package com.chameleonvision.vision.camera; import org.apache.commons.math3.fraction.Fraction; import org.apache.commons.math3.util.FastMath; -@SuppressWarnings("WeakerAccess") public class CameraValues { public final int ImageWidth; public final int ImageHeight; @@ -11,20 +10,14 @@ public class CameraValues { public final double ImageArea; public final double CenterX; public final double CenterY; - public final double DiagonalView; - public final double DiagonalAspect; - public final Fraction AspectFraction; - public final int HorizontalRatio; - public final int VerticalRatio; - public final double HorizontalView; - public final double VerticalView; - public final double HorizontalFocalLength; - public final double VerticalFocalLength; + private final double HorizontalFocalLength; + private final double VerticalFocalLength; public CameraValues(USBCamera USBCamera) { this(USBCamera.getVideoMode().width, USBCamera.getVideoMode().height, USBCamera.getFOV()); } + public CameraValues(int imageWidth, int imageHeight, double fov) { ImageWidth = imageWidth; ImageHeight = imageHeight; @@ -32,21 +25,25 @@ public class CameraValues { ImageArea = ImageWidth * ImageHeight; CenterX = ((double) ImageWidth / 2) - 0.5; CenterY = ((double) ImageHeight / 2) - 0.5; - DiagonalView = FastMath.toRadians(FOV); - AspectFraction = new Fraction(ImageWidth, ImageHeight); - HorizontalRatio = AspectFraction.getNumerator(); - VerticalRatio = AspectFraction.getDenominator(); - DiagonalAspect = FastMath.hypot(HorizontalRatio, VerticalRatio); - HorizontalView = FastMath.atan(FastMath.tan(DiagonalView / 2) * (HorizontalRatio / DiagonalAspect)) * 2; - VerticalView = FastMath.atan(FastMath.tan(DiagonalView / 2) * (VerticalRatio / DiagonalAspect)) * 2; - HorizontalFocalLength = ImageWidth / (2 * FastMath.tan(HorizontalView /2)); - VerticalFocalLength = ImageHeight / (2 * FastMath.tan(VerticalView /2)); + + // pinhole model calculations + double diagonalView = FastMath.toRadians(FOV); + Fraction aspectFraction = new Fraction(ImageWidth, 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)); } - public double CalculatePitch(double PixelY, double centerY){ - double pitch = FastMath.toDegrees(FastMath.atan((PixelY - centerY) / VerticalFocalLength)); + + public double CalculatePitch(double PixelY, double centerY) { + double pitch = FastMath.toDegrees(FastMath.atan((PixelY - centerY) / VerticalFocalLength)); return (pitch * -1); } - public double CalculateYaw(double PixelX, double centerX){ + + public double CalculateYaw(double PixelX, double centerX) { return FastMath.toDegrees(FastMath.atan((PixelX - centerX) / HorizontalFocalLength)); } }