Invertable hue (#428)

* Add UI-side changes for invertable hue slider

* Add hue inverted range

* Add new slider backgrounds to threshold tab

* Run spotless

* Updated libpicam.so to artifact built from commit c458bab87740 in that repo on gerth2's pi.

* undo the java-side hack since isVCSMSupported is fixed

* Hook up hue inversion frontend to backend and UI tweaks

* Remove unused .flipped class

* Fix hueInverted name in Vue.js store

Co-authored-by: Declan Freeman-Gleason <declanfreemangleason@gmail.com>
Co-authored-by: Matt <matthew.morley.ca@gmail.com>
Co-authored-by: Chris Gerth <chrisgerth010592@gmail.com>
This commit is contained in:
Banks T
2022-02-21 22:41:51 -05:00
committed by GitHub
parent d779fe23f0
commit 5144819ce2
11 changed files with 133 additions and 23 deletions

View File

@@ -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);

View File

@@ -28,19 +28,56 @@ public class HSVPipe extends CVPipe<Mat, Mat, HSVPipe.HSVParams> {
@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<Mat, Mat, HSVPipe.HSVParams> {
public Scalar getHsvUpper() {
return m_hsvUpper;
}
public boolean getHueInverted() {
return m_hueInverted;
}
}
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -77,12 +77,14 @@ public class ReflectivePipeline extends CVPipeline<CVPipelineResult, ReflectiveP
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);
}