Programmatically determine best foreground color to be placed onto an image

前端 未结 3 1131
[愿得一人]
[愿得一人] 2021-02-02 00:11

I\'m working on a node module that will return the color that will look best onto a background image which of course will have multiple colors.

Here\'s what I have so fa

3条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-02-02 00:53

    Sounds like an interesting problem to have!

    Each algorithm you're using to generate colors likely has a bias toward certain colors in their respective random color algorithms.

    What you're likely seeing is the end result of that bias for each. Both are selecting darker and lighter colors independently.

    It may make more sense to keep a hash of common colors and use that hash as opposed to using randomly generated colors.

    Either way your 'fitness' check, the algorithm that checks to see which color has the best average contrast is picking lighter and darker colors for both color sets. This makes sense, lighter images should have darker backgrounds and darker images should have lighter backgrounds.

    Although you don't explicitly say, I'd bet my bottom dollar you're getting dark background for lighter average images and brighter backgrounds on darker images.

    Alternatively rather than using a hash of colors, you could generate multiple random color palettes and combine the result sets to average them out.

    Or rather than taking the 6 most commonly occurring colors, why not take the overall color gradient and try against that?

    I've put together an example where I get the most commonly occurring color and invert it to get the complementary color. This in theory at least should provide a good contrast ratio for the image as a whole.

    Using the most commonly occurring color in the image seems to work quite well. as outlined in my example below. This is a similar technique that Blindman67 uses without the massive bloating of including libraries and performing un-necessary steps, I borrowed the same images that Blindman67 uses for a fair comparison of the result set.

    See Get average color of image via Javascript for getting average color (getAverageRGB() function written by James).

    var images = [
      "https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Cistothorus_palustris_CT.jpg/450px-Cistothorus_palustris_CT.jpg",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Black-necked_Stilt_%28Himantopus_mexicanus%29%2C_Corte_Madera.jpg/362px-Black-necked_Stilt_%28Himantopus_mexicanus%29%2C_Corte_Madera.jpg",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Daurian_redstart_at_Daisen_Park_in_Osaka%2C_January_2016.jpg/573px-Daurian_redstart_at_Daisen_Park_in_Osaka%2C_January_2016.jpg",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Myioborus_torquatus_Santa_Elena.JPG/675px-Myioborus_torquatus_Santa_Elena.JPG",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Great_tit_side-on.jpg/645px-Great_tit_side-on.jpg",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Sarcoramphus_papa_%28K%C3%B6nigsgeier_-_King_Vulture%29_-_Weltvogelpark_Walsrode_2013-01.jpg/675px-Sarcoramphus_papa_%28K%C3%B6nigsgeier_-_King_Vulture%29_-_Weltvogelpark_Walsrode_2013-01.jpg",
    ];
    
    // append images
    for (var i = 0; i < images.length; i++) {
      var img = document.createElement('img'),
    div = document.createElement('div');
      img.crossOrigin = "Anonymous";
    
      img.style.border = '1px solid black';
      img.style.margin = '5px';
    
      div.appendChild(img);
    
      document.body.appendChild(div);
      (function(img, div) {
    img.addEventListener('load', function() {
      var avg = getAverageRGB(img);
      div.style = 'background: rgb(' + avg.r + ',' + avg.g + ',' + avg.b + ')';
      img.style.height = '128px';
      img.style.width = '128px';
    });
    img.src = images[i];
      }(img, div));
    }
    
    function getAverageRGB(imgEl) { // not my work, see http://jsfiddle.net/xLF38/818/
      var blockSize = 5, // only visit every 5 pixels
    defaultRGB = {
      r: 0,
      g: 0,
      b: 0
    }, // for non-supporting envs
    canvas = document.createElement('canvas'),
    context = canvas.getContext && canvas.getContext('2d'),
    data, width, height,
    i = -4,
    length,
    rgb = {
      r: 0,
      g: 0,
      b: 0
    },
    count = 0;
    
      if (!context) {
    return defaultRGB;
      }
    
      height = canvas.height = imgEl.offsetHeight || imgEl.height;
      width = canvas.width = imgEl.offsetWidth || imgEl.width;
    
      context.drawImage(imgEl, 0, 0);
      try {
    data = context.getImageData(0, 0, width, height);
      } catch (e) {
    return defaultRGB;
      }
    
      length = data.data.length;
    
      while ((i += blockSize * 4) < length) {
    ++count;
    rgb.r += data.data[i];
    rgb.g += data.data[i + 1];
    rgb.b += data.data[i + 2];
      }
    
      // ~~ used to floor values
      rgb.r = ~~(rgb.r / count);
      rgb.g = ~~(rgb.g / count);
      rgb.b = ~~(rgb.b / count);
    
      return rgb;
    }

提交回复
热议问题