Skip to content
This repository has been archived by the owner on Nov 24, 2024. It is now read-only.

Commit

Permalink
Implement support for decoding CCTFs.
Browse files Browse the repository at this point in the history
  • Loading branch information
KelSolaar committed Aug 10, 2018
1 parent 733728a commit f7c2138
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 91 deletions.
36 changes: 29 additions & 7 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
from colour.utilities import domain_range_scale

from colour_analysis import (
COLOURSPACE_MODEL, IMAGE_COLOURSPACE, PRIMARY_COLOURSPACE,
COLOURSPACE_MODEL, IMAGE_COLOURSPACE, IMAGE_DECODING_CCTF, PRIMARY_COLOURSPACE,
RGB_colourspaces, RGB_colourspace_volume_visual, SECONDARY_COLOURSPACE,
colourspace_models, spectral_locus_visual, RGB_image_scatter_visual,
image_data)
colourspace_models, decoding_cctfs, spectral_locus_visual,
RGB_image_scatter_visual, image_data)

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2018 - Colour Developers'
Expand All @@ -41,7 +41,7 @@

__all__ = [
'APP', 'CACHE', 'CACHE_DEFAULT_TIMEOUT', 'IMAGES_DIRECTORY',
'images_response', 'colourspace_models_response',
'images_response', 'decoding_cctfs_response','colourspace_models_response',
'RGB_colourspaces_response', 'RGB_colourspace_volume_visual_response',
'spectral_locus_visual_response', 'RGB_image_scatter_visual_response',
'image_data_response', 'index', 'after_request'
Expand Down Expand Up @@ -153,6 +153,26 @@ def images_response():
return response


@APP.route('/decoding-cctfs')
@CACHE.cached(timeout=CACHE_DEFAULT_TIMEOUT, query_string=True)
def decoding_cctfs_response():
"""
Returns the decoding colour component transfer functions response.
Returns
-------
Response
Decoding colour component transfer functions response.
"""

json_data = decoding_cctfs()

response = Response(json_data, status=200, mimetype='application/json')
response.headers['X-Content-Length'] = len(json_data)

return response


@APP.route('/colourspace-models')
@CACHE.cached(timeout=CACHE_DEFAULT_TIMEOUT, query_string=True)
def colourspace_models_response():
Expand Down Expand Up @@ -265,6 +285,7 @@ def RGB_image_scatter_visual_response(image):
secondary_colourspace=args.get('secondaryColourspace',
SECONDARY_COLOURSPACE),
image_colourspace=args.get('imageColourspace', IMAGE_COLOURSPACE),
image_decoding_cctf=args.get('imageDecodingCctf', IMAGE_DECODING_CCTF),
colourspace_model=args.get('colourspaceModel', COLOURSPACE_MODEL),
out_of_primary_colourspace_gamut=_bool_to_bool(
args.get('outOfPrimaryColourspaceGamut', False)),
Expand Down Expand Up @@ -302,6 +323,7 @@ def image_data_response(image):
secondary_colourspace=args.get('secondaryColourspace',
SECONDARY_COLOURSPACE),
image_colourspace=args.get('imageColourspace', IMAGE_COLOURSPACE),
image_decoding_cctf=args.get('imageDecodingCctf', IMAGE_DECODING_CCTF),
out_of_primary_colourspace_gamut=_bool_to_bool(
args.get('outOfPrimaryColourspaceGamut', False)),
out_of_secondary_colourspace_gamut=_bool_to_bool(
Expand Down Expand Up @@ -332,7 +354,8 @@ def index():
image=os.listdir(IMAGES_DIRECTORY)[0],
primary_colourspace=PRIMARY_COLOURSPACE,
secondary_colourspace=SECONDARY_COLOURSPACE,
image_colourspace=IMAGE_COLOURSPACE)
image_colourspace=IMAGE_COLOURSPACE,
image_decoding_cctf=IMAGE_DECODING_CCTF)


@APP.after_request
Expand All @@ -342,8 +365,7 @@ def after_request(response):
'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods',
'GET,PUT,POST,DELETE,OPTIONS')
response.headers.add('Access-Control-Expose-Headers',
'X-Content-Length')
response.headers.add('Access-Control-Expose-Headers', 'X-Content-Length')

