Skip to content

Implement the Delta E algorithm to improve color perception#11095

Merged
27 commits merged intomainfrom
dev/pabhoj/delta_e
Oct 7, 2021
Merged

Implement the Delta E algorithm to improve color perception#11095
27 commits merged intomainfrom
dev/pabhoj/delta_e

Conversation

@PankajBhojwani
Copy link
Contributor

@PankajBhojwani PankajBhojwani commented Aug 31, 2021

  • Implements the Delta E algorithm
  • Uses the Delta E algorithm to precalculate adjusted foreground values based on possible foreground/background color pairs in the color table
  • Adds a setting to use the adjusted foreground values when applicable

PR Checklist

Validation Steps Performed

Before:
color before

After (note dark blue):
color after

@ghost ghost added Area-Accessibility Issues related to accessibility Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Terminal The new Windows Terminal. labels Aug 31, 2021
@github-actions

This comment has been minimized.

@zadjii-msft
Copy link
Member

Can we make this a (default on) setting?

@PankajBhojwani
Copy link
Contributor Author

Can we make this a (default on) setting?

That's probably a good idea

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@j4james
Copy link
Collaborator

j4james commented Sep 2, 2021

This seems like it would have a significant hit on performance. I could have sworn ConEmu only applied the algorithm to the initial palette initialization, but this looks like it's adjusting the colors on every color lookup in the renderer.

Also, would this not break the "concealed" SGR attribute, which deliberately sets the foreground and background colors to the same values?

@github-actions

This comment has been minimized.

@DHowett
Copy link
Member

DHowett commented Sep 2, 2021

This seems like it would have a significant hit on performance. I could have sworn ConEmu only applied the algorithm to the initial palette initialization, but this looks like it's adjusting the colors on every color lookup in the renderer.

That's a good question; I understood it to be at render time for them as well (otherwise, they need to compute each color's contrast on each background and determine whether to nudge that foreground only on that background or nudge it generally... potentially having to resolve a recursive conflict with other colors?), but I may indeed be wrong.

EDIT: Also, perhaps, to improve the contrast of applications that use true color? I'm not sure whether that is a noble goal.

EDIT 2: However, it might be a noble goal if we want to add a feature for High Contrast users to actually induce high contrast in otherwise intransigent applications. (EDIT 3: Which I do -- that is an accessibility feature that could help people quite a bit!)

Also, would this not break the "concealed" SGR attribute, which deliberately sets the foreground and background colors to the same values?

Oh boy, yeah, almost certainly.

@DHowett
Copy link
Member

DHowett commented Sep 3, 2021

EDIT 4: Surprisingly, i think it does do it for True Color

Here's ConEmu

image

Terminal

image

@j4james
Copy link
Collaborator

j4james commented Sep 3, 2021

Hmmm... maybe it's doing it at the time the SGR attributes are applied then. That's probably better than render time, but that still seems like it would be expensive to me, especially if you're planning to have this enabled by default.

@j4james
Copy link
Collaborator

j4james commented Sep 3, 2021

I've had a chance to do a bit more testing on ConEmu now, and it looks to me like it doesn't really support true color - it just maps those sequences to values in the palette. And even with the color adjustment disabled, that mapping seems to be choosing distinguishable colors, which is why it appears to be "working" for you. Also, if I use the 8-color SGR sequences, it's quite happy to let me use black-on-black or white-on-white. It's only color combinations that are close, but not the same, that get adjusted.

That said, I don't think we necessarily need to match what ConEmu is doing exactly, but I do think we need be selective about the situations in which this algorithm is applied, because it definitely has the potential to breaks things.

RGB colors aren't typically a problem, because an app is unlikely to choose a bad RGB color combination unless they had a good reason for it (e.g. they;re creating a gradient effect), which we really shouldn't be "fixing". Palette colors are where the problems arise, because the app doesn't know what palette combinations are distinguishable, and color scheme designers have a well known history of poor choices.

So I had originally thought this feature would just be making sure that every color combination in the palette was distinguishable (i.e. a way to fix the broken color schemes). That would assumedly have zero render-time expense, but would probably cover 99% of the visibility issues that users are facing.

@PankajBhojwani
Copy link
Contributor Author

