如何使用 image-js 和 JavaScript 规范化图像(直方图拉伸)?

How do you normalize an image (histogram stretching) using image-js and JavaScript?

我正在使用 image-js

我查看了文档,但没有看到称为归一化或直方图拉伸的函数。但是我确实看到了一些直方图函数。我可以使用直方图函数对高度值的灰度 PNG 数组进行归一化吗?

图像数组是 0 - 255 范围内的高度值,黑色是最低高度,白色是最高。我正在使用此数组创建灰度高度图图像。

澄清一下:

归一化是指对图像颜色进行归一化,在本例中为灰度。喜欢这个项目,但使用 image-js https://www.npmjs.com/package/@jimp/plugin-normalize

这个 GIMP 文档中描述了我想要完成的规范化并在下面列出

来自 GIMP:8.10. Normalize

Normalize 命令缩放活动图层的亮度值,使最暗的点变黑,最亮的点变亮,而不改变其色调。对于暗淡或褪色的图像,这通常是一种“神奇修复”。 “标准化”适用于 RGB、灰度和索引图像的图层。

图像 normalization 也被称为 histogram stretching

选项 1

使用 D3.js 而不是 image-js 来完成这个任务,就像这个来源的代码

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
    canvas { width:50%; float: left}
  </style>
</head>
<body>
  <canvas id="imageOriginalCanvas"></canvas>
    <canvas id="imageCanvas"></canvas>

  <script>

    var cnv = document.getElementById('imageCanvas');
    var ctx = cnv.getContext('2d');
    var cnvori = document.getElementById('imageOriginalCanvas');
    var ctxori = cnvori.getContext('2d');

        var colorScales = {
      'linearBlackAndWhite': function(values){
        return d3.scale.linear()
          .domain(d3.extent(values))
          .range(['#000', '#fff']);
      },
      'histogramEqualize': function(values){
        var buckets = 100;
        var quantiles = d3.scale.quantile()
            .domain(values)
            .range(d3.range(buckets))
            .quantiles();

        var stopCount = quantiles.length;
        var linearScale = d3.scale.linear()
            .domain([0, stopCount - 1])
            .range([d3.rgb('rgb(0, 0, 0)'), d3.rgb('rgb(255, 255, 255)')]);
        
        var grayScale = d3.range(stopCount).map(function(d){
          return linearScale(d);
        });

        return d3.scale.linear().domain(quantiles).range(grayScale);
      }
    };

    var img = new Image;
    img.onload = function(){

      cnvori.width = cnv.width = img.width;
      cnvori.height = cnv.height = img.height;
      ctx.drawImage(img, 0, 0, img.width, img.height);
      ctxori.drawImage(img, 0, 0, img.width, img.height);

      var imgData = ctx.getImageData(0, 0, img.width, img.height);

      var rasterData = [];
      for(j = 0; j < (imgData.data.length / 4); j++){
        var brightness = d3.lab(d3.rgb(imgData.data[j * 4], 
                            imgData.data[j * 4 + 1], 
                            imgData.data[j * 4 + 2])).l;
        rasterData.push(imgData.data[j * 4] === 0 ? null : brightness);
      }

      var scale = colorScales.histogramEqualize(rasterData);

      for(j = 0; j < rasterData.length; j++){
        var scaledColor = scale(rasterData[j]);
        var color = d3.rgb(scaledColor);
        imgData.data[j * 4] = color.r;
        imgData.data[j * 4 + 1] = color.g;
        imgData.data[j * 4 + 2] = color.b;
        imgData.data[j * 4 + 3] = 255;
      }

      ctx.putImageData(imgData, 0, 0);
    };
    img.crossOrigin = '';   
    img.src = 'https://upload.wikimedia.org/wikipedia/commons/0/08/Unequalized_Hawkes_Bay_NZ.jpg';

  </script>
</body>

选项 2

来自js-objectdetect you could write you own function using image-js, better explained in this answer

的8位单通道图像直方图均衡算法
/**
* Equalizes the histogram of an unsigned 1-channel image with values
* in range [0, 255]. Corresponds to the equalizeHist OpenCV function.
*
* @param {Array} src 1-channel source image
* @param {Array} [dst] 1-channel destination image. If omitted, the
* result is written to src (faster)
* @return {Array} Destination image
*/
equalizeHistogram = function(src, dst) {
    var srcLength = src.length;
    if (!dst) { dst = src; }

    // Compute histogram and histogram sum:
    var hist = new Float32Array(256);
    var sum = 0;
    for (var i = 0; i < srcLength; ++i) {
        ++hist[~~src[i]];
        ++sum;
    }

    // Compute integral histogram:
    var prev = hist[0];
    for (var i = 1; i < 256; ++i) {
        prev = hist[i] += prev;
    }

    // Equalize image:
    var norm = 255 / sum;
    for (var i = 0; i < srcLength; ++i) {
        dst[i] = hist[~~src[i]] * norm;
    }
    return dst;
}