Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More accurate ICtCp matrices #365

Merged
merged 1 commit into from Nov 28, 2023

Conversation

facelessuser
Copy link
Collaborator

No description provided.

Copy link

netlify bot commented Nov 28, 2023

Deploy Preview for colorjs ready!

Name Link
🔨 Latest commit eea9f83
🔍 Latest deploy log https://app.netlify.com/sites/colorjs/deploys/656564c6d3d51f00086b4df1
😎 Deploy Preview https://deploy-preview-365--colorjs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@facelessuser
Copy link
Collaborator Author

It occurred to me today how to fix the rough conversion in ICtCp.

Simply using the rational matrix and applying a matrix multiply of the Rec2020 XYZ to RGB matrix creates a much more accurate conversion. This is directly inferred from the Dolby paper. https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf

Matrix Calculations
"""
Calculate ICtCp matrices.

https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf
"""
import numpy as np

np.set_printoptions(precision=16, sign='-', floatmode='fixed')

# Matrix is directly from Color.js Rec2020
XYZ_TO_RGB = [
    [  1.716651187971268,  -0.355670783776392, -0.253366281373660  ],
    [ -0.666684351832489,   1.616481236634939,  0.0157685458139111 ],
    [  0.017639857445311,  -0.042770613257809,  0.942103121235474  ]
]

# Use rational values and apply Rec. 2020 matrix to get a precise XYZ to LMS matrix
m1 = [
    [1688, 2146, 262],
    [683, 2951, 462],
    [99, 309, 3688]
]
m1 = np.matmul(np.divide(m1, 4096), XYZ_TO_RGB)

# LMS to ICtCp
m2 = [
    [2048, 2048, 0],
    [6610, -13613, 7003],
    [17933, -17390, -543]
]
m2 = np.divide(m2, 4096)

if __name__ == "__main__":
    print('===== XYZ to LMS =====')
    print(m1)
    print('===== LMS to XYZ =====')
    print(np.linalg.inv(m1))
    print('===== PQ LMS to ICtCp =====')
    print(m2)
    print('===== ICtCp to PQ LMS =====')
    print(np.linalg.inv(m2))

The results are much, much better, especially around the achromatic regions.

> new Color('rec2100pq', [1, 1, 1]).to('ictcp').coords
[ 1, 0, 0 ]
> new Color('white').to('ictcp').coords
[ 0.5806888810416109, 1.1102230246251565e-16, 2.914335439641036e-16 ]

@svgeesus svgeesus merged commit 7ec8c42 into color-js:main Nov 28, 2023
4 checks passed
jgerigmeyer added a commit to oddbird/color.js that referenced this pull request Nov 29, 2023
* main:
  More consistent formatting across the codebase. (color-js#372)
  More accurate ICtCp matrices (color-js#365)
  Fix Jzazbz tests (color-js#366)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants