diff options
author | Mathias Agopian <mathias@google.com> | 2013-09-01 21:36:12 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2013-09-04 22:11:15 -0700 |
commit | ff2ed70fa30f04b90dd1a2c06ec2319e157152d7 (patch) | |
tree | ce07917c9844239d37b000afd2518b08028ed8be /services/surfaceflinger/Effects | |
parent | 1d4d8f94e2989b7c8667602304df9059d2701653 (diff) | |
download | frameworks_native-ff2ed70fa30f04b90dd1a2c06ec2319e157152d7.zip frameworks_native-ff2ed70fa30f04b90dd1a2c06ec2319e157152d7.tar.gz frameworks_native-ff2ed70fa30f04b90dd1a2c06ec2319e157152d7.tar.bz2 |
color blindness enhancement
This is an attempt at improving the experience of
users with color vision impairement.
At this time this feature can only be enabled for
debugging:
adb shell service call SurfaceFlinger 1014 i32 PARAM
with PARAM:
0 : disabled
1 : protanomaly/protanopia simulation
2 : deuteranomaly/deuteranopia simulation
3 : tritanopia/tritanomaly simulation
11, 12, 13: same as above w/ attempted correction/enhancement
The enhancement algorithm tries to spread the "error"
such that tones that would otherwise appear similar can be
distinguished.
Bug: 9465644
Change-Id: I860f7eed0cb81f54ef9cf24ad78155b6395ade48
Diffstat (limited to 'services/surfaceflinger/Effects')
-rw-r--r-- | services/surfaceflinger/Effects/Daltonizer.cpp | 183 | ||||
-rw-r--r-- | services/surfaceflinger/Effects/Daltonizer.h | 59 |
2 files changed, 242 insertions, 0 deletions
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp new file mode 100644 index 0000000..f384ba4 --- /dev/null +++ b/services/surfaceflinger/Effects/Daltonizer.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Daltonizer.h" +#include <ui/mat4.h> + +namespace android { + +Daltonizer::Daltonizer() : + mType(deuteranomaly), mMode(simulation), mDirty(true) { +} + +Daltonizer::~Daltonizer() { +} + +void Daltonizer::setType(Daltonizer::ColorBlindnessTypes type) { + if (type != mType) { + mDirty = true; + mType = type; + } +} + +void Daltonizer::setMode(Daltonizer::Mode mode) { + if (mode != mMode) { + mDirty = true; + mMode = mode; + } +} + +const mat4& Daltonizer::operator()() { + if (mDirty) { + mDirty = false; + update(); + } + return mColorTransform; +} + +void Daltonizer::update() { + // converts a linear RGB color to the XYZ space + const mat4 rgb2xyz( 0.4124, 0.2126, 0.0193, 0, + 0.3576, 0.7152, 0.1192, 0, + 0.1805, 0.0722, 0.9505, 0, + 0 , 0 , 0 , 1); + + // converts a XYZ color to the LMS space. + const mat4 xyz2lms( 0.7328,-0.7036, 0.0030, 0, + 0.4296, 1.6975, 0.0136, 0, + -0.1624, 0.0061, 0.9834, 0, + 0 , 0 , 0 , 1); + + // Direct conversion from linear RGB to LMS + const mat4 rgb2lms(xyz2lms*rgb2xyz); + + // And back from LMS to linear RGB + const mat4 lms2rgb(inverse(rgb2lms)); + + // To simulate color blindness we need to "remove" the data lost by the absence of + // a cone. This cannot be done by just zeroing out the corresponding LMS component + // because it would create a color outside of the RGB gammut. + // Instead we project the color along the axis of the missing component onto a plane + // within the RGB gammut: + // - since the projection happens along the axis of the missing component, a + // color blind viewer perceives the projected color the same. + // - We use the plane defined by 3 points in LMS space: black, white and + // blue and red for protanopia/deuteranopia and tritanopia respectively. + + // LMS space red + const vec3& lms_r(rgb2lms[0].rgb); + // LMS space blue + const vec3& lms_b(rgb2lms[2].rgb); + // LMS space white + const vec3 lms_w((rgb2lms * vec4(1)).rgb); + + // To find the planes we solve the a*L + b*M + c*S = 0 equation for the LMS values + // of the three known points. This equation is trivially solved, and has for + // solution the following cross-products: + const vec3 p0 = cross(lms_w, lms_b); // protanopia/deuteranopia + const vec3 p1 = cross(lms_w, lms_r); // tritanopia + + // The following 3 matrices perform the projection of a LMS color onto the given plane + // along the selected axis + + // projection for protanopia (L = 0) + const mat4 lms2lmsp( 0.0000, 0.0000, 0.0000, 0, + -p0.y / p0.x, 1.0000, 0.0000, 0, + -p0.z / p0.x, 0.0000, 1.0000, 0, + 0 , 0 , 0 , 1); + + // projection for deuteranopia (M = 0) + const mat4 lms2lmsd( 1.0000, -p0.x / p0.y, 0.0000, 0, + 0.0000, 0.0000, 0.0000, 0, + 0.0000, -p0.z / p0.y, 1.0000, 0, + 0 , 0 , 0 , 1); + + // projection for tritanopia (S = 0) + const mat4 lms2lmst( 1.0000, 0.0000, -p1.x / p1.z, 0, + 0.0000, 1.0000, -p1.y / p1.z, 0, + 0.0000, 0.0000, 0.0000, 0, + 0 , 0 , 0 , 1); + + // We will calculate the error between the color and the color viewed by + // a color blind user and "spread" this error onto the healthy cones. + // The matrices below perform this last step and have been chosen arbitrarily. + + // The amount of correction can be adjusted here. + + // error spread for protanopia + const mat4 errp( 1.0, 0.7, 0.7, 0, + 0.0, 1.0, 0.0, 0, + 0.0, 0.0, 1.0, 0, + 0, 0, 0, 1); + + // error spread for deuteranopia + const mat4 errd( 1.0, 0.0, 0.0, 0, + 0.7, 1.0, 0.7, 0, + 0.0, 0.0, 1.0, 0, + 0, 0, 0, 1); + + // error spread for tritanopia + const mat4 errt( 1.0, 0.0, 0.0, 0, + 0.0, 1.0, 0.0, 0, + 0.7, 0.7, 1.0, 0, + 0, 0, 0, 1); + + const mat4 identity; + + // And the magic happens here... + // We construct the matrix that will perform the whole correction. + + // simulation: type of color blindness to simulate: + // set to either lms2lmsp, lms2lmsd, lms2lmst + mat4 simulation; + + // correction: type of color blindness correction (should match the simulation above): + // set to identity, errp, errd, errt ([0] for simulation only) + mat4 correction(0); + + // control: simulation post-correction (used for debugging): + // set to identity or lms2lmsp, lms2lmsd, lms2lmst + mat4 control; + switch (mType) { + case protanopia: + case protanomaly: + simulation = lms2lmsp; + if (mMode == Daltonizer::correction) + correction = errp; + break; + case deuteranopia: + case deuteranomaly: + simulation = lms2lmsd; + if (mMode == Daltonizer::correction) + correction = errd; + break; + case tritanopia: + case tritanomaly: + simulation = lms2lmst; + if (mMode == Daltonizer::correction) + correction = errt; + break; + } + + if (true) { + control = simulation; + } + + mColorTransform = lms2rgb * control * + (simulation * rgb2lms + correction * (rgb2lms - simulation * rgb2lms)); +} + +} /* namespace android */ diff --git a/services/surfaceflinger/Effects/Daltonizer.h b/services/surfaceflinger/Effects/Daltonizer.h new file mode 100644 index 0000000..e816437 --- /dev/null +++ b/services/surfaceflinger/Effects/Daltonizer.h @@ -0,0 +1,59 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SF_EFFECTS_DALTONIZER_H_ +#define SF_EFFECTS_DALTONIZER_H_ + +#include <ui/mat4.h> + +namespace android { + +class Daltonizer { +public: + enum ColorBlindnessTypes { + protanopia, // L (red) cone missing + deuteranopia, // M (green) cone missing + tritanopia, // S (blue) cone missing + protanomaly, // L (red) cone deficient + deuteranomaly, // M (green) cone deficient (most common) + tritanomaly // S (blue) cone deficient + }; + + enum Mode { + simulation, + correction + }; + + Daltonizer(); + ~Daltonizer(); + + void setType(ColorBlindnessTypes type); + void setMode(Mode mode); + + // returns the color transform to apply in the shader + const mat4& operator()(); + +private: + void update(); + + ColorBlindnessTypes mType; + Mode mMode; + bool mDirty; + mat4 mColorTransform; +}; + +} /* namespace android */ +#endif /* SF_EFFECTS_DALTONIZER_H_ */ |