diff options
author | Richard Hughes <richard@hughsie.com> | 2015-10-16 11:57:17 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2015-10-16 11:59:34 +0100 |
commit | 6c3a8185bb09d5cab4a1821be43c26a5a42cffe5 (patch) | |
tree | c133a6ced6c25fab43c9432622d3b5fb2a07a796 | |
parent | ea20f28db7b672793012b398a219d907b3da02d9 (diff) | |
download | colord-6c3a8185bb09d5cab4a1821be43c26a5a42cffe5.tar.gz |
libcolord: Add cd_spectrum_set_wavelength_cal()
This allows us to have a non-linear relationship between pixel index and
wavelength value.
-rw-r--r-- | lib/colord/cd-spectrum.c | 101 | ||||
-rw-r--r-- | lib/colord/cd-spectrum.h | 8 | ||||
-rw-r--r-- | lib/colord/cd-test-private.c | 45 |
3 files changed, 143 insertions, 11 deletions
diff --git a/lib/colord/cd-spectrum.c b/lib/colord/cd-spectrum.c index 29e7dc2..52c07fa 100644 --- a/lib/colord/cd-spectrum.c +++ b/lib/colord/cd-spectrum.c @@ -42,6 +42,7 @@ struct _CdSpectrum { gdouble start; gdouble end; gdouble norm; + gdouble wavelength_cal[3]; GArray *data; }; @@ -69,6 +70,8 @@ cd_spectrum_dup (const CdSpectrum *spectrum) tmp = cd_spectrum_get_value_raw (spectrum, i); cd_spectrum_add_value (dest, tmp); } + for (i = 0; i < 3; i++) + dest->wavelength_cal[i] = spectrum->wavelength_cal[i]; return dest; } @@ -196,20 +199,27 @@ cd_spectrum_get_value_raw (const CdSpectrum *spectrum, guint idx) gdouble cd_spectrum_get_wavelength (const CdSpectrum *spectrum, guint idx) { - gdouble step; - guint number_points; - g_return_val_if_fail (spectrum != NULL, -1.0f); - /* if we used cd_spectrum_size_new() and there is no data we can infer - * the wavelenth based on the declared initial size */ - if (spectrum->reserved_size > 0) - number_points = spectrum->reserved_size; - else - number_points = spectrum->data->len; + /* fall back to the old method */ + if (spectrum->wavelength_cal[0] < 0) { + gdouble step; + guint number_points; + /* if we used cd_spectrum_size_new() and there is no data we can infer + * the wavelenth based on the declared initial size */ + if (spectrum->reserved_size > 0) + number_points = spectrum->reserved_size; + else + number_points = spectrum->data->len; + step = (spectrum->end - spectrum->start) / (number_points - 1); + return spectrum->start + (step * (gdouble) idx); + } - step = (spectrum->end - spectrum->start) / (number_points - 1); - return spectrum->start + (step * (gdouble) idx); + /* use wavelength_cal to work out wavelength */ + return spectrum->start + + spectrum->wavelength_cal[0] * (gdouble) idx + + spectrum->wavelength_cal[1] * pow (idx, 2) + + spectrum->wavelength_cal[2] * pow (idx, 3); } /** @@ -352,6 +362,7 @@ cd_spectrum_new (void) spectrum = g_slice_new0 (CdSpectrum); spectrum->norm = 1.f; spectrum->data = g_array_new (FALSE, FALSE, sizeof (gdouble)); + spectrum->wavelength_cal[0] = -1.f; return spectrum; } @@ -373,6 +384,7 @@ cd_spectrum_sized_new (guint reserved_size) spectrum->norm = 1.f; spectrum->reserved_size = reserved_size; spectrum->data = g_array_sized_new (FALSE, FALSE, sizeof (gdouble), reserved_size); + spectrum->wavelength_cal[0] = -1.f; return spectrum; } @@ -510,12 +522,25 @@ cd_spectrum_set_start (CdSpectrum *spectrum, gdouble start) * * Set the end value of the spectal data in nm. * + * If there is already spectral data, the wavelength calibration will + * also be set automatically. + * * Since: 1.1.6 **/ void cd_spectrum_set_end (CdSpectrum *spectrum, gdouble end) { g_return_if_fail (spectrum != NULL); + + /* calculate the calibration co-efficients */ + if (spectrum->data->len > 1) { + spectrum->wavelength_cal[0] = (end - spectrum->start) / + (spectrum->data->len - 1); + spectrum->wavelength_cal[1] = 0.f; + spectrum->wavelength_cal[2] = 0.f; + } + + /* set this for later */ spectrum->end = end; } @@ -723,6 +748,8 @@ cd_spectrum_subtract (CdSpectrum *s1, CdSpectrum *s2) s->id = g_strdup_printf ("%s-%s", s1->id, s2->id); s->start = s1->start; s->end = s1->end; + for (i = 0; i < 3; i++) + s->wavelength_cal[i] = s1->wavelength_cal[i]; for (i = 0; i < s1->data->len; i++) { gdouble tmp; tmp = cd_spectrum_get_value (s1, i) - cd_spectrum_get_value (s2, i); @@ -796,3 +823,55 @@ cd_spectrum_to_string (CdSpectrum *spectrum, guint max_width, guint max_height) /* success */ return g_string_free (str, FALSE); } + +/** + * cd_spectrum_set_wavelength_cal: + * @spectrum: a #CdSpectrum instance + * @c1: the 1st coefficient + * @c2: the 2nd coefficient + * @c3: the 3rd coefficient + * + * Sets the calibration coefficients used to map pixel indexes to + * wavelengths. + * + * This function will set the 'end' wavelength automatically, + * potentially overwriting the value set by cd_spectrum_set_end(). + * + * Since: 1.3.1 + **/ +void +cd_spectrum_set_wavelength_cal (CdSpectrum *spectrum, + gdouble c1, gdouble c2, gdouble c3) +{ + spectrum->wavelength_cal[0] = c1; + spectrum->wavelength_cal[1] = c2; + spectrum->wavelength_cal[2] = c3; + + /* recalculate the end wavelength */ + spectrum->end = cd_spectrum_get_wavelength (spectrum, + cd_spectrum_get_size (spectrum) - 1); +} + +/** + * cd_spectrum_get_wavelength_cal: + * @spectrum: a #CdSpectrum instance + * @c1: the 1st coefficient + * @c2: the 2nd coefficient + * @c3: the 3rd coefficient + * + * Gets the calibration coefficients used to map pixel indexes to + * wavelengths. + * + * Since: 1.3.1 + **/ +void +cd_spectrum_get_wavelength_cal (CdSpectrum *spectrum, + gdouble *c1, gdouble *c2, gdouble *c3) +{ + if (c1 != NULL) + *c1 = spectrum->wavelength_cal[0]; + if (c2 != NULL) + *c2 = spectrum->wavelength_cal[1]; + if (c3 != NULL) + *c3 = spectrum->wavelength_cal[2]; +} diff --git a/lib/colord/cd-spectrum.h b/lib/colord/cd-spectrum.h index ac6755a..816fc77 100644 --- a/lib/colord/cd-spectrum.h +++ b/lib/colord/cd-spectrum.h @@ -88,6 +88,14 @@ void cd_spectrum_set_value (CdSpectrum *spectrum, gdouble data); void cd_spectrum_add_value (CdSpectrum *spectrum, gdouble data); +void cd_spectrum_set_wavelength_cal (CdSpectrum *spectrum, + gdouble c1, + gdouble c2, + gdouble c3); +void cd_spectrum_get_wavelength_cal (CdSpectrum *spectrum, + gdouble *c1, + gdouble *c2, + gdouble *c3); CdSpectrum *cd_spectrum_multiply (CdSpectrum *s1, CdSpectrum *s2, gdouble resolution); diff --git a/lib/colord/cd-test-private.c b/lib/colord/cd-test-private.c index 617c9d6..efc4ffa 100644 --- a/lib/colord/cd-test-private.c +++ b/lib/colord/cd-test-private.c @@ -303,6 +303,50 @@ colord_spectrum_func (void) } static void +colord_spect_cx_func (void) +{ + gdouble tmp; + g_autoptr(CdSpectrum) sp = NULL; + + /* create test spectrum */ + sp = cd_spectrum_new (); + cd_spectrum_set_start (sp, 100); + cd_spectrum_set_end (sp, 200); + g_assert_cmpfloat (fabs (cd_spectrum_get_end (sp) - 200.f), <, 0.001); + + /* we don't calculate the coefficients with no data */ + cd_spectrum_get_wavelength_cal (sp, &tmp, NULL, NULL); + g_assert_cmpfloat (fabs (tmp - -1.f), <, 0.001); + + /* try again, this time with data added first */ + cd_spectrum_add_value (sp, 1.f); + cd_spectrum_add_value (sp, 2.f); + cd_spectrum_add_value (sp, 3.f); + cd_spectrum_set_end (sp, 200); + cd_spectrum_get_wavelength_cal (sp, &tmp, NULL, NULL); + g_assert_cmpfloat (fabs (tmp - 50.f), <, 0.001); + + /* test with linear polynomials */ + g_assert_cmpfloat (fabs (cd_spectrum_get_end (sp) - 200.f), <, 0.001); + tmp = cd_spectrum_get_wavelength (sp, 0); + g_assert_cmpfloat (fabs (tmp - 100), <, 0.001); + tmp = cd_spectrum_get_wavelength (sp, 1); + g_assert_cmpfloat (fabs (tmp - 150), <, 0.001); + tmp = cd_spectrum_get_wavelength (sp, 2); + g_assert_cmpfloat (fabs (tmp - 200), <, 0.001); + + /* test with 3rd order polynomials */ + cd_spectrum_set_wavelength_cal (sp, 100.1f, 1.1f, 0.1f); + g_assert_cmpfloat (fabs (cd_spectrum_get_end (sp) - 305.3999f), <, 0.01); + tmp = cd_spectrum_get_wavelength (sp, 0); + g_assert_cmpfloat (fabs (tmp - 100), <, 0.001); + tmp = cd_spectrum_get_wavelength (sp, 1); + g_assert_cmpfloat (fabs (tmp - 201.2999), <, 0.01); + tmp = cd_spectrum_get_wavelength (sp, 2); + g_assert_cmpfloat (fabs (tmp - 305.3999), <, 0.01); +} + +static void colord_it8_spect_func (void) { CdIt8 *it8; @@ -2251,6 +2295,7 @@ main (int argc, char **argv) g_test_add_func ("/colord/spectrum", colord_spectrum_func); g_test_add_func ("/colord/spectrum{planckian}", colord_spectrum_planckian_func); g_test_add_func ("/colord/spectrum{subtract}", colord_spectrum_subtract_func); + g_test_add_func ("/colord/spectrum{cx}", colord_spect_cx_func); g_test_add_func ("/colord/edid", colord_edid_func); g_test_add_func ("/colord/transform", colord_transform_func); g_test_add_func ("/colord/icc", colord_icc_func); |