Major pipeline optimizations, moved grabFrame in to vision thread

This commit is contained in:
Banks Troutman
2019-11-26 02:55:05 -05:00
parent 4bebc3d063
commit f6e56ce930
15 changed files with 236 additions and 289 deletions

View File

@@ -11,6 +11,7 @@ import com.google.gson.GsonBuilder;
import edu.wpi.cscore.VideoMode;
import edu.wpi.first.networktables.*;
import edu.wpi.first.wpiutil.CircularBuffer;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Mat;
import java.util.ArrayList;
@@ -21,7 +22,6 @@ public class VisionProcess {
private final CameraCapture cameraCapture;
private final List<CVPipeline> pipelines = new ArrayList<>();
private final CameraFrameRunnable cameraRunnable;
private final CameraStreamerRunnable streamRunnable;
private final VisionProcessRunnable visionRunnable;
public final CameraStreamer cameraStreamer;
@@ -32,13 +32,10 @@ public class VisionProcess {
private final CVPipelineSettings driverModeSettings = new CVPipelineSettings();
private CVPipeline driverModePipeline = new DriverVisionPipeline(driverModeSettings);
// shitty stuff
private volatile Mat lastCameraFrame = new Mat();
private volatile boolean hasUnprocessedFrame = true;
private volatile CVPipelineResult lastPipelineResult;
// network table stuff
private NetworkTable defaultTable;
private final NetworkTable defaultTable;
private NetworkTableEntry ntPipelineEntry;
private NetworkTableEntry ntDriverModeEntry;
private int ntDriveModeListenerID;
@@ -57,14 +54,6 @@ public class VisionProcess {
pipelines.add(new CVPipeline2d("New Pipeline"));
setPipeline(0, false);
// Thread to grab frames from the camera
// TODO: (HIGH) fix video modes!!!
this.cameraRunnable = new CameraFrameRunnable(cameraCapture.getProperties().videoModes.get(0).fps);
lastPipelineResult = new DriverVisionPipeline.DriverPipelineResult(
null, cameraRunnable.getFrame(new Mat()), 0
);
// Thread to put frames on the dashboard
this.cameraStreamer = new CameraStreamer(cameraCapture, name);
this.streamRunnable = new CameraStreamerRunnable(30, cameraStreamer);
@@ -77,18 +66,8 @@ public class VisionProcess {
}
public void start() {
System.out.println("Starting NetworkTables");
System.out.println("Starting NetworkTables.");
initNT(defaultTable);
System.out.println("Starting camera thread.");
new Thread(cameraRunnable).start();
while (cameraRunnable.cameraFrame == null) {
try {
if (lastCameraFrame.cols() > 0) break;
} catch (Exception e) {
// e.printStackTrace();
}
}
System.out.println("Starting vision thread.");
new Thread(visionRunnable).start();
System.out.println("Starting stream thread.");
@@ -217,7 +196,7 @@ public class VisionProcess {
//noinspection unchecked
List<CVPipeline2d.Target2d> targets = (List<CVPipeline2d.Target2d>) data.targets;
ntTimeStampEntry.setDouble(data.processTime);
ntTimeStampEntry.setDouble(data.imageTimestamp);
ntPitchEntry.setDouble(targets.get(0).pitch);
ntYawEntry.setDouble(targets.get(0).yaw);
ntAreaEntry.setDouble(targets.get(0).area);
@@ -231,12 +210,12 @@ public class VisionProcess {
ntYawEntry.setDouble(0.0);
ntAreaEntry.setDouble(0.0);
ntTimeStampEntry.setDouble(0.0);
ntAuxListEntry.setString("");
}
}
public void setVideoMode(VideoMode newMode) {
cameraCapture.setVideoMode(newMode);
cameraRunnable.updateCameraFPS(newMode.fps);
cameraStreamer.setNewVideoMode(newMode);
}
@@ -277,59 +256,6 @@ public class VisionProcess {
return pipelines.get(pipelineIndex);
}
/**
* CameraFrameRunnable grabs images from the cameraProcess
* at a specified loopTime
*/
protected class CameraFrameRunnable extends LoopingRunnable {
private Mat cameraFrame;
private long timestampMicros;
private final Object frameLock = new Object();
/**
* CameraFrameRunnable grabs images from the cameraProcess
* at a specified framerate
* @param cameraFPS FPS of camera
*/
CameraFrameRunnable(int cameraFPS) {
// add 2 FPS to allow for a bit of overhead
// TODO: (low) test the effect of this
super(1000L/(cameraFPS + 2));
}
void updateCameraFPS(int newFPS) {
super.loopTimeMs = 1000L / (newFPS + 2);
}
@Override
public void process() {
// Grab camera frames
var camData = cameraCapture.getFrame();
if (camData.getLeft().cols() > 0) {
// System.out.println("grabbing frame");
// synchronized (frameLock) {
// cameraFrame = camData.getLeft();
// }
timestampMicros = camData.getRight();
camData.getLeft().copyTo(lastCameraFrame);
hasUnprocessedFrame = true;
}
}
public Mat getFrame(Mat dst) {
if (cameraFrame != null) {
dst = cameraFrame;
} else {
System.out.println("no frame");
}
return dst;
}
}
/**
* VisionProcessRunnable will process images as quickly as possible
*/
@@ -337,48 +263,36 @@ public class VisionProcess {
volatile Double fps = 0.0;
private CircularBuffer fpsAveragingBuffer = new CircularBuffer(7);
@SuppressWarnings("FieldCanBeLocal")
private CVPipelineResult result;
private Mat streamBuffer = new Mat();
@Override
public void run() {
var lastUpdateTimeNanos = System.nanoTime();
while(!Thread.interrupted()) {
// System.out.println("running vision process");
while(!hasUnprocessedFrame) {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// blocking call, will block until camera has a new frame.
Pair<Mat, Long> camData = cameraCapture.getFrame();
lastCameraFrame.copyTo(streamBuffer); // = //cameraRunnable.getFrame(streamBuffer);
hasUnprocessedFrame = false;
if (streamBuffer.cols() > 0 && streamBuffer.rows() > 0) {
result = currentPipeline.runPipeline(streamBuffer);
lastPipelineResult = result;
Mat camFrame = camData.getLeft();
if (camFrame.cols() > 0 && camFrame.rows() > 0) {
CVPipelineResult result = currentPipeline.runPipeline(camFrame);
if (result != null) {
result.setTimestamp(camData.getRight());
lastPipelineResult = result;
updateNetworkTableData(lastPipelineResult);
updateUI(lastPipelineResult);
}
}
var deltaTimeNanos = lastUpdateTimeNanos - System.nanoTime();
fpsAveragingBuffer.addFirst(1.0 / (deltaTimeNanos * 1E-09));
lastUpdateTimeNanos = System.nanoTime();
fps = getAverageFPS();
// TODO: (HIGH) do something with the result
}
}
public double getAverageFPS() {
double getAverageFPS() {
var temp = 0.0;
for(int i = 0; i < 7; i++) {
temp += fpsAveragingBuffer.get(i);
@@ -389,31 +303,32 @@ public class VisionProcess {
}
private class CameraStreamerRunnable extends LoopingRunnable {
private static class CameraStreamerRunnable extends LoopingRunnable {
public final CameraStreamer streamer;
final CameraStreamer streamer;
private Mat streamBuffer = new Mat();
private CameraStreamerRunnable(int cameraFPS, CameraStreamer streamer) {
// add 2 FPS to allow for a bit of overhead
// TODO: (low) test the effect of this
super(1000L/(cameraFPS + 2));
// super(1000L/(cameraFPS + 2));
super(10L);
this.streamer = streamer;
}
@Override
protected void process() {
// System.out.println("running camera streamer");
Mat latestMat = lastPipelineResult.outputMat; //visionRunnable.result;
if (latestMat != null && latestMat.cols() > 0) {
latestMat.copyTo(streamBuffer);
streamer.runStream(streamBuffer);
streamBuffer.release();
// Mat latestMat = lastPipelineResult.outputMat; //visionRunnable.result;
// if (latestMat != null && latestMat.cols() > 0) {
// latestMat.copyTo(streamBuffer);
// streamer.runStream(streamBuffer);
// streamBuffer.release();
// if (toStreamMat != null && toStreamMat.cols() > 0) {
// } else {
// System.out.println("fuuuuck");
// }
}
// }
}
}
}

View File

@@ -31,9 +31,8 @@ public class USBCameraCapture implements CameraCapture {
@Override
public Pair<Mat, Long> getFrame() {
Long deltaTime;
synchronized (cvSink) {
deltaTime = cvSink.grabFrame(imageBuffer) * 1000L;
}
// TODO: Why multiply by 1000 here?
deltaTime = cvSink.grabFrame(imageBuffer) * 1000L;
return Pair.of(imageBuffer, deltaTime);
}

View File

@@ -89,11 +89,10 @@ public class CVPipeline2d extends CVPipeline<CVPipeline2dResult, CVPipeline2dSet
if (cameraCapture == null) {
throw new RuntimeException("Pipeline was not initialized before being run!");
}
if(inputMat.cols() <= 1) {
if (inputMat.cols() <= 1) {
throw new RuntimeException("Input Mat is empty!");
}
pipelineTimeStringBuilder = new StringBuilder();
inputMat.copyTo(rawCameraMat);

View File

@@ -9,6 +9,7 @@ public abstract class CVPipelineResult<T> {
public final boolean hasTarget;
public final Mat outputMat;
public final long processTime;
public long imageTimestamp = 0;
public CVPipelineResult(List<T> targets, Mat outputMat, long processTime) {
this.targets = targets;
@@ -16,4 +17,8 @@ public abstract class CVPipelineResult<T> {
this.outputMat = outputMat;
this.processTime = processTime;
}
public void setTimestamp(long timestamp) {
imageTimestamp = timestamp;
}
}

View File

@@ -30,6 +30,7 @@ public class BlurPipe implements Pipe<Mat, Mat> {
try {
Imgproc.blur(processBuffer, processBuffer, new Size(blurSize, blurSize));
processBuffer.copyTo(outputMat);
processBuffer.release();
} catch (CvException e) {
System.err.println("(BlurPipe) Exception thrown by OpenCV: \n" + e.getMessage());
}
@@ -37,10 +38,7 @@ public class BlurPipe implements Pipe<Mat, Mat> {
input.copyTo(outputMat);
}
long processTime = System.nanoTime() - processStartNanos;
Pair<Mat, Long> output = Pair.of(outputMat, processTime);
processBuffer.release();
return output;
return Pair.of(outputMat, processTime);
}
}

View File

@@ -43,30 +43,32 @@ public class Collect2dTargetsPipe implements Pipe<List<RotatedRect>, List<CVPipe
targets.clear();
input.forEach(r -> {
CVPipeline2d.Target2d t = new CVPipeline2d.Target2d();
t.rawPoint = r;
switch (calibrationMode) {
case None:
t.calibratedX = camProps.centerX;
t.calibratedY = camProps.centerY;
break;
case Single:
t.calibratedX = calibrationPoint.get(0).doubleValue();
t.calibratedY = calibrationPoint.get(1).doubleValue();
break;
case Dual:
t.calibratedX = (r.center.y - calibrationB) / calibrationM;
t.calibratedY = (r.center.x * calibrationM) + calibrationB;
break;
if (input.size() > 0) {
for (RotatedRect r : input) {
CVPipeline2d.Target2d t = new CVPipeline2d.Target2d();
t.rawPoint = r;
switch (calibrationMode) {
case None:
t.calibratedX = camProps.centerX;
t.calibratedY = camProps.centerY;
break;
case Single:
t.calibratedX = calibrationPoint.get(0).doubleValue();
t.calibratedY = calibrationPoint.get(1).doubleValue();
break;
case Dual:
t.calibratedX = (r.center.y - calibrationB) / calibrationM;
t.calibratedY = (r.center.x * calibrationM) + calibrationB;
break;
}
t.pitch = calculatePitch(r.center.y, t.calibratedY);
t.yaw = calculateYaw(r.center.x, t.calibratedX);
t.area = r.size.area();
targets.add(t);
}
t.pitch = calculatePitch(r.center.y, t.calibratedY);
t.yaw = calculateYaw(r.center.x, t.calibratedX);
t.area = r.size.area();
targets.add(t);
});
}
long processTime = System.nanoTime() - processStartNanos;
return Pair.of(targets, processTime);

View File

@@ -17,6 +17,7 @@ public class Draw2dContoursPipe implements Pipe<Pair<Mat, List<RotatedRect>>, Ma
private final Draw2dContoursSettings settings;
private CaptureStaticProperties camProps;
private Mat processBuffer = new Mat();
private Mat outputMat = new Mat();
public Draw2dContoursPipe(Draw2dContoursSettings settings, CaptureStaticProperties camProps) {
@@ -32,48 +33,51 @@ public class Draw2dContoursPipe implements Pipe<Pair<Mat, List<RotatedRect>>, Ma
public Pair<Mat, Long> run(Pair<Mat, List<RotatedRect>> input) {
long processStartNanos = System.nanoTime();
outputMat = input.getLeft();
if (settings.showCrosshair || settings.showCentroid || settings.showMaximumBox || settings.showRotatedBox) {
input.getLeft().copyTo(processBuffer);
if (input.getRight() != null && !input.getRight().isEmpty()) {
for (RotatedRect r : input.getRight()) {
if (r == null) continue;
if (input.getRight().size() > 0) {
for (RotatedRect r : input.getRight()) {
if (r == null) continue;
List<MatOfPoint> drawnContour = new ArrayList<>();
Point[] vertices = new Point[4];
r.points(vertices);
MatOfPoint contour = new MatOfPoint(vertices);
drawnContour.add(contour);
List<MatOfPoint> drawnContour = new ArrayList<>();
Point[] vertices = new Point[4];
r.points(vertices);
MatOfPoint contour = new MatOfPoint(vertices);
drawnContour.add(contour);
if (settings.showCentroid) {
Imgproc.circle(outputMat, r.center, 3, Helpers.colorToScalar(settings.centroidColor));
}
if (settings.showCentroid) {
Imgproc.circle(processBuffer, r.center, 3, Helpers.colorToScalar(settings.centroidColor));
}
if (settings.showRotatedBox) {
Imgproc.drawContours(outputMat, drawnContour, 0, Helpers.colorToScalar(settings.rotatedBoxColor), settings.boxOutlineSize);
}
if (settings.showRotatedBox) {
Imgproc.drawContours(processBuffer, drawnContour, 0, Helpers.colorToScalar(settings.rotatedBoxColor), settings.boxOutlineSize);
}
if (settings.showMaximumBox) {
Rect box = Imgproc.boundingRect(contour);
Imgproc.rectangle(outputMat, new Point(box.x, box.y), new Point((box.x + box.width), (box.y + box.height)), Helpers.colorToScalar(settings.maximumBoxColor), settings.boxOutlineSize);
if (settings.showMaximumBox) {
Rect box = Imgproc.boundingRect(contour);
Imgproc.rectangle(processBuffer, new Point(box.x, box.y), new Point((box.x + box.width), (box.y + box.height)), Helpers.colorToScalar(settings.maximumBoxColor), settings.boxOutlineSize);
}
}
}
}
if (settings.showCrosshair) {
Point xMax = new Point(camProps.centerX + 10, camProps.centerY);
Point xMin = new Point(camProps.centerX - 10, camProps.centerY);
Point yMax = new Point(camProps.centerX, camProps.centerY + 10);
Point yMin = new Point(camProps.centerX, camProps.centerY - 10);
if (outputMat != null && outputMat.cols() > 0) {
Imgproc.line(outputMat, xMax, xMin, Helpers.colorToScalar(settings.crosshairColor), 2);
Imgproc.line(outputMat, yMax, yMin, Helpers.colorToScalar(settings.crosshairColor), 2);
if (settings.showCrosshair) {
Point xMax = new Point(camProps.centerX + 10, camProps.centerY);
Point xMin = new Point(camProps.centerX - 10, camProps.centerY);
Point yMax = new Point(camProps.centerX, camProps.centerY + 10);
Point yMin = new Point(camProps.centerX, camProps.centerY - 10);
Imgproc.line(processBuffer, xMax, xMin, Helpers.colorToScalar(settings.crosshairColor), 2);
Imgproc.line(processBuffer, yMax, yMin, Helpers.colorToScalar(settings.crosshairColor), 2);
}
processBuffer.copyTo(outputMat);
processBuffer.release();
} else {
input.getLeft().copyTo(outputMat);
}
long processTime = System.nanoTime() - processStartNanos;
Pair<Mat, Long> output = Pair.of(outputMat, processTime);
outputMat.release();
return output;
return Pair.of(outputMat, processTime);
}
public static class Draw2dContoursSettings {

View File

@@ -30,20 +30,24 @@ public class ErodeDilatePipe implements Pipe<Mat, Mat> {
public Pair<Mat, Long> run(Mat input) {
long processStartNanos = System.nanoTime();
input.copyTo(processBuffer);
if (erode || dilate) {
input.copyTo(processBuffer);
if (erode) {
Imgproc.erode(processBuffer, processBuffer, kernel);
}
if (erode) {
Imgproc.erode(processBuffer, processBuffer, kernel);
}
if (dilate) {
Imgproc.erode(processBuffer, processBuffer, kernel);
if (dilate) {
Imgproc.erode(processBuffer, processBuffer, kernel);
}
processBuffer.copyTo(outputMat);
processBuffer.release();
} else {
input.copyTo(outputMat);
}
long processTime = System.nanoTime() - processStartNanos;
processBuffer.copyTo(outputMat);
Pair<Mat, Long> output = Pair.of(outputMat, processTime);
processBuffer.release();
return output;
return Pair.of(outputMat, processTime);
}
}

View File

@@ -40,30 +40,32 @@ public class FilterContoursPipe implements Pipe<List<MatOfPoint>, List<MatOfPoin
filteredContours.clear();
for (MatOfPoint Contour : input) {
try {
double contourArea = Imgproc.contourArea(Contour);
double AreaRatio = (contourArea / camProps.imageArea) * 100;
double minArea = (MathHandler.sigmoid(area.get(0)));
double maxArea = (MathHandler.sigmoid(area.get(1)));
if (AreaRatio < minArea || AreaRatio > maxArea) {
continue;
if (input.size() > 0) {
for (MatOfPoint Contour : input) {
try {
double contourArea = Imgproc.contourArea(Contour);
double AreaRatio = (contourArea / camProps.imageArea) * 100;
double minArea = (MathHandler.sigmoid(area.get(0)));
double maxArea = (MathHandler.sigmoid(area.get(1)));
if (AreaRatio < minArea || AreaRatio > maxArea) {
continue;
}
var rect = Imgproc.minAreaRect(new MatOfPoint2f(Contour.toArray()));
double minExtent = (extent.get(0).doubleValue() * rect.size.area()) / 100;
double maxExtent = (extent.get(1).doubleValue() * 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.get(0).doubleValue() || aspectRatio > ratio.get(1).doubleValue()) {
continue;
}
filteredContours.add(Contour);
} catch (Exception e) {
System.err.println("Error while filtering contours");
e.printStackTrace();
}
var rect = Imgproc.minAreaRect(new MatOfPoint2f(Contour.toArray()));
double minExtent = (extent.get(0).doubleValue() * rect.size.area()) / 100;
double maxExtent = (extent.get(1).doubleValue() * 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.get(0).doubleValue() || aspectRatio > ratio.get(1).doubleValue()) {
continue;
}
filteredContours.add(Contour);
} catch (Exception e) {
System.err.println("Error while filtering contours");
e.printStackTrace();
}
}

View File

@@ -41,56 +41,59 @@ public class GroupContoursPipe implements Pipe<List<MatOfPoint>, List<RotatedRec
groupedContours.clear();
List<MatOfPoint> sorted = new ArrayList<>(input);
sorted.sort(sortByMomentsX);
if (input.size() > 0) {
Collections.reverse(sorted);
List<MatOfPoint> sorted = new ArrayList<>(input);
sorted.sort(sortByMomentsX);
switch (group) {
case Single: {
input.forEach(c -> {
MatOfPoint2f contour = new MatOfPoint2f();
contour.fromArray(c.toArray());
if (contour.cols() != 0 && contour.rows() != 0) {
RotatedRect rect = Imgproc.minAreaRect(contour);
groupedContours.add(rect);
}
});
break;
}
case Dual: {
for (var i = 0; i < input.size(); i++) {
List<Point> finalContourList = new ArrayList<>(input.get(i).toList());
try {
MatOfPoint firstContour = input.get(i);
MatOfPoint secondContour = input.get(i + 1);
if (isIntersecting(firstContour, secondContour)) {
finalContourList.addAll(secondContour.toList());
} else {
finalContourList.clear();
continue;
}
intersectMatA.release();
intersectMatB.release();
firstContour.release();
secondContour.release();
Collections.reverse(sorted);
switch (group) {
case Single: {
input.forEach(c -> {
MatOfPoint2f contour = new MatOfPoint2f();
contour.fromList(finalContourList);
contour.fromArray(c.toArray());
if (contour.cols() != 0 && contour.rows() != 0) {
RotatedRect rect = Imgproc.minAreaRect(contour);
groupedContours.add(rect);
}
} catch (IndexOutOfBoundsException e) {
System.err.println("GroupContours: WTF");
finalContourList.clear();
}
});
break;
}
case Dual: {
for (var i = 0; i < input.size(); i++) {
List<Point> finalContourList = new ArrayList<>(input.get(i).toList());
try {
MatOfPoint firstContour = input.get(i);
MatOfPoint secondContour = input.get(i + 1);
if (isIntersecting(firstContour, secondContour)) {
finalContourList.addAll(secondContour.toList());
} else {
finalContourList.clear();
continue;
}
intersectMatA.release();
intersectMatB.release();
firstContour.release();
secondContour.release();
MatOfPoint2f contour = new MatOfPoint2f();
contour.fromList(finalContourList);
if (contour.cols() != 0 && contour.rows() != 0) {
RotatedRect rect = Imgproc.minAreaRect(contour);
groupedContours.add(rect);
}
} catch (IndexOutOfBoundsException e) {
System.err.println("GroupContours: WTF");
finalContourList.clear();
}
}
break;
}
break;
}
}

View File

@@ -38,11 +38,11 @@ public class HsvPipe implements Pipe<Mat, Mat> {
System.err.println("(HsvPipe) Exception thrown by OpenCV: \n" + e.getMessage());
}
long processTime = System.nanoTime() - processStartNanos;
processBuffer.copyTo(outputMat);
Pair<Mat, Long> output = Pair.of(outputMat, processTime);
processBuffer.release();
return output;
long processTime = System.nanoTime() - processStartNanos;
return Pair.of(outputMat, processTime);
}
}

View File

@@ -28,15 +28,27 @@ public class RotateFlipPipe implements Pipe<Mat, Mat> {
public Pair<Mat, Long> run(Mat input) {
long processStartNanos = System.nanoTime();
input.copyTo(processBuffer);
boolean shouldFlip = !flip.equals(ImageFlipMode.NONE);
boolean shouldRotate = !rotation.equals(ImageRotation.DEG_0);
Core.flip(processBuffer, processBuffer, flip.value);
Core.rotate(processBuffer, processBuffer, rotation.value);
if (shouldFlip || shouldRotate) {
input.copyTo(processBuffer);
if (shouldFlip) {
Core.flip(processBuffer, processBuffer, flip.value);
}
if (shouldRotate) {
Core.rotate(processBuffer, processBuffer, rotation.value);
}
processBuffer.copyTo(outputMat);
processBuffer.release();
} else {
input.copyTo(outputMat);
}
long processTime = System.nanoTime() - processStartNanos;
processBuffer.copyTo(outputMat);
Pair<Mat, Long> output = Pair.of(outputMat, processTime);
processBuffer.release();
return output;
return Pair.of(outputMat, processTime);
}
}

View File

@@ -44,32 +44,35 @@ public class SortContoursPipe implements Pipe<List<RotatedRect>, List<RotatedRec
long processStartNanos = System.nanoTime();
sortedContours.clear();
sortedContours.addAll(input);
switch (sort) {
case Largest:
sortedContours.sort(SortByLargestComparator);
break;
case Smallest:
sortedContours.sort(SortBySmallestComparator);
break;
case Highest:
sortedContours.sort(SortByHighestComparator);
break;
case Lowest:
sortedContours.sort(SortByLowestComparator);
break;
case Leftmost:
sortedContours.sort(SortByLeftmostComparator);
break;
case Rightmost:
sortedContours.sort(SortByRightmostComparator);
break;
case Centermost:
sortedContours.sort(SortByCentermostComparator);
break;
default:
break;
if (input.size() > 0) {
sortedContours.addAll(input);
switch (sort) {
case Largest:
sortedContours.sort(SortByLargestComparator);
break;
case Smallest:
sortedContours.sort(SortBySmallestComparator);
break;
case Highest:
sortedContours.sort(SortByHighestComparator);
break;
case Lowest:
sortedContours.sort(SortByLowestComparator);
break;
case Leftmost:
sortedContours.sort(SortByLeftmostComparator);
break;
case Rightmost:
sortedContours.sort(SortByRightmostComparator);
break;
case Centermost:
sortedContours.sort(SortByCentermostComparator);
break;
default:
break;
}
}
long processTime = System.nanoTime() - processStartNanos;

View File

@@ -27,19 +27,21 @@ public class SpeckleRejectPipe implements Pipe<List<MatOfPoint>, List<MatOfPoint
despeckledContours.clear();
double averageArea = 0.0;
if (input.size() > 0) {
double averageArea = 0.0;
for (MatOfPoint c : input) {
averageArea += Imgproc.contourArea(c);
}
for (MatOfPoint c : input) {
averageArea += Imgproc.contourArea(c);
}
averageArea /= input.size();
averageArea /= input.size();
double minAllowedArea = minPercentOfAvg / 100.0 * averageArea;
double minAllowedArea = minPercentOfAvg / 100.0 * averageArea;
for (MatOfPoint c : input) {
if (Imgproc.contourArea(c) >= minAllowedArea) {
despeckledContours.add(c);
for (MatOfPoint c : input) {
if (Imgproc.contourArea(c) >= minAllowedArea) {
despeckledContours.add(c);
}
}
}

View File

@@ -20,7 +20,6 @@ public class Server {
ws.onClose(ctx -> {
handler.onClose(ctx);
System.out.println("Socket Disconnected");
// TODO: (HIGH) add generalSettingsSave
ConfigManager.saveSettings();
});
ws.onBinaryMessage(ctx -> {