Added new image filters that allow an image to be viewed in colorblind modes, allow cartographers to see what their maps would appear like to a color blind person
This commit is contained in:
parent
6b05f19c38
commit
6245790e72
4 changed files with 145 additions and 2 deletions
|
@ -674,6 +674,81 @@ void apply_filter(Src & src, scale_hsla const& transform)
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Src, typename ColorBlindFilter>
|
||||
void color_blind_filter(Src & src, ColorBlindFilter const& op)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
rgba8_view_t src_view = rgba8_view(src);
|
||||
|
||||
for (std::ptrdiff_t y = 0; y < src_view.height(); ++y)
|
||||
{
|
||||
rgba8_view_t::x_iterator src_it = src_view.row_begin(static_cast<long>(y));
|
||||
for (std::ptrdiff_t x = 0; x < src_view.width(); ++x)
|
||||
{
|
||||
// formula taken from boost/gil/color_convert.hpp:rgb_to_luminance
|
||||
uint8_t & r = get_color(src_it[x], red_t());
|
||||
uint8_t & g = get_color(src_it[x], green_t());
|
||||
uint8_t & b = get_color(src_it[x], blue_t());
|
||||
double dr = static_cast<double>(r);
|
||||
double dg = static_cast<double>(g);
|
||||
double db = static_cast<double>(b);
|
||||
// RGB to LMS matrix conversion
|
||||
double L = (17.8824 * dr) + (43.5161 * dg) + (4.11935 * db);
|
||||
double M = (3.45565 * dr) + (27.1554 * dg) + (3.86714 * db);
|
||||
double S = (0.0299566 * dr) + (0.184309 * dg) + (1.46709 * db);
|
||||
// Simulate color blindness
|
||||
double l = (op.f0 * L) + (op.f1 * M) + (op.f2 * S);
|
||||
double m = (op.f3 * L) + (op.f4 * M) + (op.f5 * S);
|
||||
double s = (op.f6 * L) + (op.f7 * M) + (op.f8 * S);
|
||||
// LMS to RGB matrix conversion
|
||||
double R = (0.0809444479 * l) + (-0.130504409 * m) + (0.116721066 * s);
|
||||
double G = (-0.0102485335 * l) + (0.0540193266 * m) + (-0.113614708 * s);
|
||||
double B = (-0.000365296938 * l) + (-0.00412161469 * m) + (0.693511405 * s);
|
||||
// Isolate invisible colors to color vision deficiency (calculate error matrix)
|
||||
R = dr - R;
|
||||
G = dg - G;
|
||||
B = db - B;
|
||||
// Shift colors towards visible spectrum (apply error modifications)
|
||||
double RR = (0.0 * R) + (0.0 * G) + (0.0 * B);
|
||||
double GG = (0.7 * R) + (1.0 * G) + (0.0 * B);
|
||||
double BB = (0.7 * R) + (0.0 * G) + (1.0 * B);
|
||||
// Add compensation to original values
|
||||
R = RR + dr;
|
||||
G = GG + dg;
|
||||
B = BB + db;
|
||||
// Clamp values
|
||||
if(R < 0.0) R = 0.0;
|
||||
if(R > 255.0) R = 255.0;
|
||||
if(G < 0.0) G = 0.0;
|
||||
if(G > 255.0) G = 255.0;
|
||||
if(B < 0.0) B = 0.0;
|
||||
if(B > 255.0) B = 255.0;
|
||||
r = static_cast<uint8_t>(R);
|
||||
g = static_cast<uint8_t>(G);
|
||||
b = static_cast<uint8_t>(B);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, color_blind_protanope const& op)
|
||||
{
|
||||
color_blind_filter(src, op);
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, color_blind_deuteranope const& op)
|
||||
{
|
||||
color_blind_filter(src, op);
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, color_blind_tritanope const& op)
|
||||
{
|
||||
color_blind_filter(src, op);
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, gray const& /*op*/)
|
||||
{
|
||||
|
|
|
@ -80,6 +80,12 @@ image_filter_grammar<Iterator,ContType>::image_filter_grammar()
|
|||
|
|
||||
lit("invert") >> no_args [push_back(_val,construct<mapnik::filter::invert>())]
|
||||
|
|
||||
lit("color-blind-protanope") >> no_args [push_back(_val,construct<mapnik::filter::color_blind_protanope>())]
|
||||
|
|
||||
lit("color-blind-deuteranope") >> no_args [push_back(_val,construct<mapnik::filter::color_blind_deuteranope>())]
|
||||
|
|
||||
lit("color-blind-tritanope") >> no_args [push_back(_val,construct<mapnik::filter::color_blind_tritanope>())]
|
||||
|
|
||||
agg_blur_filter(_val)
|
||||
|
|
||||
scale_hsla_filter(_val)
|
||||
|
|
|
@ -55,6 +55,47 @@ struct x_gradient : image_filter_base {};
|
|||
struct y_gradient : image_filter_base {};
|
||||
struct invert : image_filter_base {};
|
||||
|
||||
|
||||
// http://vision.psychol.cam.ac.uk/jdmollon/papers/colourmaps.pdf
|
||||
struct color_blind_protanope : image_filter_base
|
||||
{
|
||||
const double f0 = 0.0;
|
||||
const double f1 = 2.02344;
|
||||
const double f2 = -2.52581;
|
||||
const double f3 = 0.0;
|
||||
const double f4 = 1.0;
|
||||
const double f5 = 0.0;
|
||||
const double f6 = 0.0;
|
||||
const double f7 = 0.0;
|
||||
const double f8 = 1.0;
|
||||
};
|
||||
|
||||
struct color_blind_deuteranope : image_filter_base
|
||||
{
|
||||
const double f0 = 1.0;
|
||||
const double f1 = 0.0;
|
||||
const double f2 = 0.0;
|
||||
const double f3 = 0.494207;
|
||||
const double f4 = 0.0;
|
||||
const double f5 = 1.24827;
|
||||
const double f6 = 0.0;
|
||||
const double f7 = 0.0;
|
||||
const double f8 = 1.0;
|
||||
};
|
||||
|
||||
struct color_blind_tritanope : image_filter_base
|
||||
{
|
||||
const double f0 = 1.0;
|
||||
const double f1 = 0.0;
|
||||
const double f2 = 0.0;
|
||||
const double f3 = 0.0;
|
||||
const double f4 = 1.0;
|
||||
const double f5 = 0.0;
|
||||
const double f6 = -0.395913;
|
||||
const double f7 = 0.801109;
|
||||
const double f8 = 0.0;
|
||||
};
|
||||
|
||||
struct agg_stack_blur : image_filter_base
|
||||
{
|
||||
agg_stack_blur(unsigned rx_, unsigned ry_)
|
||||
|
@ -169,7 +210,10 @@ using filter_type = util::variant<filter::blur,
|
|||
filter::invert,
|
||||
filter::scale_hsla,
|
||||
filter::colorize_alpha,
|
||||
filter::color_to_alpha>;
|
||||
filter::color_to_alpha,
|
||||
filter::color_blind_protanope,
|
||||
filter::color_blind_deuteranope,
|
||||
filter::color_blind_tritanope>;
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, blur)
|
||||
{
|
||||
|
@ -247,6 +291,24 @@ inline std::ostream& operator<< (std::ostream& os, invert)
|
|||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, color_blind_protanope)
|
||||
{
|
||||
os << "color-blind-protanope";
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, color_blind_deuteranope)
|
||||
{
|
||||
os << "color-blind-deuteranope";
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, color_blind_tritanope)
|
||||
{
|
||||
os << "color-blind-tritanope";
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, colorize_alpha const& filter)
|
||||
{
|
||||
os << "colorize-alpha(";
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e3d79ed493485afbb5c79cd90913c8db488561b6
|
||||
Subproject commit 22d44804277eec9e62964b4059c71d9f001747c7
|
Loading…
Reference in a new issue