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

Time:10-20

I am using image-js.

I have looked at the documentation and I do not see a function called normalize or histogram stretching. However I do see some histogram functions. Can I use the histogram functions to do a normalization on a grayscale PNG array of height values?

The image array is values of heights from range 0 - 255 black being lowest height white highest. I am using this array to create a grayscale heightmap image.

Clarify:

By normalize I mean normalizing an image colors in this case the grayscale. Like this project but using image-js https://www.npmjs.com/package/@jimp/plugin-normalize

The normalization I want to accomplished is described in this GIMP doc and listed below

From GIMP: 8.10. Normalize

The Normalize command scales the brightness values of the active layer so that the darkest point becomes black and the brightest point becomes as bright as possible, without altering its hue. This is often a “magic fix” for images that are dim or washed out. “Normalize” works on layers from RGB, Grayscale, and Indexed images.

CodePudding user response:

Image normalization is called also histogram stretching

Option 1

Use D3.js instead of image-js for this task, like tis code from this source

<!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>

Option 2

From this histogram equalization algorithm for 8-bit single channel images taken from js-objectdetect you could write you own function using image-js, better explained in this answer

/**
* 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;
}
  • Related