So I had originally thought this feature would just be making sure that every color combination in the palette was distinguishable (i.e. a way to fix the broken color schemes). That would assumedly have zero render-time expense, but would probably cover 99% of the visibility issues that users are facing.

Yep this is probably the better way to do it, thank you!

@github-actions

This comment has been minimized.

Copy link
Member

@carlos-zamora carlos-zamora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it! Thanks!

Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I would like to review this! Blocking for a chance.)

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Oct 5, 2021
Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm being nitpicky, I know. I'm sorry. I just had the open question really for Leonard 😄


static constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" };
static constexpr size_t TaskbarMinProgress{ 10 };
static constexpr size_t DefaultBgIndex{ 16 };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind-of an implementation detail that you could keep in the c++ file

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just because... it pollutes the global namespace of any file that includes it with some generically-named DefaultBgIndex constant 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same below ofc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense! Moved _MakeAdjustedColorArray into TerminalRenderData.cpp and these constants are only defined in that c++ file now


void _NotifyTerminalCursorPositionChanged() noexcept;

std::array<std::array<COLORREF, 18>, 18> _adjustedForegroundColors;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're spending 1296 bytes per Terminal instance -- @lhecker, is that something you're okay with? Or should we find a better way to store this that can go away if the feature is disabled?

Copy link
Member

@lhecker lhecker Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the data isn't accessed it's not in the CPU. Optimally I'd place it somewhere at the start or end of the struct, so all other (smaller) members can live closely together and get cached together.
Since that's not the case at the moment I can only suggest @PankajBhojwani to move the member before this is merged.

1.2kB of RAM usage isn't much either nowadays. Personally I'd lazily allocate it on the heap just because it's so large, but purely from a performance perspective it's not important to do that. What would be much better though would be to compress data to fit more of it into our modern CPUs! Halving the data for instance is easy, since storing signed 5-bit RGB offsets would fit into 16 bit per color instead of 32.

Considering that this should go into 1.12 I'd do neither "optimization" and just move the member (but moving it is important).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it to the bottom of the struct!

@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Oct 7, 2021
Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just fix or kick that failing build, and we're good! thanks!

@PankajBhojwani PankajBhojwani added the AutoMerge Marked for automatic merge by the bot when requirements are met label Oct 7, 2021
@ghost
Copy link

ghost commented Oct 7, 2021

Hello @PankajBhojwani!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit dd5dbb2 into main Oct 7, 2021
@ghost ghost deleted the dev/pabhoj/delta_e branch October 7, 2021 22:43
@hectormz
Copy link

hectormz commented Oct 8, 2021

Thanks @PankajBhojwani @zadjii-msft @DHowett and others for this feature!

ghost pushed a commit that referenced this pull request Oct 11, 2021
This commit enables /fp:fast. This doubles the performance of the Delta E
computation in #11095 for instance. Additionally it re-enables two options for
debug builds which are normally enabled by default by Visual Studio.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* No change in binary size
* No obvious change in behavior
PankajBhojwani pushed a commit that referenced this pull request Oct 13, 2021
This commit enables /fp:fast. This doubles the performance of the Delta E
computation in #11095 for instance. Additionally it re-enables two options for
debug builds which are normally enabled by default by Visual Studio.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* No change in binary size
* No obvious change in behavior
@ghost
Copy link

ghost commented Oct 20, 2021

🎉Windows Terminal Preview v1.12.2922.0 has been released which incorporates this pull request.:tada:

Handy links:

ghost pushed a commit that referenced this pull request Jan 18, 2022
…le text (#12160)

## Summary of the Pull Request
Disables the automatic adjustment of indistinguishable text (added in #11095) because of the concerns brought up in #11917. Also, the setting is hidden in the SUI for as long as this feature remains disabled.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here
ghost pushed a commit that referenced this pull request Jul 14, 2022
…13343)

## Summary of the Pull Request
Re-enable the setting to adjust indistinguishable text, with some changes:

- We now pre-calculate the nudged values for 'default bright foreground' as well
- When a color table entry is manually set (i.e. via VT sequences) we re-calculate the nudged values

## References
#11095 #12160

## PR Checklist
* [x] Closes #11917
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.

## Validation Steps Performed
Indistinguishable text gets adjusted again
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Accessibility Issues related to accessibility Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Terminal The new Windows Terminal. zBugBash-Consider

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Delta E 2000 to correct color perception

8 participants