使用XMLHttpRequest为RGB图像生成显性颜色 [英] Generate the Dominant Colors for an RGB image with XMLHttpRequest

查看:209
本文介绍了使用XMLHttpRequest为RGB图像生成显性颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

读者注意事项:这是一个很长的问题,但它需要一个背景来理解问题。

颜色量化技术通常用于获取图像的主色
一个着名的色彩量化库是 Leptonica 通过修改的中值切割量化(MMCQ)和八叉树量化(OQ)
Github的 Color-thief 是一个非常简单的MMCQ算法JavaScript实现:

The color quantization technique is commonly used to get the dominant colors of an image. One of the well-known libraries that do color quantization is Leptonica through the Modified Median Cut Quantization (MMCQ) and octree quantization (OQ) Github's Color-thief by @lokesh is a very simple implementation in JavaScript of the MMCQ algorithm:

var colorThief = new ColorThief();
colorThief.getColor(sourceImage);

从技术上讲,上的图片< img /> HTML元素支持< canvas /> 元素:

Technically, the image on a <img/> HTML element is backed on a <canvas/> element:

var CanvasImage = function (image) {
    this.canvas  = document.createElement('canvas');
    this.context = this.canvas.getContext('2d');

    document.body.appendChild(this.canvas);

    this.width  = this.canvas.width  = image.width;
    this.height = this.canvas.height = image.height;

    this.context.drawImage(image, 0, 0, this.width, this.height);
};

这是 TVML 的问题,我们稍后会看到。

And that is the problem with TVML, as we will see later on.

我最近发现的另一个实现与本文相关联使用imagemagick,awk和kmeans找到图像中的主色链接到使用python生成真棒linux桌面主题
作者发表了一篇关于使用python和k-means查找在那里使用的图像中的主色(对不起所有这些链接,但我正在追溯我的历史......)。

