Skip to content

Commit

Permalink
Merge pull request #145 from colour-science/feature/recovery
Browse files Browse the repository at this point in the history
PR: Implement support for "Smits (1999)" reflectance recovery method.
  • Loading branch information
MichaelMauderer committed Oct 25, 2014
2 parents 7e5db89 + 837be43 commit a3d85a6
Show file tree
Hide file tree
Showing 10 changed files with 441 additions and 2 deletions.
4 changes: 4 additions & 0 deletions colour/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- phenomenons: Computation of various optical phenomenons.
- plotting: Diagrams, plots, etc...
- quality: Colour quality computation.
- recovery: Reflectance recovery.
- temperature: Colour temperature and correlated colour temperature
computation.
- utilities: Various utilities and data structures.
Expand Down Expand Up @@ -71,6 +72,8 @@
from . import notation
from .quality import * # noqa
from . import quality
from .recovery import * # noqa
from . import recovery
from .temperature import * # noqa
from . import temperature
from . import plotting
Expand All @@ -97,6 +100,7 @@
__all__ += phenomenons.__all__
__all__ += notation.__all__
__all__ += quality.__all__
__all__ += recovery.__all__
__all__ += temperature.__all__

__application_name__ = 'Colour'
Expand Down
6 changes: 5 additions & 1 deletion colour/characterisation/dataset/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

from __future__ import absolute_import

from .colour_checkers import COLOURCHECKERS, COLOURCHECKERS_SPDS
from .colour_checkers import (
COLOURCHECKERS,
COLOURCHECKER_INDEXES_TO_NAMES_MAPPING,
COLOURCHECKERS_SPDS)

__all__ = ['COLOURCHECKERS',
'COLOURCHECKER_INDEXES_TO_NAMES_MAPPING',
'COLOURCHECKERS_SPDS']
3 changes: 2 additions & 1 deletion colour/characterisation/dataset/colour_checkers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from __future__ import absolute_import

from .chromaticity_coordinates import COLOURCHECKERS
from .spds import COLOURCHECKERS_SPDS
from .spds import COLOURCHECKER_INDEXES_TO_NAMES_MAPPING, COLOURCHECKERS_SPDS

__all__ = ['COLOURCHECKERS',
'COLOURCHECKER_INDEXES_TO_NAMES_MAPPING',
'COLOURCHECKERS_SPDS']
23 changes: 23 additions & 0 deletions colour/examples/recovery/examples_smits1999.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Showcases reflectance recovery computations using *Brian Smits (1999)* method.
"""

import colour
from colour.utilities.verbose import message_box

message_box('"Brian Smits (1999)" - Reflectance Recovery Computations')

RGB = [0.35505307, 0.47995567, 0.61088035]
message_box(('Recovering reflectance using "Brian Smits (1999)" method from '
'given "RGB" colourspace matrix:\n'
'\n\tRGB: {0}'.format(RGB)))
print(colour.RGB_to_spectral_smits1999(RGB))

print('\n')

message_box(('An analysis of "Brian Smits (1999)" method is available at the '
'following url : '
'http://nbviewer.ipython.org/github/colour-science/colour-website/blob/master/ipython/about_reflectance_recovery.ipynb')) # noqa
12 changes: 12 additions & 0 deletions colour/recovery/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import absolute_import

from .dataset import * # noqa
from . import dataset
from .smits1999 import RGB_to_spectral_smits1999

__all__ = []
__all__ += dataset.__all__
__all__ += ['RGB_to_spectral_smits1999']
8 changes: 8 additions & 0 deletions colour/recovery/dataset/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import absolute_import

from .smits1999 import SMITS_1999_SPDS

__all__ = ['SMITS_1999_SPDS']
130 changes: 130 additions & 0 deletions colour/recovery/dataset/smits1999.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Smits (1999) - Reflectance Recovery Dataset
===========================================
Defines the dataset for reflectance recovery using *Smits (1999)* method.
References
----------
.. [1] Smits, B. (1999). An RGB-to-Spectrum Conversion for Reflectances.
Journal of Graphics Tools, 4(4), 11–22.
doi:10.1080/10867651.1999.10487511
"""

from __future__ import division, unicode_literals

from colour.colorimetry.spectrum import SpectralPowerDistribution
from colour.utilities import CaseInsensitiveMapping

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013 - 2014 - Colour Developers'
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'

