diff --git a/Main/src/main/java/com/chameleonvision/MemoryManager.java b/Main/src/main/java/com/chameleonvision/MemoryManager.java new file mode 100644 index 000000000..881789dfd --- /dev/null +++ b/Main/src/main/java/com/chameleonvision/MemoryManager.java @@ -0,0 +1,41 @@ +package com.chameleonvision; + +public class MemoryManager { + + private static final long MEGABYTE_FACTOR = 1024L * 1024L; + + private int collectionThreshold; + private int lastUsedMb = 0; + + public MemoryManager(int collectionThreshold) { + this.collectionThreshold = collectionThreshold; + } + + + public static long getUsedMemory() { + return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); + } + + public static int getUsedMemoryMB() { + return (int) (getUsedMemory() / MEGABYTE_FACTOR); + } + + private static void collect() { + System.gc(); + System.runFinalization(); + } + + public void run() { + var usedMem = getUsedMemoryMB(); + + if (usedMem != lastUsedMb) { + lastUsedMb = usedMem; + System.out.printf("Memory usage: %dMB\n", usedMem); + } + + if (usedMem >= collectionThreshold) { + collect(); + System.out.printf("Garbage collected at %dMB\n", usedMem); + } + } +} diff --git a/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java b/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java index e714a3a41..c8703af46 100644 --- a/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java +++ b/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java @@ -45,8 +45,6 @@ public class SettingsManager { private Path SettingsPath = Paths.get(System.getProperty("user.dir"),"Settings"); private Path CamsPath = Paths.get(SettingsPath.toString(),"Cams"); - - private void InitiateGeneralSettings(){ CheckPath(SettingsPath); try { diff --git a/Main/src/main/java/com/chameleonvision/vision/Camera.java b/Main/src/main/java/com/chameleonvision/vision/Camera.java index d64bf4cb5..fde8e0326 100644 --- a/Main/src/main/java/com/chameleonvision/vision/Camera.java +++ b/Main/src/main/java/com/chameleonvision/vision/Camera.java @@ -8,5 +8,4 @@ public class Camera { public HashMap pipelines; public int resolution = 0; public CamVideoMode camVideoMode; - } diff --git a/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java b/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java index e1c907c89..8ae8efb43 100644 --- a/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java @@ -1,5 +1,6 @@ package com.chameleonvision.vision.process; +import com.chameleonvision.MemoryManager; import com.chameleonvision.settings.SettingsManager; import com.chameleonvision.vision.Pipeline; import edu.wpi.first.networktables.NetworkTableInstance; @@ -7,8 +8,12 @@ import edu.wpi.first.cameraserver.CameraServer; import org.opencv.core.Mat; import org.apache.commons.math3.fraction.Fraction; import org.apache.commons.math3.util.FastMath; +import org.opencv.core.MatOfPoint; -public class CameraProcess implements Runnable{ +import java.util.ArrayList; +import java.util.List; + +public class CameraProcess implements Runnable { private String CameraName; public CameraProcess(String CameraName){ this.CameraName = CameraName; @@ -23,17 +28,17 @@ public class CameraProcess implements Runnable{ SettingsManager manager = SettingsManager.getInstance(); SettingsManager.CamerasCurrentPipeline.put(CameraName, SettingsManager.Cameras.get(CameraName).pipelines.keySet().toArray()[0].toString()); //Setting up camera and network table - var Table = networkTableInstance.getTable("/Chameleon-vision/" + CameraName); + var Table = networkTableInstance.getTable("/chameleon-vision/" + CameraName); var PipeLineEntry = Table.getEntry("Pipeline"); var DriverModeEntry = Table.getEntry("Driver_Mode"); - var cv_sink = cs.getVideo(manager.UsbCameras.get(CameraName)); + var cv_sink = cs.getVideo(SettingsManager.UsbCameras.get(CameraName)); - int Width = manager.Cameras.get(CameraName).camVideoMode.width; - int Height = manager.Cameras.get(CameraName).camVideoMode.heigh; + int Width = SettingsManager.Cameras.get(CameraName).camVideoMode.width; + int Height = SettingsManager.Cameras.get(CameraName).camVideoMode.heigh; var cv_publish = cs.putVideo(CameraName,Width,Height); //initial math setup for camera - double DiagonalView = FastMath.toRadians(manager.Cameras.get(CameraName).FOV); + double DiagonalView = FastMath.toRadians(SettingsManager.Cameras.get(CameraName).FOV); Fraction AspectFraction = new Fraction(Width,Height); int HorizontalRatio = AspectFraction.getNumerator(); int VerticalRatio = AspectFraction.getDenominator(); @@ -48,16 +53,32 @@ public class CameraProcess implements Runnable{ Mat mat = new Mat(); long time; + MemoryManager memManager = new MemoryManager(125); + + Pipeline currentPipeline; + Mat HSVImage = new Mat(); + List FoundContours = new ArrayList<>(); + List FilteredContours = new ArrayList<>(); + while (!Thread.interrupted()){ - Pipeline pipeline = manager.Cameras.get(CameraName).pipelines.get(manager.CamerasCurrentPipeline.get(CameraName)); + FoundContours.clear(); + FilteredContours.clear(); + + currentPipeline = SettingsManager.Cameras.get(CameraName).pipelines.get(SettingsManager.CamerasCurrentPipeline.get(CameraName)); time = cv_sink.grabFrame(mat); if (mat.cols() !=0 && mat.rows() != 0) { - Mat HSVImage = visionProcess.HSVThreshold(pipeline.hue, pipeline.saturation, pipeline.value, mat, pipeline.erode, pipeline.dilate); -// List Contours = visionProcess.FindContours(HSVImage); -// List FilterdContours = visionProcess.FilterContours(Contours, pipeline.area, pipeline.ratio, pipeline.extent, pipeline.sort_mode, pipeline.target_intersection, pipeline.target_group); + HSVImage = visionProcess.HSVThreshold(currentPipeline.hue, currentPipeline.saturation, currentPipeline.value, mat, currentPipeline.erode, currentPipeline.dilate); + FoundContours = visionProcess.FindContours(HSVImage); + FilteredContours = visionProcess.FilterContours(FoundContours, currentPipeline.area, currentPipeline.ratio, currentPipeline.extent, currentPipeline.sort_mode, currentPipeline.target_intersection, currentPipeline.target_group); + cv_publish.putFrame(mat); + mat.release(); + HSVImage.release(); + for (MatOfPoint oldMat : FoundContours) { oldMat.release(); } + for (MatOfPoint oldMat1 : FilteredContours) { oldMat1.release(); } } + memManager.run(); } } diff --git a/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java b/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java index ea4d9c18f..79e41c727 100644 --- a/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java +++ b/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java @@ -9,42 +9,53 @@ import java.util.HashMap; import java.util.List; public class VisionProcess { - private HashMapTargetGrouping= new HashMap(){{ - put("Single",1); - put("Dual",2); - put("Triple",3); - put("Quadruple",4); - put("Quintuple",5); + + private HashMapTargetGrouping= new HashMap<>() {{ + put("Single", 1); + put("Dual", 2); + put("Triple", 3); + put("Quadruple", 4); + put("Quintuple", 5); }}; - private double CamArea,CenterX, CenterY; + + private double CamArea, CenterX, CenterY; + VisionProcess(double CenterX, double CenterY, double CamArea){ this.CenterX = CenterX; this.CenterY = CenterY; this.CamArea = CamArea; } + private Mat Kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5)); - public Mat HSVThreshold(@NotNull List hue, @NotNull List saturation , @NotNull List value, Mat image, boolean IsErode, boolean IsDilate){ - Mat hsv = new Mat(); - Imgproc.cvtColor(image,hsv,Imgproc.COLOR_BGR2HSV,3); - new Scalar(hue.get(0),saturation.get(0),value.get(0)); - Mat threshold = new Mat(); - Core.inRange(hsv,new Scalar(hue.get(0),saturation.get(0),value.get(0)),new Scalar(hue.get(1),saturation.get(1),value.get(1)),threshold); + private Mat hsvMat = new Mat(); + private Mat hsvThreshMat = new Mat(); + private Scalar hsvLower, hsvUpper; + + Mat HSVThreshold(@NotNull List hue, @NotNull List saturation, @NotNull List value, Mat image, boolean IsErode, boolean IsDilate){ + Imgproc.cvtColor(image, hsvMat,Imgproc.COLOR_BGR2HSV,3); + hsvLower = new Scalar(hue.get(0), saturation.get(0), value.get(0)); + hsvUpper = new Scalar(hue.get(1), saturation.get(1), value.get(1)); + Core.inRange(hsvMat, hsvLower, hsvUpper, hsvThreshMat); if (IsErode){ - Imgproc.erode(threshold,threshold, Kernel); + Imgproc.erode(hsvThreshMat, hsvThreshMat, Kernel); } if (IsDilate){ - Imgproc.dilate(threshold,threshold, Kernel); + Imgproc.dilate(hsvThreshMat, hsvThreshMat, Kernel); } - return threshold; + return hsvThreshMat; } + + private List FoundContours = new ArrayList<>(); public List FindContours(Mat BinaryImage){ - List Contours = new ArrayList<>(); - Imgproc.findContours(BinaryImage,Contours,new Mat(),Imgproc.RETR_EXTERNAL,Imgproc.CHAIN_APPROX_TC89_L1); - return Contours; + FoundContours.clear(); + Imgproc.findContours(BinaryImage, FoundContours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_L1); + BinaryImage.release(); + return FoundContours; } - public List FilterContours(List InputContours, List area, List ratio, List extent, String SortMode,String TargetIntersection , String TargetGrouping){ - List FilteredContours = new ArrayList(); + + private List FilteredContours = new ArrayList(); + public List FilterContours(List InputContours, List area, List ratio, List extent, String SortMode, String TargetIntersection, String TargetGrouping){ for (MatOfPoint Contour : InputContours){ try{ var contourArea = Imgproc.contourArea(Contour); @@ -62,24 +73,29 @@ public class VisionProcess { continue; } FilteredContours.add(Contour); - } catch (Exception e){ - continue; + } + catch (Exception e) { + } } return FilteredContours; } - private List GroupTargets(List InputContours, String IntersectionPoint,String TargetGroup){ + + private List FinalCountours = new ArrayList<>(); + private List GroupTargets(List InputContours, String IntersectionPoint,String TargetGroup) { + FinalCountours.clear(); if (!TargetGroup.equals("Single")){ - List FinalCountours = new ArrayList(); for (var i = 0; i < InputContours.size(); i++){ var FinalContour = InputContours.get(i); for (var c = 0; c < (TargetGrouping.get(TargetGroup)-1);c++){ try{ MatOfPoint firstContour = InputContours.get(i + c); - MatOfPoint secoundContour = InputContours.get(i+c+1); - if (IsIntersecting(firstContour,secoundContour, IntersectionPoint)){ + MatOfPoint secondContour = InputContours.get(i+c+1); + if (IsIntersecting(firstContour, secondContour, IntersectionPoint)){ System.out.println(""); } + firstContour.release(); + secondContour.release(); } catch (IndexOutOfBoundsException e){ FinalContour = new MatOfPoint(); break; @@ -90,12 +106,13 @@ public class VisionProcess { } return InputContours; } - private boolean IsIntersecting(MatOfPoint ContourOne, MatOfPoint ContourTwo, String IntersectionPoint){ - Mat LineA = new Mat(); - Imgproc.fitLine(ContourOne,LineA,Imgproc.CV_DIST_L2,0,0.01,0.01); - Mat LineB = new Mat(); - Imgproc.fitLine(ContourTwo,LineB,Imgproc.CV_DIST_L2,0,0.01,0.01); + + private Mat intersectMatA = new Mat(); + private Mat intersectMatB = new Mat(); + private boolean IsIntersecting(MatOfPoint ContourOne, MatOfPoint ContourTwo, String IntersectionPoint) { + Imgproc.fitLine(ContourOne, intersectMatA, Imgproc.CV_DIST_L2,0,0.01,0.01); + Imgproc.fitLine(ContourTwo, intersectMatB, Imgproc.CV_DIST_L2,0,0.01,0.01); +// Rect2d = return true; } - }