Another implementation I recently came to know was linked on this article Using imagemagick, awk and kmeans to find dominant colors in images that links to Using python to generate awesome linux desktop themes. The author posted an article about Using python and k-means to find the dominant colors in images that was used there (sorry for all those links, but I'm following back my History...).

作者非常高效,并且我在这里发布了一个JavaScript版本:使用JavaScript和k-means查找图像中的主色

The author was super productive, and added a JavaScript version too that I'm posting here: Using JavaScript and k-means to find the dominant colors in images

在这种情况下,我们生成主色图像,不是使用MMCQ(或OQ)算法,而是使用K-Means。
问题是图像必须是一个:

In this case, we are generating the dominant colors of an image, not using the MMCQ (or OQ) algorithm, but K-Means. The problem is that the image must be a as well:

<canvas id="canvas" style="display: none;" width="200" height="200"></canvas>

然后

function analyze(img_elem) {
        var ctx = document.getElementById('canvas').getContext('2d')
          , img = new Image();
        img.onload = function() {
          var results = document.getElementById('results');
          results.innerHTML = 'Waiting...';
          var colors = process_image(img, ctx)
            , p1 = document.getElementById('c1')
            , p2 = document.getElementById('c2')
            , p3 = document.getElementById('c3');
          p1.style.backgroundColor = colors[0];
          p2.style.backgroundColor = colors[1];
          p3.style.backgroundColor = colors[2];
          results.innerHTML = 'Done';
        }
        img.src = img_elem.src;
      }

这是因为Canvas有一个getContext()方法,可以显示2D图像绘图API - 请参阅 Canvas 2D API简介

This is because the Canvas has a getContext() method, that expose 2D image drawing APIs - see An introduction to the Canvas 2D API

此上下文ctx传递给图像处理函数

This context ctx is passed to the image processing function

  function process_image(img, ctx) {
    var points = [];
    ctx.drawImage(img, 0, 0, 200, 200);
    data = ctx.getImageData(0, 0, 200, 200).data;
    for (var i = 0, l = data.length; i < l;  i += 4) {
      var r = data[i]
        , g = data[i+1]
        , b = data[i+2];
      points.push([r, g, b]);
    }
    var results = kmeans(points, 3, 1)
     , hex = [];
    for (var i = 0; i < results.length; i++) {
      hex.push(rgbToHex(results[i][0]));
    }
    return hex;
  }

因此,您可以通过上下文在Canvas上绘制图像并获取图像数据:

So you can draw an image on the Canvas through the Context and get image data:

ctx.drawImage(img, 0, 0, 200, 200);
data = ctx.getImageData(0, 0, 200, 200).data;

另一个不错的解决方案是在CoffeeScript中, ColorTunes ,但这也使用了一个:

Another nice solution is in CoffeeScript, ColorTunes, but this is using a as well:

ColorTunes.getColorMap = function(canvas, sx, sy, w, h, nc) {
    var index, indexBase, pdata, pixels, x, y, _i, _j, _ref, _ref1;
    if (nc == null) {
      nc = 8;
    }
    pdata = canvas.getContext("2d").getImageData(sx, sy, w, h).data;
    pixels = [];
    for (y = _i = sy, _ref = sy + h; _i < _ref; y = _i += 1) {
      indexBase = y * w * 4;
      for (x = _j = sx, _ref1 = sx + w; _j < _ref1; x = _j += 1) {
        index = indexBase + (x * 4);
        pixels.push([pdata[index], pdata[index + 1], pdata[index + 2]]);
      }
    }
    return (new MMCQ).quantize(pixels, nc);
  };

但是,等等,我们没有< canvas /> 元素 TVML

But, wait, we have no <canvas/> element in TVML!

当然,还有像Objective-C这样的原生解决方案 ColorCube DominantColor - 这是使用K-means

Of course, there are native solutions like Objective-C ColorCube, DominantColor - this is using K-means

以及非常好的和可重用的 ColorArt

and the very nice and reusable ColorArt by @AaronBrethorst from CocoaControls.

尽管这可以通过本机在TVML应用程序中使用到JavaScriptCore桥 - 请参阅如何将TVML / JavaScriptCore连接到UIKit / Objective-C(Swift)?

Despite the fact that this could be used in a TVML application through a native to JavaScriptCore bridge - see How to bridge TVML/JavaScriptCore to UIKit/Objective-C (Swift)?

我的目标是完全在 TVJS 中完成这项工作, TVML

my aim is to make this work completely in TVJS and TVML.

Th最简单的MMCQ JavaScript实现不需要Canvas:请参阅 MMCQ的基本Javascript端口(修改后的中值切换量化) 通过 Nick Rabinowitz ,但需要图像的RGB数组:

The simplest MMCQ JavaScript implementation does not need a Canvas: see Basic Javascript port of the MMCQ (modified median cut quantization) by Nick Rabinowitz, but needs the RGB array of the image:

var cmap = MMCQ.quantize(pixelArray, colorCount);

取自HTML < canvas /> ,这就是它的原因!

that is taken from the HTML <canvas/> and that is the reason for it!

function createPalette(sourceImage, colorCount) {

    // Create custom CanvasImage object
    var image = new CanvasImage(sourceImage),
        imageData = image.getImageData(),
        pixels = imageData.data,
        pixelCount = image.getPixelCount();

    // Store the RGB values in an array format suitable for quantize function
    var pixelArray = [];
    for (var i = 0, offset, r, g, b, a; i < pixelCount; i++) {
        offset = i * 4;
        r = pixels[offset + 0];
        g = pixels[offset + 1];
        b = pixels[offset + 2];
        a = pixels[offset + 3];
        // If pixel is mostly opaque and not white
        if (a >= 125) {
            if (!(r > 250 && g > 250 && b > 250)) {
                pixelArray.push([r, g, b]);
            }
        }
    }

    // Send array to quantize function which clusters values
    // using median cut algorithm

    var cmap = MMCQ.quantize(pixelArray, colorCount);
    var palette = cmap.palette();

    // Clean up
    image.removeCanvas();

    return palette;
}

[问题]
如何在不使用HTML5 < canvas /> 的情况下生成RGB图像的主色,但在图像的 ByteArray 使用 XMLHttpRequest 获取?

[QUESTION] How to generate the dominant colors of a RGB image without using the HTML5 <canvas/>, but in pure JavaScript from an image's ByteArray fetched with XMLHttpRequest?

[更新]
我已将此问题发布到 Color-Thief github repo,调整RGB阵列计算到最新的代码库。
我试过的解决方案就是这个

[UPDATE] I have posted this question to Color-Thief github repo, adapting the RGB array calculations to the latest codebase. The solution I have tried was this

ColorThief.prototype.getPaletteNoCanvas = function(sourceImageURL, colorCount, quality, done) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', sourceImageURL, true);
  xhr.responseType = 'arraybuffer';
  xhr.onload = function(e) {
    if (this.status == 200) {

      var uInt8Array = new Uint8Array(this.response);
      var i = uInt8Array.length;
      var biStr = new Array(i);
      while (i--)
      { biStr[i] = String.fromCharCode(uInt8Array[i]);
      }

      if (typeof colorCount === 'undefined') {
          colorCount = 10;
      }
      if (typeof quality === 'undefined' || quality < 1) {
          quality = 10;
      }

      var pixels     = uInt8Array;
      var pixelCount = 152 * 152 * 4 // this should be width*height*4

      // Store the RGB values in an array format suitable for quantize function
      var pixelArray = [];
      for (var i = 0, offset, r, g, b, a; i < pixelCount; i = i + quality) {
          offset = i * 4;
          r = pixels[offset + 0];
          g = pixels[offset + 1];
          b = pixels[offset + 2];
          a = pixels[offset + 3];
          // If pixel is mostly opaque and not white
          if (a >= 125) {
              if (!(r > 250 && g > 250 && b > 250)) {
                  pixelArray.push([r, g, b]);
              }
          }
      }

      // Send array to quantize function which clusters values
      // using median cut algorithm
      var cmap    = MMCQ.quantize(pixelArray, colorCount);
      var palette = cmap? cmap.palette() : null;
      done.apply(this,[ palette ])

    } // 200
  };
  xhr.send();
}

但它不会返回正确的RGB颜色数组。

but it does not gives back the right RGB colors array.

[更新]
感谢我提出的所有建议。现在可以在 Github 上找到完整的示例,

[UPDATE] Thanks to all the suggestions I got it working. Now a full example is available on Github,

推荐答案

canvas元素被用作将图像解码为RGBA数组的便捷方式。您还可以使用纯JavaScript库来进行图像解码。

The canvas element is being used as a convenient way to decode the image into an RGBA array. You can also use pure JavaScript libraries to do the image decoding.

jpgjs 是一个JPEG解码器, pngjs 是一个PNG解码器。看起来JPEG解码器将与TVJS一起使用。然而,PNG解码器看起来像是在Node或Web浏览器环境中工作,因此您可能需要稍微调整一下。

jpgjs is a JPEG decoder and pngjs is a PNG decoder. It looks like the JPEG decoder will work with TVJS as is. The PNG decoder, however, looks like it's made to work in a Node or web browser environment, so you might have to tweak that one a bit.

这篇关于使用XMLHttpRequest为RGB图像生成显性颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