__all__ = ['SMITS_1999_SPDS_DATA',
'SMITS_1999_SPDS']

SMITS_1999_SPDS_DATA = {
'white': {
380.0: 1.0,
417.7778: 1.0,
455.5556: 0.9999,
493.3333: 0.9993,
531.1111: 0.9992,
568.8889: 0.9998,
606.6667: 1.0,
644.4444: 1.0,
682.2222: 1.0,
720.0: 1.0},
'cyan': {
380.0: 0.971,
417.7778: 0.9426,
455.5556: 1.0007,
493.3333: 1.0007,
531.1111: 1.0007,
568.8889: 1.0007,
606.6667: 0.1564,
644.4444: 0.0,
682.2222: 0.0,
720.0: 0.0},
'magenta': {
380.0: 1.0,
417.7778: 1.0,
455.5556: 0.9685,
493.3333: 0.2229,
531.1111: 0.0,
568.8889: 0.0458,
606.6667: 0.8369,
644.4444: 1.0,
682.2222: 1.0,
720.0: 0.9959},
'yellow': {
380.0: 0.0001,
417.7778: 0.0,
455.5556: 0.1088,
493.3333: 0.6651,
531.1111: 1.0,
568.8889: 1.0,
606.6667: 0.9996,
644.4444: 0.9586,
682.2222: 0.9685,
720.0: 0.984},
'red': {
380.0: 0.1012,
417.7778: 0.0515,
455.5556: 0.0,
493.3333: 0.0,
531.1111: 0.0,
568.8889: 0.0,
606.6667: 0.8325,
644.4444: 1.0149,
682.2222: 1.0149,
720.0: 1.0149},
'green': {
380.0: 0.0,
417.7778: 0.0,
455.5556: 0.0273,
493.3333: 0.7937,
531.1111: 1.0,
568.8889: 0.9418,
606.6667: 0.1719,
644.4444: 0.0,
682.2222: 0.0,
720.0: 0.0025},
'blue': {
380.0: 1.0,
417.7778: 1.0,
455.5556: 0.8916,
493.3333: 0.3323,
531.1111: 0.0,
568.8889: 0.0,
606.6667: 0.0003,
644.4444: 0.0369,
682.2222: 0.0483,
720.0: 0.0496}}

