+
rollback('hue',e)"
/>
rollback('saturation',e)"
/>
rollback('value',e)"
/>
+ rollback('hueInverted',e)"
+ />
+
+
diff --git a/photon-core/src/main/java/org/photonvision/raspi/PicamJNI.java b/photon-core/src/main/java/org/photonvision/raspi/PicamJNI.java
index 0761978f9..bc0641dc8 100644
--- a/photon-core/src/main/java/org/photonvision/raspi/PicamJNI.java
+++ b/photon-core/src/main/java/org/photonvision/raspi/PicamJNI.java
@@ -86,7 +86,7 @@ public class PicamJNI {
public static boolean isSupported() {
return libraryLoaded
- && !isVCSMSupported()
+ && isVCSMSupported()
&& getSensorModel() != SensorModel.Disconnected
&& Platform.isRaspberryPi()
&& (Platform.currentPiVersion == PiVersion.PI_3
@@ -134,6 +134,8 @@ public class PicamJNI {
public static native void setThresholds(
double hL, double sL, double vL, double hU, double sU, double vU);
+ public static native void setInvertHue(boolean shouldInvert);
+
public static native boolean setExposure(int exposure);
public static native boolean setBrightness(int brightness);
diff --git a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java
index 3c10a8e1a..162c975d1 100644
--- a/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java
+++ b/photon-core/src/main/java/org/photonvision/vision/pipe/impl/HSVPipe.java
@@ -28,19 +28,56 @@ public class HSVPipe extends CVPipe {
@Override
protected Mat process(Mat in) {
var outputMat = new Mat();
- in.copyTo(outputMat);
- Imgproc.cvtColor(outputMat, outputMat, Imgproc.COLOR_BGR2HSV, 3);
- Core.inRange(outputMat, params.getHsvLower(), params.getHsvUpper(), outputMat);
+ // We can save a copy here by sending the output of cvtcolor to outputMat directly
+ // rather than copying. Free performance!
+ Imgproc.cvtColor(in, outputMat, Imgproc.COLOR_BGR2HSV, 3);
+
+ if (params.getHueInverted()) {
+ // In Java code we do this by taking an image thresholded
+ // from [0, minHue] and ORing it with [maxHue, 180]
+
+ // we want hue from the end of the slider to max hue
+ Scalar firstLower = params.getHsvLower().clone();
+ Scalar firstUpper = params.getHsvUpper().clone();
+ firstLower.val[0] = params.getHsvUpper().val[0];
+ ;
+ firstUpper.val[0] = 180;
+
+ var lowerThresholdMat = new Mat();
+ Core.inRange(outputMat, firstLower, firstUpper, lowerThresholdMat);
+
+ // We want hue from 0 to the start of the slider
+ var secondLower = params.getHsvLower().clone();
+ var secondUpper = params.getHsvUpper().clone();
+ secondLower.val[0] = 0;
+ secondUpper.val[0] = params.getHsvLower().val[0];
+
+ // Now that the output mat's been used by the first inRange, it's fine to mutate it
+ Core.inRange(outputMat, secondLower, secondUpper, outputMat);
+
+ // Now OR the two images together to make a mat that combines the lower and upper bounds
+ // outputMat holds the second half of the range
+ Core.bitwise_or(lowerThresholdMat, outputMat, outputMat);
+
+ lowerThresholdMat.release();
+ } else {
+ Core.inRange(outputMat, params.getHsvLower(), params.getHsvUpper(), outputMat);
+ }
+
return outputMat;
}
public static class HSVParams {
private final Scalar m_hsvLower;
private final Scalar m_hsvUpper;
+ private final boolean m_hueInverted;
- public HSVParams(IntegerCouple hue, IntegerCouple saturation, IntegerCouple value) {
+ public HSVParams(
+ IntegerCouple hue, IntegerCouple saturation, IntegerCouple value, boolean hueInverted) {
m_hsvLower = new Scalar(hue.getFirst(), saturation.getFirst(), value.getFirst());
m_hsvUpper = new Scalar(hue.getSecond(), saturation.getSecond(), value.getSecond());
+
+ this.m_hueInverted = hueInverted;
}
public Scalar getHsvLower() {
@@ -50,5 +87,9 @@ public class HSVPipe extends CVPipe {
public Scalar getHsvUpper() {
return m_hsvUpper;
}
+
+ public boolean getHueInverted() {
+ return m_hueInverted;
+ }
}
}
diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/AdvancedPipelineSettings.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/AdvancedPipelineSettings.java
index 7e8a3bbb0..411642c89 100644
--- a/photon-core/src/main/java/org/photonvision/vision/pipeline/AdvancedPipelineSettings.java
+++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/AdvancedPipelineSettings.java
@@ -38,6 +38,7 @@ public class AdvancedPipelineSettings extends CVPipelineSettings {
public IntegerCouple hsvHue = new IntegerCouple(50, 180);
public IntegerCouple hsvSaturation = new IntegerCouple(50, 255);
public IntegerCouple hsvValue = new IntegerCouple(50, 255);
+ public boolean hueInverted = false;
public boolean outputShouldDraw = true;
public boolean outputShowMultipleTargets = false;
@@ -109,6 +110,7 @@ public class AdvancedPipelineSettings extends CVPipelineSettings {
&& Objects.equals(hsvHue, that.hsvHue)
&& Objects.equals(hsvSaturation, that.hsvSaturation)
&& Objects.equals(hsvValue, that.hsvValue)
+ && Objects.equals(hueInverted, that.hueInverted)
&& Objects.equals(contourArea, that.contourArea)
&& Objects.equals(contourRatio, that.contourRatio)
&& Objects.equals(contourFullness, that.contourFullness)
@@ -132,6 +134,7 @@ public class AdvancedPipelineSettings extends CVPipelineSettings {
hsvHue,
hsvSaturation,
hsvValue,
+ hueInverted,
outputShouldDraw,
outputShowMultipleTargets,
contourArea,
diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java
index 1851600b1..734d56595 100644
--- a/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java
+++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/ColoredShapePipeline.java
@@ -85,12 +85,14 @@ public class ColoredShapePipeline
settings.hsvHue.getSecond() / 180d,
settings.hsvSaturation.getSecond() / 255d,
settings.hsvValue.getSecond() / 255d);
+ PicamJNI.setInvertHue(settings.hueInverted);
PicamJNI.setRotation(settings.inputImageRotationMode.value);
PicamJNI.setShouldCopyColor(settings.inputShouldShow);
} else {
var hsvParams =
- new HSVPipe.HSVParams(settings.hsvHue, settings.hsvSaturation, settings.hsvValue);
+ new HSVPipe.HSVParams(
+ settings.hsvHue, settings.hsvSaturation, settings.hsvValue, settings.hueInverted);
hsvPipe.setParams(hsvParams);
}
@@ -99,10 +101,6 @@ public class ColoredShapePipeline
// TODO: add kernel size to pipeline settings
erodeDilatePipe.setParams(erodeDilateParams);
- HSVPipe.HSVParams hsvParams =
- new HSVPipe.HSVParams(settings.hsvHue, settings.hsvSaturation, settings.hsvValue);
- hsvPipe.setParams(hsvParams);
-
SpeckleRejectPipe.SpeckleRejectParams speckleRejectParams =
new SpeckleRejectPipe.SpeckleRejectParams(settings.contourSpecklePercentage);
speckleRejectPipe.setParams(speckleRejectParams);
diff --git a/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java b/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java
index 572798273..13c375a7d 100644
--- a/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java
+++ b/photon-core/src/main/java/org/photonvision/vision/pipeline/ReflectivePipeline.java
@@ -77,12 +77,14 @@ public class ReflectivePipeline extends CVPipeline