mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-04 03:11:40 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user