SMITS_1999_SPDS = CaseInsensitiveMapping({
'white': SpectralPowerDistribution(
'white', SMITS_1999_SPDS_DATA.get('white')),
'cyan': SpectralPowerDistribution(
'cyan', SMITS_1999_SPDS_DATA.get('cyan')),
'magenta': SpectralPowerDistribution(
'magenta', SMITS_1999_SPDS_DATA.get('magenta')),
'yellow': SpectralPowerDistribution(
'yellow', SMITS_1999_SPDS_DATA.get('yellow')),
'red': SpectralPowerDistribution(
'red', SMITS_1999_SPDS_DATA.get('red')),
'green': SpectralPowerDistribution(
'green', SMITS_1999_SPDS_DATA.get('green')),
'blue': SpectralPowerDistribution(
'blue', SMITS_1999_SPDS_DATA.get('blue'))})
"""
*Smits (1999)* spectral power distributions.
SMITS_1999_SPDS : CaseInsensitiveMapping
"""
168 changes: 168 additions & 0 deletions colour/recovery/smits1999.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Smits (1999) - Reflectance Recovery
===================================
Defines objects for reflectance recovery using *Smits (1999)* method.
See Also
--------
`Smits (1999) - Reflectance Recovery IPython Notebook
<http://nbviewer.ipython.org/github/colour-science/colour-ipython/blob/master/notebooks/recovery/smits1999.ipynb>`_ # noqa
References
----------
.. [1] Smits, B. (1999). An RGB-to-Spectrum Conversion for Reflectances.
Journal of Graphics Tools, 4(4), 11–22.
doi:10.1080/10867651.1999.10487511
"""

from __future__ import division, unicode_literals

import numpy as np

from colour.colorimetry import ILLUMINANTS, zeros_spd
from colour.models import (
XYZ_to_RGB,
sRGB_COLOURSPACE,
normalised_primary_matrix)
from colour.recovery import SMITS_1999_SPDS

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013 - 2014 - Colour Developers'
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'

__all__ = ['SMITS1999_PRIMARIES',
'SMITS1999_WHITEPOINT',
'SMITS1999_XYZ_TO_RGB_MATRIX',
'XYZ_to_RGB_smits1999',
'RGB_to_spectral_smits1999']

SMITS1999_PRIMARIES = sRGB_COLOURSPACE.primaries
"""
Current *Brian Smits (1999)* method implementation colourspace primaries.
SMITS1999_PRIMARIES : ndarray, (3, 2)
"""

SMITS1999_WHITEPOINT = ILLUMINANTS.get(
'CIE 1931 2 Degree Standard Observer').get('E')
"""
Current *Brian Smits (1999)* method implementation colourspace whitepoint.
SMITS1999_WHITEPOINT : tuple
"""

SMITS1999_XYZ_TO_RGB_MATRIX = np.linalg.inv(
normalised_primary_matrix(SMITS1999_PRIMARIES, SMITS1999_WHITEPOINT))
"""
Current *Brian Smits (1999)* method implementation *RGB* colourspace to
*CIE XYZ* colourspace matrix.
SMITS1999_XYZ_TO_RGB_MATRIX : array_like, (3, 3)
"""


def XYZ_to_RGB_smits1999(XYZ, chromatic_adaptation_transform='Bradford'):
"""
Convenient object to convert from *CIE XYZ* colourspace to *RGB*
colourspace in conditions required by the current *Smits (1999)* method
implementation.
Parameters
----------
XYZ : array_like, (3,)
*CIE XYZ* colourspace matrix.
chromatic_adaptation_method : unicode, optional
{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild,
'CMCCAT97', 'CMCCAT2000', 'Bianco', 'Bianco PC'},
*Chromatic adaptation* method.
Returns
-------
ndarray, (3,)
*RGB* colour matrix.
Notes
-----
- Input *CIE XYZ* colourspace matrix is in domain [0, 1].
Examples
--------
>>> XYZ = np.array([0.07049534, 0.1008, 0.09558313])
>>> XYZ_to_RGB_smits1999(XYZ) # doctest: +ELLIPSIS
array([ 0.0214496..., 0.1315460..., 0.0928760...])
"""

return XYZ_to_RGB(XYZ,
SMITS1999_WHITEPOINT,
SMITS1999_WHITEPOINT,
SMITS1999_XYZ_TO_RGB_MATRIX,
chromatic_adaptation_transform,
transfer_function=None)


def RGB_to_spectral_smits1999(RGB):
"""
Recovers the spectral power distribution of given *RGB* colourspace matrix
using *Smits (1999)* method.
Parameters
----------
RGB : array_like, (3,)
*RGB* colourspace matrix.
Returns
-------
SpectralPowerDistribution
Recovered spectral power distribution.
Examples
--------
>>> RGB = np.array([0.02144962, 0.13154603, 0.09287601])
>>> RGB_to_spectral_smits1999(RGB) # doctest: +ELLIPSIS
<...SpectralPowerDistribution object at 0x...>
"""

white_spd = SMITS_1999_SPDS.get('white').clone()
cyan_spd = SMITS_1999_SPDS.get('cyan').clone()
magenta_spd = SMITS_1999_SPDS.get('magenta').clone()
yellow_spd = SMITS_1999_SPDS.get('yellow').clone()
red_spd = SMITS_1999_SPDS.get('red').clone()
green_spd = SMITS_1999_SPDS.get('green').clone()
blue_spd = SMITS_1999_SPDS.get('blue').clone()

R, G, B = np.ravel(RGB)
spd = zeros_spd(SMITS_1999_SPDS.get('white').shape)

if R <= G and R <= B:
spd += white_spd * R
if G <= B:
spd += cyan_spd * (G - R)
spd += blue_spd * (B - G)
else:
spd += cyan_spd * (B - R)
spd += green_spd * (G - B)
elif G <= R and G <= B:
spd += white_spd * G
if R <= B:
spd += magenta_spd * (R - G)
spd += blue_spd * (B - R)
else:
spd += magenta_spd * (B - G)
spd += red_spd * (R - B)
else:
spd += white_spd * B
if R <= G:
spd += yellow_spd * (R - B)
spd += green_spd * (G - R)
else:
spd += yellow_spd * (G - B)
spd += red_spd * (R - G)

return spd
2 changes: 2 additions & 0 deletions colour/recovery/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
Loading

0 comments on commit a3d85a6

Please sign in to comment.