return response

Expand Down
86 changes: 72 additions & 14 deletions colour_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
import numpy as np
import os
import re
from collections import OrderedDict
from werkzeug.contrib.cache import SimpleCache

from colour import RGB_COLOURSPACES, RGB_to_XYZ, read_image
from colour.models import (XYZ_to_colourspace_model, XYZ_to_RGB, RGB_to_RGB,
oetf_reverse_sRGB)
from colour import (LOG_DECODING_CURVES, OETFS_REVERSE,
RGB_COLOURSPACES, RGB_to_RGB, RGB_to_XYZ, XYZ_to_RGB,
read_image)
from colour.models import XYZ_to_colourspace_model, function_gamma
from colour.plotting import filter_cmfs, filter_RGB_colourspaces
from colour.utilities import first_item, normalise_maximum, tsplit, tstack

Expand All @@ -30,11 +32,12 @@

__all__ = [
'LINEAR_FILE_FORMATS', 'DEFAULT_FLOAT_DTYPE', 'COLOURSPACE_MODELS',
'COLOURSPACE_MODELS_LABELS', 'PRIMARY_COLOURSPACE',
'SECONDARY_COLOURSPACE', 'IMAGE_COLOURSPACE', 'COLOURSPACE_MODEL',
'IMAGE_CACHE', 'load_image', 'colourspace_model_axis_reorder',
'colourspace_model_faces_reorder', 'colourspace_models',
'RGB_colourspaces', 'buffer_geometry', 'create_plane', 'create_box',
'COLOURSPACE_MODELS_LABELS', 'DECODING_CCTFS', 'PRIMARY_COLOURSPACE',
'SECONDARY_COLOURSPACE', 'IMAGE_COLOURSPACE', 'IMAGE_DECODING_CCTF',
'COLOURSPACE_MODEL', 'IMAGE_CACHE', 'load_image',
'colourspace_model_axis_reorder', 'colourspace_model_faces_reorder',
'decoding_cctfs', 'colourspace_models', 'RGB_colourspaces',
'buffer_geometry', 'create_plane', 'create_box',
'RGB_colourspace_volume_visual', 'spectral_locus_visual',
'RGB_image_scatter_visual', 'image_data'
]
Expand Down Expand Up @@ -93,6 +96,21 @@
'hdr-CIELAB', 'hdr-IPT'}**
"""

DECODING_CCTFS = OrderedDict()
DECODING_CCTFS.update(
sorted({
'Gamma 2.2': lambda x: function_gamma(x, 2.2),
'Gamma 2.4': lambda x: function_gamma(x, 2.4),
'Gamma 2.6': lambda x: function_gamma(x, 2.6)
}.items()))
DECODING_CCTFS.update(sorted(OETFS_REVERSE.items()))
DECODING_CCTFS.update(sorted(LOG_DECODING_CURVES.items()))
"""
Decoding colour component transfer functions.
DECODING_CCTFS : OrderedDict
"""

PRIMARY_COLOURSPACE = 'sRGB'
"""
Primary analysis RGB colourspace.
Expand All @@ -114,6 +132,13 @@
IMAGE_COLOURSPACE : unicode
"""

IMAGE_DECODING_CCTF = 'sRGB'
"""
Analysed image RGB colourspace decoding colour component transfer function.
IMAGE_DECODING_CCTF : unicode
"""

COLOURSPACE_MODEL = 'CIE xyY'
"""
Analysis colour model.
Expand All @@ -132,7 +157,7 @@
"""


def load_image(path):
def load_image(path, decoding_cctf='sRGB'):
"""
Loads the image at given path and caches it in `IMAGE_CACHE` cache. If the
image is already cached, it is returned directly.
Expand All @@ -141,21 +166,28 @@ def load_image(path):
----------
path : unicode
Image path.
decoding_cctf : unicode, optional
Decoding colour component transfer function (Decoding CCTF) /
electro-optical transfer function (EOTF / EOCF) that maps an
:math:`R'G'B'` video component signal value to tristimulus values at
the display.
Returns
-------
ndarray
Image as a ndarray.
"""

RGB = IMAGE_CACHE.get(path)
key = '{0}-{1}'.format(path, decoding_cctf)

RGB = IMAGE_CACHE.get(key)
if RGB is None:
RGB = read_image(path)

if os.path.splitext(path)[-1].lower() not in LINEAR_FILE_FORMATS:
RGB = oetf_reverse_sRGB(RGB)
RGB = DECODING_CCTFS[decoding_cctf](RGB)

IMAGE_CACHE.set(path, RGB)
IMAGE_CACHE.set(key, RGB)

return RGB

Expand Down Expand Up @@ -220,6 +252,20 @@ def colourspace_model_faces_reorder(a, model=None):
return a


def decoding_cctfs():
"""
Returns the decoding colour component transfer functions formatted as
*JSON*.
Returns
-------
unicode
Decoding colour component transfer functions formatted as *JSON*.
"""

return json.dumps(DECODING_CCTFS.keys())


def colourspace_models():
"""
Returns the colourspace models formatted as *JSON*.
Expand Down Expand Up @@ -608,6 +654,7 @@ def RGB_image_scatter_visual(path,
primary_colourspace=PRIMARY_COLOURSPACE,
secondary_colourspace=SECONDARY_COLOURSPACE,
image_colourspace=IMAGE_COLOURSPACE,
image_decoding_cctf=IMAGE_DECODING_CCTF,
colourspace_model=COLOURSPACE_MODEL,
out_of_primary_colourspace_gamut=False,
out_of_secondary_colourspace_gamut=False,
Expand All @@ -628,6 +675,11 @@ def RGB_image_scatter_visual(path,
image_colourspace: unicode, optional
**{'Primary', 'Secondary'}**,
Analysed image RGB colourspace.
image_decoding_cctf : unicode, optional
Analysed image decoding colour component transfer function
(Decoding CCTF) / electro-optical transfer function (EOTF / EOCF) that
maps an :math:`R'G'B'` video component signal value to tristimulus
values at the display.
colourspace_model : unicode, optional
Colourspace model used to generate the visual geometry.
out_of_primary_colourspace_gamut : bool, optional
Expand Down Expand Up @@ -659,7 +711,7 @@ def RGB_image_scatter_visual(path,
colourspace = (primary_colourspace if image_colourspace == 'Primary' else
secondary_colourspace)

RGB = load_image(path)
RGB = load_image(path, image_decoding_cctf)

if saturate:
RGB = np.clip(RGB, 0, 1)
Expand Down Expand Up @@ -698,6 +750,7 @@ def image_data(path,
primary_colourspace=PRIMARY_COLOURSPACE,
secondary_colourspace=SECONDARY_COLOURSPACE,
image_colourspace=IMAGE_COLOURSPACE,
image_decoding_cctf=IMAGE_DECODING_CCTF,
out_of_primary_colourspace_gamut=False,
out_of_secondary_colourspace_gamut=False,
saturate=False):
Expand All @@ -716,6 +769,11 @@ def image_data(path,
image_colourspace: unicode, optional
**{'Primary', 'Secondary'}**,
Analysed image RGB colourspace.
image_decoding_cctf : unicode, optional
Analysed image decoding colour component transfer function
(Decoding CCTF) / electro-optical transfer function (EOTF / EOCF) that
maps an :math:`R'G'B'` video component signal value to tristimulus
values at the display.
out_of_primary_colourspace_gamut : bool, optional
Whether to only generate the out of primary RGB colourspace gamut
values.
Expand All @@ -738,7 +796,7 @@ def image_data(path,
filter_RGB_colourspaces('^{0}$'.format(
re.escape(secondary_colourspace))))

RGB = load_image(path)
RGB = load_image(path, image_decoding_cctf)

if saturate:
RGB = np.clip(RGB, 0, 1)
Expand Down
2 changes: 1 addition & 1 deletion dist/colour-analysis.js

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion src/views/gamut-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class GamutView extends PerspectiveView {
colourspaceModel: 'CIE xyY',
primaryColourspace: 'sRGB',
secondaryColourspace: 'DCI-P3',
imageColourspace: 'Primary'
imageColourspace: 'Primary',
imageDecodingCctf: 'sRGB'
},
...settings
};
Expand Down Expand Up @@ -78,6 +79,7 @@ class GamutView extends PerspectiveView {
this._primaryColourspace = settings.primaryColourspace;
this._secondaryColourspace = settings.secondaryColourspace;
this._imageColourspace = settings.imageColourspace;
this._imageDecodingCctf = settings.imageDecodingCctf;

this._viewAxesVisual = undefined;

Expand Down Expand Up @@ -222,6 +224,22 @@ class GamutView extends PerspectiveView {
}
}

get imageDecodingCctf() {
return this._imageDecodingCctf;
}

set imageDecodingCctf(value) {
this._imageDecodingCctf = value;

if (this._imageScatterVisual != undefined) {
this._imageScatterVisual.imageDecodingCctf = value;
}

if (this._imageScatterOverlayVisual != undefined) {
this._imageScatterOverlayVisual.imageDecodingCctf = value;
}
}

get viewAxesVisual() {
return this._viewAxesVisual;
}
Expand Down Expand Up @@ -335,6 +353,7 @@ class GamutView extends PerspectiveView {
primaryColourspace: this._primaryColourspace,
secondaryColourspace: this._secondaryColourspace,
imageColourspace: this._imageColourspace,
imageDecodingCctf: this._imageDecodingCctf,
colourspaceModel: this._colourspaceModel
},
...settings
Expand All @@ -353,6 +372,7 @@ class GamutView extends PerspectiveView {
primaryColourspace: this._primaryColourspace,
secondaryColourspace: this._secondaryColourspace,
imageColourspace: this._imageColourspace,
imageDecodingCctf: this._imageDecodingCctf,
colourspaceModel: this._colourspaceModel,
uniformOpacity: 0.5
},
Expand Down
25 changes: 23 additions & 2 deletions src/views/image-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class ImageView extends OrthographicView {
colourspaceModel: 'CIE xyY',
primaryColourspace: 'sRGB',
secondaryColourspace: 'DCI-P3',
imageColourspace: 'Primary'
imageColourspace: 'Primary',
imageDecodingCctf: 'sRGB'
},
...settings
};
Expand All @@ -36,6 +37,7 @@ class ImageView extends OrthographicView {
this._primaryColourspace = settings.primaryColourspace;
this._secondaryColourspace = settings.secondaryColourspace;
this._imageColourspace = settings.imageColourspace;
this._imageDecodingCctf = settings.imageDecodingCctf;

// The following groups are defining the rendering order.
this._imageVisualGroup = new THREE.Group();
Expand Down Expand Up @@ -116,6 +118,22 @@ class ImageView extends OrthographicView {
}
}

get imageDecodingCctf() {
return this._imageDecodingCctf;
}

set imageDecodingCctf(value) {
this._imageDecodingCctf = value;

if (this._imageVisual != undefined) {
this._imageVisual.imageDecodingCctf = value;
}

if (this._imageOverlayVisual != undefined) {
this._imageOverlayVisual.imageDecodingCctf = value;
}
}

get imageVisual() {
return this._imageVisual;
}
Expand All @@ -139,7 +157,9 @@ class ImageView extends OrthographicView {
image: this._image,
primaryColourspace: this._primaryColourspace,
secondaryColourspace: this._secondaryColourspace,
imageColourspace: this._imageColourspace
imageColourspace: this._imageColourspace,
imageDecodingCctf: this._imageDecodingCctf

},
...settings
});
Expand All @@ -156,6 +176,7 @@ class ImageView extends OrthographicView {
primaryColourspace: this._primaryColourspace,
secondaryColourspace: this._secondaryColourspace,
imageColourspace: this._imageColourspace,
imageDecodingCctf: this._imageDecodingCctf,
uniformOpacity: 0.5,
depth: 0.5
},
Expand Down
Loading

0 comments on commit f7c2138

Please sign in to comment.