Skip to content

Commit 8aa3eb4

Browse files
committed
added threshold and distance limit calculations to research, threshold values are now based on SMPTE 2065-1 ColorChecker24 RGB values
1 parent 428094d commit 8aa3eb4

File tree

3 files changed

+32396
-1
lines changed

3 files changed

+32396
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The following implementations are available in the [model](model) directory:
2929
- Python Script for [Numpy](https://numpy.org/)
3030

3131
## Default Parameter Values
32-
This [Google Colab notebook](https://colab.research.google.com/drive/1ZMSQhyhXtAYQXfop6qhifXudDiPu4eTV?usp=sharing) shows calculations for the threshold values needed to protect the colors of the ColorChecker24, as defined in Annexe B of [TB-2014-004](http://j.mp/TB-2014-004), and the distance limits needed to map the entirety of a set of common camera encoding gamuts into AP1.
32+
This [Google Colab notebook](https://colab.research.google.com/drive/1ZMSQhyhXtAYQXfop6qhifXudDiPu4eTV?usp=sharing) shows calculations for the threshold values needed to protect the colors of the ColorChecker24, as defined in table D.1 of SMPTE 2065-1, and the distance limits needed to map the entirety of a set of common camera encoding gamuts into AP1.
3333

3434
## Research
3535

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
{
2+
"nbformat": 4,
3+
"nbformat_minor": 0,
4+
"metadata": {
5+
"colab": {
6+
"name": "gamut_compress_defaults_new_distance_limit_method.ipynb",
7+
"provenance": [],
8+
"collapsed_sections": [],
9+
"toc_visible": true
10+
},
11+
"kernelspec": {
12+
"name": "python3",
13+
"display_name": "Python 3"
14+
}
15+
},
16+
"cells": [
17+
{
18+
"cell_type": "markdown",
19+
"metadata": {
20+
"id": "nP-x7mebWWOA",
21+
"colab_type": "text"
22+
},
23+
"source": [
24+
"# Set up Colour Science for Python with latest `develop` branch"
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"metadata": {
30+
"id": "UlCRUQswC3KF",
31+
"colab_type": "code",
32+
"colab": {
33+
"base_uri": "https://localhost:8080/",
34+
"height": 748
35+
},
36+
"outputId": "a13e51c1-b797-47a1-b923-d8f01dee660d"
37+
},
38+
"source": [
39+
"!pip install -q colour-science\n",
40+
"\n",
41+
"!pip uninstall -y colour-science\n",
42+
"!if ! [ -d \"colour\" ]; then git clone https://github.com/colour-science/colour; fi\n",
43+
"!if [ -d \"colour\" ]; then cd colour && git fetch && git checkout develop && cd ..; fi\n",
44+
"\n",
45+
"import sys\n",
46+
"sys.path.append('colour')\n",
47+
"\n",
48+
"import colour\n",
49+
"colour.utilities.describe_environment()"
50+
],
51+
"execution_count": 2,
52+
"outputs": [
53+
{
54+
"output_type": "stream",
55+
"text": [
56+
"\u001b[K |████████████████████████████████| 1.6MB 2.9MB/s \n",
57+
"\u001b[?25hUninstalling colour-science-0.3.15:\n",
58+
" Successfully uninstalled colour-science-0.3.15\n",
59+
"Cloning into 'colour'...\n",
60+
"remote: Enumerating objects: 270, done.\u001b[K\n",
61+
"remote: Counting objects: 100% (270/270), done.\u001b[K\n",
62+
"remote: Compressing objects: 100% (186/186), done.\u001b[K\n",
63+
"remote: Total 45133 (delta 170), reused 180 (delta 84), pack-reused 44863\u001b[K\n",
64+
"Receiving objects: 100% (45133/45133), 110.60 MiB | 32.13 MiB/s, done.\n",
65+
"Resolving deltas: 100% (34504/34504), done.\n",
66+
"Already on 'develop'\n",
67+
"Your branch is up to date with 'origin/develop'.\n",
68+
"===============================================================================\n",
69+
"* *\n",
70+
"* Interpreter : *\n",
71+
"* python : 3.6.9 (default, Jul 17 2020, 12:50:27) *\n",
72+
"* [GCC 8.4.0] *\n",
73+
"* *\n",
74+
"* colour-science.org : *\n",
75+
"* colour : v0.3.15-370-g1317e9df *\n",
76+
"* *\n",
77+
"* Runtime : *\n",
78+
"* imageio : 2.4.1 *\n",
79+
"* matplotlib : 3.2.2 *\n",
80+
"* networkx : 2.5 *\n",
81+
"* numpy : 1.18.5 *\n",
82+
"* pandas : 1.0.5 *\n",
83+
"* scipy : 1.4.1 *\n",
84+
"* six : 1.15.0 *\n",
85+
"* *\n",
86+
"===============================================================================\n"
87+
],
88+
"name": "stdout"
89+
},
90+
{
91+
"output_type": "execute_result",
92+
"data": {
93+
"text/plain": [
94+
"defaultdict(collections.OrderedDict,\n",
95+
" {'Interpreter': OrderedDict([('python',\n",
96+
" '3.6.9 (default, Jul 17 2020, 12:50:27) \\n[GCC 8.4.0]')]),\n",
97+
" 'Runtime': OrderedDict([('imageio', '2.4.1'),\n",
98+
" ('matplotlib', '3.2.2'),\n",
99+
" ('networkx', '2.5'),\n",
100+
" ('numpy', '1.18.5'),\n",
101+
" ('pandas', '1.0.5'),\n",
102+
" ('scipy', '1.4.1'),\n",
103+
" ('six', '1.15.0')]),\n",
104+
" 'colour-science.org': OrderedDict([('colour',\n",
105+
" 'v0.3.15-370-g1317e9df')])})"
106+
]
107+
},
108+
"metadata": {
109+
"tags": []
110+
},
111+
"execution_count": 2
112+
}
113+
]
114+
},
115+
{
116+
"cell_type": "markdown",
117+
"metadata": {
118+
"id": "AFjVUDozXPXM",
119+
"colab_type": "text"
120+
},
121+
"source": [
122+
"# Define Blackmagic Wide Gamut v4 colour space\n",
123+
"# (not currently included in Colour)"
124+
]
125+
},
126+
{
127+
"cell_type": "code",
128+
"metadata": {
129+
"id": "XEdXherNWrXK",
130+
"colab_type": "code",
131+
"colab": {}
132+
},
133+
"source": [
134+
"import numpy as np\n",
135+
"\n",
136+
"import colour\n",
137+
"from colour.models import (\n",
138+
" RGB_Colourspace,\n",
139+
" normalised_primary_matrix\n",
140+
" )\n",
141+
"from colour.colorimetry import CCS_ILLUMINANTS\n",
142+
"\n",
143+
"BMD_WIDE_GAMUT_V4_PRIMARIES = np.array([\n",
144+
" [0.7177, 0.3171],\n",
145+
" [0.2280, 0.8616],\n",
146+
" [0.1006, -0.0820],\n",
147+
"])\n",
148+
"\"\"\"\n",
149+
"*BMD Wide Gamut V4* colourspace primaries.\n",
150+
"As displayed on DaVinci Resolve Chromaticity scope.\n",
151+
"\n",
152+
"BMD_WIDE_GAMUT_V4_PRIMARIES : ndarray, (3, 2)\n",
153+
"\"\"\"\n",
154+
"\n",
155+
"BMD_WIDE_GAMUT_V4_WHITEPOINT_NAME = 'D65'\n",
156+
"\"\"\"\n",
157+
"*BMD Wide Gamut V4* colourspace whitepoint name.\n",
158+
"\n",
159+
"BMD_WIDE_GAMUT_V4_WHITEPOINT : unicode\n",
160+
"\"\"\"\n",
161+
"\n",
162+
"BMD_WIDE_GAMUT_V4_WHITEPOINT = (CCS_ILLUMINANTS[\n",
163+
" 'CIE 1931 2 Degree Standard Observer'][BMD_WIDE_GAMUT_V4_WHITEPOINT_NAME])\n",
164+
"\"\"\"\n",
165+
"*BMD Wide Gamut V4* colourspace whitepoint.\n",
166+
"\n",
167+
"BMD_WIDE_GAMUT_V4_WHITEPOINT : ndarray\n",
168+
"\"\"\"\n",
169+
"\n",
170+
"BMD_WIDE_GAMUT_V4_TO_XYZ_MATRIX = (normalised_primary_matrix(\n",
171+
" BMD_WIDE_GAMUT_V4_PRIMARIES, BMD_WIDE_GAMUT_V4_WHITEPOINT))\n",
172+
"\"\"\"\n",
173+
"*BMD Wide Gamut V4* colourspace to *CIE XYZ* tristimulus values matrix.\n",
174+
"\n",
175+
"BMD_WIDE_GAMUT_V4_TO_XYZ_MATRIX : array_like, (3, 3)\n",
176+
"\"\"\"\n",
177+
"\n",
178+
"XYZ_TO_BMD_WIDE_GAMUT_V4_MATRIX = (\n",
179+
" np.linalg.inv(BMD_WIDE_GAMUT_V4_TO_XYZ_MATRIX))\n",
180+
"\"\"\"\n",
181+
"*CIE XYZ* tristimulus values to *BMD Wide Gamut V4* colourspace matrix.\n",
182+
"\n",
183+
"XYZ_TO_BMD_WIDE_GAMUT_V4_MATRIX : array_like, (3, 3)\n",
184+
"\"\"\"\n",
185+
"\n",
186+
"RGB_COLOURSPACE_BMD_WIDE_GAMUT_V4 = RGB_Colourspace(\n",
187+
" 'BMD Wide Gamut V4',\n",
188+
" BMD_WIDE_GAMUT_V4_PRIMARIES,\n",
189+
" BMD_WIDE_GAMUT_V4_WHITEPOINT,\n",
190+
" BMD_WIDE_GAMUT_V4_WHITEPOINT_NAME,\n",
191+
" BMD_WIDE_GAMUT_V4_TO_XYZ_MATRIX,\n",
192+
" XYZ_TO_BMD_WIDE_GAMUT_V4_MATRIX,\n",
193+
")"
194+
],
195+
"execution_count": 3,
196+
"outputs": []
197+
},
198+
{
199+
"cell_type": "markdown",
200+
"metadata": {
201+
"id": "qo0_9YCJXOLw",
202+
"colab_type": "text"
203+
},
204+
"source": [
205+
"# Thresholds\n",
206+
"Calculate `thresholds` to protect ColorChecker 24"
207+
]
208+
},
209+
{
210+
"cell_type": "code",
211+
"metadata": {
212+
"id": "bCukamO6DOsF",
213+
"colab_type": "code",
214+
"colab": {
215+
"base_uri": "https://localhost:8080/",
216+
"height": 51
217+
},
218+
"outputId": "8a1eff8c-1ae3-4701-d449-1f78df8c89eb"
219+
},
220+
"source": [
221+
"from __future__ import division\n",
222+
"\n",
223+
"import warnings\n",
224+
"\n",
225+
"from colour.models import (\n",
226+
" RGB_to_RGB,\n",
227+
" RGB_COLOURSPACE_ACES2065_1,\n",
228+
" RGB_COLOURSPACE_ACESCG,\n",
229+
" RGB_COLOURSPACE_ALEXA_WIDE_GAMUT,\n",
230+
" RGB_COLOURSPACE_CINEMA_GAMUT,\n",
231+
" RGB_COLOURSPACE_RED_WIDE_GAMUT_RGB,\n",
232+
" RGB_COLOURSPACE_S_GAMUT3,\n",
233+
" RGB_COLOURSPACE_VENICE_S_GAMUT3,\n",
234+
" RGB_COLOURSPACE_V_GAMUT\n",
235+
" )\n",
236+
"from colour.utilities import tsplit, tstack, dot_vector\n",
237+
"\n",
238+
"# ColorChecker 24 values as per SMPTE 2065-1\n",
239+
"CC24 = np.array([[0.11877, 0.08709, 0.05895],\n",
240+
" [0.40002, 0.31916, 0.23736],\n",
241+
" [0.18476, 0.20398, 0.31311],\n",
242+
" [0.10901, 0.13511, 0.06493],\n",
243+
" [0.26684, 0.24604, 0.40932],\n",
244+
" [0.32283, 0.46208, 0.40606],\n",
245+
" [0.38605, 0.22743, 0.05777],\n",
246+
" [0.13822, 0.13037, 0.33703],\n",
247+
" [0.30202, 0.13752, 0.12758],\n",
248+
" [0.09310, 0.06347, 0.13525],\n",
249+
" [0.34876, 0.43654, 0.10613],\n",
250+
" [0.48655, 0.36685, 0.08061],\n",
251+
" [0.08732, 0.07443, 0.27274],\n",
252+
" [0.15366, 0.25692, 0.09071],\n",
253+
" [0.21742, 0.07070, 0.05130],\n",
254+
" [0.58919, 0.53943, 0.09157],\n",
255+
" [0.30904, 0.14818, 0.27426],\n",
256+
" [0.14901, 0.23378, 0.35939]])\n",
257+
"\n",
258+
"CC24_AP1 = RGB_to_RGB(CC24, RGB_COLOURSPACE_ACES2065_1, RGB_COLOURSPACE_ACESCG)\n",
259+
"\n",
260+
"ach = np.max(CC24_AP1, axis=-1)[..., np.newaxis]\n",
261+
"dist = ((ach - CC24_AP1) / ach)\n",
262+
"c, m, y = tsplit(dist)\n",
263+
"\n",
264+
"print('Thresholds:')\n",
265+
"print(np.max(c), np.max(m), np.max(y))"
266+
],
267+
"execution_count": 5,
268+
"outputs": [
269+
{
270+
"output_type": "stream",
271+
"text": [
272+
"Thresholds:\n",
273+
"0.814546172832 0.802945634483 0.87963185306\n"
274+
],
275+
"name": "stdout"
276+
}
277+
]
278+
},
279+
{
280+
"cell_type": "markdown",
281+
"metadata": {
282+
"id": "Rok6XJ-ZY_Xt",
283+
"colab_type": "text"
284+
},
285+
"source": [
286+
"# Distance Limits\n",
287+
"Calculate `distances` to map common camera encoding spaces to within AP1"
288+
]
289+
},
290+
{
291+
"cell_type": "code",
292+
"metadata": {
293+
"id": "2-4jmmBKZJg8",
294+
"colab_type": "code",
295+
"colab": {
296+
"base_uri": "https://localhost:8080/",
297+
"height": 68
298+
},
299+
"outputId": "ca3d9312-8f21-40fe-a4de-31e38a185573"
300+
},
301+
"source": [
302+
"maxLimits = np.array([[-1.0, 1.0, 1.0],\n",
303+
" [ 1.0, -1.0, 1.0],\n",
304+
" [ 1.0, 1.0, -1.0]])\n",
305+
"\n",
306+
"spaces = [[RGB_COLOURSPACE_ALEXA_WIDE_GAMUT, 'CAT02'],\n",
307+
" [RGB_COLOURSPACE_BMD_WIDE_GAMUT_V4, 'Bradford'],\n",
308+
" [RGB_COLOURSPACE_CINEMA_GAMUT, 'CAT02'],\n",
309+
" [RGB_COLOURSPACE_RED_WIDE_GAMUT_RGB, 'Bradford'],\n",
310+
" [RGB_COLOURSPACE_S_GAMUT3, 'CAT02'],\n",
311+
" [RGB_COLOURSPACE_VENICE_S_GAMUT3, 'CAT02'],\n",
312+
" [RGB_COLOURSPACE_V_GAMUT, 'CAT02']]\n",
313+
"\n",
314+
"bounds = []\n",
315+
"\n",
316+
"\n",
317+
"for space, cat in spaces:\n",
318+
" vendorRGB = RGB_to_RGB(maxLimits,\n",
319+
" RGB_COLOURSPACE_ACESCG,\n",
320+
" space,\n",
321+
" chromatic_adaptation_transform=cat)\n",
322+
" vendorHSV = colour.RGB_to_HSV(vendorRGB)\n",
323+
"\n",
324+
" for hsv in vendorHSV:\n",
325+
" hsv[1] = min(1.0, hsv[1])\n",
326+
"\n",
327+
" vendorRGB = colour.HSV_to_RGB(vendorHSV)\n",
328+
"\n",
329+
" bounds.append(RGB_to_RGB(vendorRGB,\n",
330+
" space,\n",
331+
" RGB_COLOURSPACE_ACESCG,\n",
332+
" chromatic_adaptation_transform=cat))\n",
333+
"\n",
334+
"ach = np.max(bounds, axis=-1)[..., np.newaxis]\n",
335+
"dist = np.where(ach == 0.0, 0.0, (ach - bounds) / ach)\n",
336+
"\n",
337+
"c, m, y = tsplit(dist)\n",
338+
"\n",
339+
"print('\\nDistance Limits:')\n",
340+
"print(np.max(c) - 1, np.max(m) - 1, np.max(y) - 1)\n"
341+
],
342+
"execution_count": 9,
343+
"outputs": [
344+
{
345+
"output_type": "stream",
346+
"text": [
347+
"\n",
348+
"Distance Limits:\n",
349+
"0.147282233491 0.264290310772 0.312377540725\n"
350+
],
351+
"name": "stdout"
352+
}
353+
]
354+
}
355+
]
356+
}

0 commit comments

Comments
 (0)