Add saturation max slider to UI and image processing logic
This commit is contained in:
parent
daf226a80f
commit
ff9dec0eff
|
|
@ -39,6 +39,7 @@
|
||||||
"sliders.hue_min" = "Hue Min (°)"
|
"sliders.hue_min" = "Hue Min (°)"
|
||||||
"sliders.hue_max" = "Hue Max (°)"
|
"sliders.hue_max" = "Hue Max (°)"
|
||||||
"sliders.sat_min" = "Sättigung Min (%)"
|
"sliders.sat_min" = "Sättigung Min (%)"
|
||||||
|
"sliders.sat_max" = "Sättigung Max (%)"
|
||||||
"sliders.val_min" = "Helligkeit Min (%)"
|
"sliders.val_min" = "Helligkeit Min (%)"
|
||||||
"sliders.val_max" = "Helligkeit Max (%)"
|
"sliders.val_max" = "Helligkeit Max (%)"
|
||||||
"sliders.alpha" = "Overlay Alpha"
|
"sliders.alpha" = "Overlay Alpha"
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
"sliders.hue_min" = "Hue min (°)"
|
"sliders.hue_min" = "Hue min (°)"
|
||||||
"sliders.hue_max" = "Hue max (°)"
|
"sliders.hue_max" = "Hue max (°)"
|
||||||
"sliders.sat_min" = "Saturation min (%)"
|
"sliders.sat_min" = "Saturation min (%)"
|
||||||
|
"sliders.sat_max" = "Saturation max (%)"
|
||||||
"sliders.val_min" = "Value min (%)"
|
"sliders.val_min" = "Value min (%)"
|
||||||
"sliders.val_max" = "Value max (%)"
|
"sliders.val_max" = "Value max (%)"
|
||||||
"sliders.alpha" = "Overlay alpha"
|
"sliders.alpha" = "Overlay alpha"
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ class QtImageProcessor:
|
||||||
"hue_min": 0,
|
"hue_min": 0,
|
||||||
"hue_max": 360,
|
"hue_max": 360,
|
||||||
"sat_min": 25,
|
"sat_min": 25,
|
||||||
|
"sat_max": 100,
|
||||||
"val_min": 15,
|
"val_min": 15,
|
||||||
"val_max": 100,
|
"val_max": 100,
|
||||||
"alpha": 120,
|
"alpha": 120,
|
||||||
|
|
@ -113,6 +114,7 @@ class QtImageProcessor:
|
||||||
self.hue_min = self.defaults["hue_min"]
|
self.hue_min = self.defaults["hue_min"]
|
||||||
self.hue_max = self.defaults["hue_max"]
|
self.hue_max = self.defaults["hue_max"]
|
||||||
self.sat_min = self.defaults["sat_min"]
|
self.sat_min = self.defaults["sat_min"]
|
||||||
|
self.sat_max = self.defaults["sat_max"]
|
||||||
self.val_min = self.defaults["val_min"]
|
self.val_min = self.defaults["val_min"]
|
||||||
self.val_max = self.defaults["val_max"]
|
self.val_max = self.defaults["val_max"]
|
||||||
self.alpha = self.defaults["alpha"]
|
self.alpha = self.defaults["alpha"]
|
||||||
|
|
@ -219,6 +221,7 @@ class QtImageProcessor:
|
||||||
match_mask = (
|
match_mask = (
|
||||||
hue_ok
|
hue_ok
|
||||||
& (sat >= float(self.sat_min))
|
& (sat >= float(self.sat_min))
|
||||||
|
& (sat <= float(self.sat_max))
|
||||||
& (val >= float(self.val_min))
|
& (val >= float(self.val_min))
|
||||||
& (val <= float(self.val_max))
|
& (val <= float(self.val_max))
|
||||||
& (alpha_ch > 0)
|
& (alpha_ch > 0)
|
||||||
|
|
@ -285,6 +288,7 @@ class QtImageProcessor:
|
||||||
match_mask = (
|
match_mask = (
|
||||||
hue_ok
|
hue_ok
|
||||||
& (sat >= float(self.sat_min))
|
& (sat >= float(self.sat_min))
|
||||||
|
& (sat <= float(self.sat_max))
|
||||||
& (val >= float(self.val_min))
|
& (val >= float(self.val_min))
|
||||||
& (val <= float(self.val_max))
|
& (val <= float(self.val_max))
|
||||||
& (alpha_ch > 0)
|
& (alpha_ch > 0)
|
||||||
|
|
@ -321,7 +325,7 @@ class QtImageProcessor:
|
||||||
hue_ok = self.hue_min <= hue <= self.hue_max
|
hue_ok = self.hue_min <= hue <= self.hue_max
|
||||||
else:
|
else:
|
||||||
hue_ok = hue >= self.hue_min or hue <= self.hue_max
|
hue_ok = hue >= self.hue_min or hue <= self.hue_max
|
||||||
sat_ok = s * 100.0 >= self.sat_min
|
sat_ok = self.sat_min <= s * 100.0 <= self.sat_max
|
||||||
val_ok = self.val_min <= v * 100.0 <= self.val_max
|
val_ok = self.val_min <= v * 100.0 <= self.val_max
|
||||||
return hue_ok and sat_ok and val_ok
|
return hue_ok and sat_ok and val_ok
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ SLIDER_SPECS: List[Tuple[str, str, int, int]] = [
|
||||||
("sliders.hue_min", "hue_min", 0, 360),
|
("sliders.hue_min", "hue_min", 0, 360),
|
||||||
("sliders.hue_max", "hue_max", 0, 360),
|
("sliders.hue_max", "hue_max", 0, 360),
|
||||||
("sliders.sat_min", "sat_min", 0, 100),
|
("sliders.sat_min", "sat_min", 0, 100),
|
||||||
|
("sliders.sat_max", "sat_max", 0, 100),
|
||||||
("sliders.val_min", "val_min", 0, 100),
|
("sliders.val_min", "val_min", 0, 100),
|
||||||
("sliders.val_max", "val_max", 0, 100),
|
("sliders.val_max", "val_max", 0, 100),
|
||||||
("sliders.alpha", "alpha", 0, 255),
|
("sliders.alpha", "alpha", 0, 255),
|
||||||
|
|
@ -917,6 +918,7 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin):
|
||||||
"hue_min": self.processor.hue_min,
|
"hue_min": self.processor.hue_min,
|
||||||
"hue_max": self.processor.hue_max,
|
"hue_max": self.processor.hue_max,
|
||||||
"sat_min": self.processor.sat_min,
|
"sat_min": self.processor.sat_min,
|
||||||
|
"sat_max": self.processor.sat_max,
|
||||||
"val_min": self.processor.val_min,
|
"val_min": self.processor.val_min,
|
||||||
"val_max": self.processor.val_max,
|
"val_max": self.processor.val_max,
|
||||||
"alpha": self.processor.alpha,
|
"alpha": self.processor.alpha,
|
||||||
|
|
@ -954,10 +956,12 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin):
|
||||||
self._update_color_display(self._current_color, self._t("palette.current"))
|
self._update_color_display(self._current_color, self._t("palette.current"))
|
||||||
|
|
||||||
# 2. Apply slider values
|
# 2. Apply slider values
|
||||||
keys = ["hue_min", "hue_max", "sat_min", "val_min", "val_max", "alpha"]
|
keys = ["hue_min", "hue_max", "sat_min", "sat_max", "val_min", "val_max", "alpha"]
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if key in settings:
|
if key in settings:
|
||||||
setattr(self.processor, key, settings[key])
|
setattr(self.processor, key, settings[key])
|
||||||
|
else:
|
||||||
|
setattr(self.processor, key, self.processor.defaults.get(key, 0))
|
||||||
|
|
||||||
# 3. Apply shapes and reference size
|
# 3. Apply shapes and reference size
|
||||||
ref_size = None
|
ref_size = None
|
||||||
|
|
@ -1177,13 +1181,15 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin):
|
||||||
margin = 15
|
margin = 15
|
||||||
hue_min = max(0, int(hue) - margin)
|
hue_min = max(0, int(hue) - margin)
|
||||||
hue_max = min(360, int(hue) + margin)
|
hue_max = min(360, int(hue) + margin)
|
||||||
|
# For a picked color, give a window of ±20% for saturation and -30% for value
|
||||||
sat_min = max(0, int(sat) - 20)
|
sat_min = max(0, int(sat) - 20)
|
||||||
|
sat_max = min(100, int(sat) + 20)
|
||||||
val_min = max(0, int(val) - 30)
|
val_min = max(0, int(val) - 30)
|
||||||
val_max = 100
|
val_max = 100
|
||||||
|
|
||||||
for attr, value in [
|
for attr, value in [
|
||||||
("hue_min", hue_min), ("hue_max", hue_max),
|
("hue_min", hue_min), ("hue_max", hue_max),
|
||||||
("sat_min", sat_min), ("val_min", val_min), ("val_max", val_max),
|
("sat_min", sat_min), ("sat_max", sat_max), ("val_min", val_min), ("val_max", val_max),
|
||||||
]:
|
]:
|
||||||
ctrl = self._slider_controls.get(attr)
|
ctrl = self._slider_controls.get(attr)
|
||||||
if ctrl:
|
if ctrl:
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ overlay_color = "#ff0000"
|
||||||
hue_min = 250.0
|
hue_min = 250.0
|
||||||
hue_max = 310.0
|
hue_max = 310.0
|
||||||
sat_min = 15.0
|
sat_min = 15.0
|
||||||
|
sat_max = 100.0
|
||||||
val_min = 15.0
|
val_min = 15.0
|
||||||
val_max = 100.0
|
val_max = 100.0
|
||||||
alpha = 120
|
alpha = 120
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,18 @@ def test_stats_summary():
|
||||||
matches_excl=10, total_excl=20
|
matches_excl=10, total_excl=20
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mock translator
|
|
||||||
def mock_t(key, **kwargs):
|
def mock_t(key, **kwargs):
|
||||||
if key == "stats.placeholder":
|
if key == "stats.placeholder":
|
||||||
return "Placeholder"
|
return "Placeholder"
|
||||||
return f"{kwargs['with_pct']:.1f} {kwargs['without_pct']:.1f} {kwargs['excluded_pct']:.1f} {kwargs['excluded_match_pct']:.1f}"
|
if not kwargs:
|
||||||
|
return key
|
||||||
|
return f"{kwargs['with_pct']:.1f} {kwargs['without_pct']:.1f} {kwargs['excluded_pct']:.1f}"
|
||||||
|
|
||||||
res = s.summary(mock_t)
|
res = s.summary(mock_t)
|
||||||
# with_pct: 40/80 = 50.0
|
# with_pct: 40/80 = 50.0
|
||||||
# without_pct: 50/100 = 50.0
|
# without_pct: 50/100 = 50.0
|
||||||
# excluded_pct: 20/100 = 20.0
|
# excluded_pct: 20/100 = 20.0
|
||||||
# excluded_match_pct: 10/20 = 50.0
|
assert res == "50.0 50.0 20.0"
|
||||||
assert res == "50.0 50.0 20.0 50.0"
|
|
||||||
|
|
||||||
def test_stats_empty():
|
def test_stats_empty():
|
||||||
s = Stats()
|
s = Stats()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue