summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2020-06-08 13:35:59 +0200
committerPaweł Redman <pawel.redman@gmail.com>2020-06-08 13:35:59 +0200
commit94d93f044446af5d53620a0f2a6ac76a2bd36386 (patch)
tree39d624337720b4da1a62a2c1aff07d27199dea9d
parent41dc1a7e756ff992ad58d67a4d92c6c1e418b450 (diff)
Factor out the colorchecker test code
-rw-r--r--jakob_hanika.py56
-rw-r--r--test_colorchecker.py37
2 files changed, 48 insertions, 45 deletions
diff --git a/jakob_hanika.py b/jakob_hanika.py
index 78803a1..3b35670 100644
--- a/jakob_hanika.py
+++ b/jakob_hanika.py
@@ -1,37 +1,9 @@
import numpy as np, scipy.optimize as optimize
from colour import *
from colour.difference import *
-from colour.plotting import *
-from matplotlib import pyplot as plt
-
-
-
-# Makes a comparison plot with SDs and swatches
-def plot_comparison(target_sd, matched_sd, label, error):
- target_XYZ = sd_to_XYZ(target_sd)
- target_RGB = np.clip(XYZ_to_sRGB(target_XYZ / 100), 0, 1)
- target_swatch = ColourSwatch(label, target_RGB)
- matched_XYZ = sd_to_XYZ(matched_sd)
- matched_RGB = np.clip(XYZ_to_sRGB(matched_XYZ / 100), 0, 1)
- matched_swatch = ColourSwatch("Model", matched_RGB)
-
- axes = plt.subplot(2, 1, 1)
- plt.title(label)
- plot_multi_sds([target_sd, matched_sd], axes=axes, standalone=False)
-
- axes = plt.subplot(2, 1, 2)
- plt.title("ΔE = %g" % error)
- plot_multi_colour_swatches([target_swatch, matched_swatch], axes=axes)
-
-
-
-# The same illuminant is used throughout
-il = ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']
# The same wavelength grid is used throughout
-wvl = np.arange(360, 830, 10)
-
-
+wvl = np.arange(360, 830, 5)
# This is the model of spectral reflectivity described in the article.
def model(wvl, cc):
@@ -45,10 +17,10 @@ def model(wvl, cc):
# The goal is to minimize the color difference between a given distrbution
# and the one computed from the model above.
-def error_function(cc, target):
+def error_function(cc, target, illuminant):
ev = model(wvl, cc)
sd = SpectralDistribution(ev, wvl)
- Lab = XYZ_to_Lab(sd_to_XYZ(sd), il)
+ Lab = XYZ_to_Lab(sd_to_XYZ(sd), illuminant)
return delta_E_CIE1976(target, Lab)
@@ -59,26 +31,20 @@ def error_function(cc, target):
def cb_basinhopping(x, f, accept):
return f < 0.1
-# This demo goes through SDs in a color checker
-for name, sd in COLOURCHECKERS_SDS['ColorChecker N Ohta'].items():
- XYZ = sd_to_XYZ(sd)
- target = XYZ_to_Lab(XYZ, il)
-
- print("The target is '%s' with L=%g, a=%g, b=%g" % (name, *target))
-
+# Finds coefficients for Jakob and Hanika's function
+def jakob_hanika(target, illuminant):
# First, a conventional solver is called. For 'yellow green' this
# actually fails: gets stuck at a local minimum that's far away
# from the global one.
# FIXME: better parameters, a better x0, a better method?
- # FIXME: stop iterating as soon as delta E is negligible (instead of
- # going).
+ # FIXME: stop iterating as soon as delta E is negligible
opt = optimize.minimize(
- error_function, (0, 0, 0), target, method="L-BFGS-B",
- options={"disp": True, "ftol": 1e-5}
+ error_function, (0, 0, 0), (target, illuminant),
+ method="L-BFGS-B", options={"disp": True, "ftol": 1e-5}
)
print(opt)
- error = error_function(opt.x, target)
+ error = error_function(opt.x, target, illuminant)
print("Delta E is %g" % error)
# Basin hopping is far more likely to find the actual minimum we're
@@ -86,7 +52,7 @@ for name, sd in COLOURCHECKERS_SDS['ColorChecker N Ohta'].items():
if error > 0.1:
print("Error too large, trying global optimization")
opt = optimize.basinhopping(
- lambda cc: error_function(cc, target),
+ lambda cc: error_function(cc, target, illuminant),
(0, 0, 0), disp=True, callback=cb_basinhopping
)
print(opt)
@@ -94,4 +60,4 @@ for name, sd in COLOURCHECKERS_SDS['ColorChecker N Ohta'].items():
print("Global delta E is %g" % error)
matched_sd = SpectralDistribution(model(wvl, opt.x), wvl, name="Model")
- plot_comparison(sd, matched_sd, name, error)
+ return opt.x, matched_sd, error
diff --git a/test_colorchecker.py b/test_colorchecker.py
new file mode 100644
index 0000000..907322b
--- /dev/null
+++ b/test_colorchecker.py
@@ -0,0 +1,37 @@
+import numpy as np
+from colour import *
+from colour.plotting import *
+from matplotlib import pyplot as plt
+from jakob_hanika import jakob_hanika
+
+D65 = ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']
+
+# Makes a comparison plot with SDs and swatches
+def plot_comparison(target_sd, matched_sd, label, error):
+ target_XYZ = sd_to_XYZ(target_sd)
+ target_RGB = np.clip(XYZ_to_sRGB(target_XYZ / 100), 0, 1)
+ target_swatch = ColourSwatch(label, target_RGB)
+ matched_XYZ = sd_to_XYZ(matched_sd)
+ matched_RGB = np.clip(XYZ_to_sRGB(matched_XYZ / 100), 0, 1)
+ matched_swatch = ColourSwatch("Model", matched_RGB)
+
+ axes = plt.subplot(2, 1, 1)
+ plt.title(label)
+ plot_multi_sds([target_sd, matched_sd], axes=axes, standalone=False)
+
+ axes = plt.subplot(2, 1, 2)
+ plt.title("ΔE = %g" % error)
+ plot_multi_colour_swatches([target_swatch, matched_swatch], axes=axes)
+
+
+
+if __name__ == "__main__":
+ # This demo goes through SDs in a color checker
+ for name, sd in COLOURCHECKERS_SDS['ColorChecker N Ohta'].items():
+ XYZ = sd_to_XYZ(sd)
+ target = XYZ_to_Lab(XYZ, D65)
+
+ print("The target is '%s' with L=%g, a=%g, b=%g" % (name, *target))
+ _, matched_sd, error = jakob_hanika(target, D65)
+
+ plot_comparison(sd, matched_sd, name, error)