📜  色调映射三个js - Javascript(1)

📅  最后修改于: 2023-12-03 15:11:48.519000             🧑  作者: Mango

色调映射三个js

在图形处理领域,色调映射(Tone mapping)是一种将高动态范围(HDR)图像映射到低动态范围(LDR)显示器上的过程。

下面介绍三个常用的 JavaScript 库来实现色调映射。

1. Reinhard Tone Mapping

Reinhard Tone Mapping 是最常用和最简单的映射方法之一,它通过简单的缩放和偏移图像的亮度和色度来实现。以下是使用 Reinhard Tone Mapping 的 JavaScript 代码:

function mapReinhard(image, key, phi) {
  var ldr = [];

  var sum = 0.0;
  var pixels = image.width * image.height;
  for (var i = 0; i < pixels; i++) {
    var r = image.data[i * 4];
    var g = image.data[i * 4 + 1];
    var b = image.data[i * 4 + 2];

    var lum = 0.27 * r + 0.67 * g + 0.06 * b;
    sum += Math.log(lum + 0.00001);
  }
  var lavg = Math.exp(sum / pixels);

  var scale = key / lavg;
  var w = 1.0 / phi;

  for (var i = 0; i < pixels; i++) {
    var r = image.data[i * 4];
    var g = image.data[i * 4 + 1];
    var b = image.data[i * 4 + 2];

    var lum = 0.27 * r + 0.67 * g + 0.06 * b;
    var mapped = (lum * scale) / (1.0 + lum * scale);

    var rnew = r * mapped / lum;
    var gnew = g * mapped / lum;
    var bnew = b * mapped / lum;

    var color = [rnew, gnew, bnew];
    for (var j = 0; j < 3; j++) {
      color[j] = Math.pow(color[j], w);
    }

    ldr.push(color[0] * 255);
    ldr.push(color[1] * 255);
    ldr.push(color[2] * 255);
    ldr.push(255);
  }

  return new ImageData(new Uint8ClampedArray(ldr), image.width, image.height);
}
2. Fattal Tone Mapping

Fattal Tone Mapping 是一种较为复杂的方法,它被证明在视觉上是一种自然的映射方法。以下是使用 Fattal Tone Mapping 的 JavaScript 代码:

function mapFattal(image, alpha, beta, saturation) {
  var MAX_ITERATION = 50;

  var ldr = [];
  var logLuminance = [];

  var pixels = image.width * image.height;
  for (var i = 0; i < pixels; i++) {
    var r = image.data[i * 4];
    var g = image.data[i * 4 + 1];
    var b = image.data[i * 4 + 2];

    var lum = 0.27 * r + 0.67 * g + 0.06 * b;
    logLuminance.push(Math.log(lum + 0.00001));
  }

  var A = Math.max.apply(null, logLuminance);
  var t = 1.0;

  for (var n = 0; n < MAX_ITERATION; n++) {
    var denominator = 0.0;
    var Luminance = [];

    for (var i = 0; i < pixels; i++) {
      var r = image.data[i * 4];
      var g = image.data[i * 4 + 1];
      var b = image.data[i * 4 + 2];

      var lum = 0.27 * r + 0.67 * g + 0.06 * b;

      var logDelta = Math.log(lum + 0.00001) - A - Math.log(t);
      var weight = 1.0 / (1.0 + logDelta * logDelta);

      denominator += weight;
      Luminance.push(weight * lum);
    }

    var Lw = Luminance.reduce(function (a, b) {
      return a + b;
    }, 0) / denominator;
    var Ld = alpha * logLuminance.map(function (x) {
      return x - A + beta * Math.log(Lw);
    });
    var Ls = logLuminance.map(function (x) {
      return x - Math.min.apply(null, Ld);
    });
    var LFinal = Ls.map(function (x) {
      return saturation * x / (x + 1.0);
    });

    for (var i = 0; i < pixels; i++) {
      var r = image.data[i * 4];
      var g = image.data[i * 4 + 1];
      var b = image.data[i * 4 + 2];

      var lum = 0.27 * r + 0.67 * g + 0.06 * b;

      var logDelta = Math.log(lum + 0.00001) - A - Math.log(t);
      var weight = 1.0 / (1.0 + logDelta * logDelta);

      var mapped = LFinal[i] / lum;

      var rnew = r * mapped / lum;
      var gnew = g * mapped / lum;
      var bnew = b * mapped / lum;

      ldr.push(rnew * 255);
      ldr.push(gnew * 255);
      ldr.push(bnew * 255);
      ldr.push(255);
    }

    t = Math.exp(Math.log(t) - Math.log(Lw / (alpha * Ld.reduce(function (a, b) {
      return a + b;
    }, 0))));
  }

  return new ImageData(new Uint8ClampedArray(ldr), image.width, image.height);
}
3. Mantiuk Tone Mapping

Mantiuk Tone Mapping 是一种基于科学数据和人类感知的算法,它在将 HDR 图像映射到 LDR 显示器上时表现出色彩和亮度的平衡。以下是使用 Mantiuk Tone Mapping 的 JavaScript 代码:

function mapMantiuk(image, alpha, beta, delta) {
  var ldr = [];

  var w = image.width;
  var h = image.height;
  var pixels = w * h;

  var luminance = new Float32Array(pixels);
  var chrominance = new Float32Array(pixels * 2);
  for (var i = 0; i < pixels; i++) {
    var r = image.data[i * 4];
    var g = image.data[i * 4 + 1];
    var b = image.data[i * 4 + 2];

    luminance[i] = 0.27 * r + 0.67 * g + 0.06 * b;
    chrominance[i * 2] = r;
    chrominance[i * 2 + 1] = b;
  }

  var LW = Math.pow(luminance.reduce(function (a, b) {
    return a + b;
  }, 0) / (w * h), alpha);

  var Lv = new Float32Array(pixels);
  for (var i = 0; i < pixels; i++) {
    Lv[i] = delta * luminance[i] / (1 + LW);
  }

  var Lwhite = Math.pow(Math.max.apply(null, luminance), alpha);

  var ldr = new Uint8ClampedArray(pixels * 4);
  for (var i = 0; i < pixels; i++) {
    var lum = Math.pow(luminance[i], alpha);
    lum = lum * (1 + lum / Math.pow(Lwhite, alpha)) / (1 + lum);
    lum = lum * (1 + Lv[i] / luminance[i]);
    lum = lum * 0.18 / luminance[i];
    lum = lum * beta;

    var r = chrominance[i * 2];
    var g = luminance[i];
    var b = chrominance[i * 2 + 1];
    var norm = Math.sqrt(r * r + b * b);
    r = r / norm;
    b = b / norm;

    r = (r + 1) / 2;
    g = (g - 0.05) / 0.95;
    b = (b + 1) / 2;

    ldr[i * 4] = Math.floor(r * 255);
    ldr[i * 4 + 1] = Math.floor(g * 255);
    ldr[i * 4 + 2] = Math.floor(b * 255);
    ldr[i * 4 + 3] = 255;
  }

  return new ImageData(ldr, w, h);
}

以上是三个常用的 JavaScript 库实现色调映射。根据实际需求,选择适合的色调映射方法可以提高图像的显示质量。