changeset 1578:57a4ee52ad69 background-mode

Make nearby-colour matching a bit more sophisticated, with slightly better algorithm (we think?) and ability to insist on dark/light background
author Chris Cannam
date Fri, 24 Jan 2020 12:40:07 +0000
parents 2c974337f306
children 85f04c956f03
files layer/ColourDatabase.cpp layer/ColourDatabase.h
diffstat 2 files changed, 48 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/layer/ColourDatabase.cpp	Thu Jan 23 15:43:51 2020 +0000
+++ b/layer/ColourDatabase.cpp	Fri Jan 24 12:40:07 2020 +0000
@@ -88,17 +88,44 @@
 }
 
 int
-ColourDatabase::getNearbyColourIndex(QColor col) const
+ColourDatabase::getNearbyColourIndex(QColor col, WithBackgroundMode mode) const
 {
-    int index = 0;
+    int index = -1;
     int closestIndex = -1;
-    int closestDistance = 0;
+    double closestDistance = 0;
 
     for (auto &c: m_colours) {
-        int distance =
-            std::abs(col.red() - c.colour.red()) +
-            std::abs(col.green() - c.colour.green()) +
-            std::abs(col.blue() - c.colour.blue());
+
+        ++index;
+
+        if (mode == WithDarkBackground && !c.darkbg) {
+#ifdef DEBUG_COLOUR_DATABASE
+            SVDEBUG << "getNearbyColourIndex: dark background requested, skipping " << c.colour.name() << endl;
+#endif
+            continue;
+        }
+        if (mode == WithLightBackground && c.darkbg) {
+#ifdef DEBUG_COLOUR_DATABASE
+            SVDEBUG << "getNearbyColourIndex: light background requested, skipping " << c.colour.name() << endl;
+#endif
+            continue;
+        }
+
+        // This distance formula is "one of the better low-cost
+        // approximations" according to
+        // https://en.wikipedia.org/w/index.php?title=Color_difference&oldid=936888327
+        
+        double r1 = col.red(), r2 = c.colour.red();
+        double g1 = col.green(), g2 = c.colour.green();
+        double b1 = col.blue(), b2 = c.colour.blue();
+
+        double rav = (r1 + r2) / 2.0;
+        double rterm = (2.0 + rav / 256.0) * (r1 - r2) * (r1 - r2);
+        double gterm = 4.0 * (g1 - g2) * (g1 - g2);
+        double bterm = (2.0 + (255 - rav) / 256.0) * (b1 - b2) * (b1 - b2);
+        
+        double distance = sqrt(rterm + gterm + bterm);
+
 #ifdef DEBUG_COLOUR_DATABASE
         SVDEBUG << "getNearbyColourIndex: comparing " << c.colour.name()
                 << " to " << col.name() << ": distance = " << distance << endl;
@@ -110,7 +137,6 @@
             SVDEBUG << "(this is the best so far)" << endl;
 #endif
         }
-        ++index;
     }
 
 #ifdef DEBUG_COLOUR_DATABASE
--- a/layer/ColourDatabase.h	Thu Jan 23 15:43:51 2020 +0000
+++ b/layer/ColourDatabase.h	Fri Jan 24 12:40:07 2020 +0000
@@ -71,13 +71,20 @@
      */
     bool haveColour(QColor c) const;
 
+    enum WithBackgroundMode {
+        WithAnyBackground,
+        WithDarkBackground,
+        WithLightBackground
+    };
+    
     /**
      * Return the index of the colour in the database that is closest
-     * to the given one, by some simplistic measure (Manhattan
-     * distance in RGB space). This always returns some valid index,
-     * unless the database is empty, in which case it returns -1.
+     * to the given one, by some simple measure. This always returns
+     * some valid index, unless the database is empty, in which case
+     * it returns -1.
      */
-    int getNearbyColourIndex(QColor c) const;
+    int getNearbyColourIndex(QColor c,
+                             WithBackgroundMode mode = WithAnyBackground) const;
 
     /**
      * Add a colour to the database, with the associated name. Return
@@ -110,9 +117,9 @@
 
     /**
      * Return a colour that contrasts with the one at index c,
-     * according to some simplistic algorithm. The returned colour is
-     * not necessarily in the database; pass it to
-     * getNearbyColourIndex if you need one that is.
+     * according to some simple algorithm. The returned colour is not
+     * necessarily in the database; pass it to getNearbyColourIndex if
+     * you need one that is.
      */
     QColor getContrastingColour(int c) const;