javascript - 自动调整亮度/对比度以从图像中读取文本

标签 javascript camera image-manipulation

我想知道是否有人可以指出正确的方向,以使用 javascript 自动调整从手机摄像头拍摄的图像的亮度/对比度,以便更轻松地从图像中读取文本。

感谢任何帮助,

非常感谢。

最佳答案

要自动调整图像,我们可以使用从图像生成的直方图,然后使用阈值找到黑/白点,用于将像素值缩放到两端的最大值。

在 HTML5 中,我们需要使用 canvas 元素来读取像素信息。

#构建直方图

直方图是图像中最能代表哪些值的概览。对于亮度对比度,我们会对亮度值(像素的感知亮度)感兴趣。

example histogram
示例亮度直方图

要计算亮度值,我们可以使用 REC.709(AKA BT.709,推荐,此处使用)或 REC.601 公式。

Y = 0.299 * R + 0.587 * G + 0.114 * B

我们需要将其转换为整数 (iluma = Math.round(luma);),否则我们将很难构建基于整数值 [0, 255 的直方图] 用于存储(参见下面的示例代码)。

确定使用哪个范围的策略可能会有所不同,但为简单起见,我们可以选择基于两端像素最小表示的阈值策略。

histogram threshold
显示示例阈值的红线

要根据阈值找到最暗的区域,我们将从左到右扫描,当我们获得高于阈值的亮度值时,将其用作最小值。如果我们到达中心(甚至只有 33%),我们可以中止并默认为 0。

对于最亮的,我们会做同样的事情,但如果没有找到阈值,则从右到左默认为 255。

您当然可以为每一端使用不同的阈值 - 这都是一个反复试验的游戏,直到您找到适合您的场景的值。

我们现在应该有两个值代表最小-最大范围:

min-max range
基于阈值的最小-最大范围

#缩放一般亮度级别

首先根据min-max范围计算出我们需要使用的比例因子:

scale = 255 / (max - min) * 2

我们总是会从每个组件中减去 min,即使这意味着它会被裁剪(如果 < 0 则将值设置为 0)。当减去时,我们使用比例因子缩放每个分量值。最后的 x2 是为了补偿亮度和实际 RGB 值之间的差异。像其他值一样使用这个值(这里只是一个任意示例)。

我们对每个像素中的每个组件执行此操作(0 剪辑和缩放):

component = max(0, component - min) * scale

当图像数据被放回时,对比度应该是基于给定阈值的最大值。

#提示

您不必使用整个图像位图来分析直方图。如果您处理按比例缩小到较小表示的大型图像源 - 您不需要太多,因为我们追求的是最亮/最暗的区域,而不是单个像素。

您可以使用自身的混合模式使图像变亮和增加对比度,例如multiplylightenhard-light/soft-light 等(<= IE11 不支持混合模式)。针对这些调整公式,然后进行实验。

#例子

这适用于显示上述技术的缓冲区。存在更复杂和准确的方法,但这是作为概念验证给出的(根据 CC-3.0-by-sa, attribution required 获得许可)。

它以 10% 的阈值开始。使用 slider 查看使用阈值的结果差异。可以通过此处显示的方法以外的其他方法计算阈值。实验!

使用整页运行代码段 -

var ctx = c.getContext("2d"),
    img = new Image;  // some demo image

img.crossOrigin ="";  // needed for demo
img.onload = setup;
img.src = "//i.imgur.com/VtNwHbU.jpg";

function setup() {
  // set canvas size based on image
  c.width = this.width;
  c.height = this.height;
    
  // draw in image to canvas
  ctx.drawImage(this, 0, 0);

  // keep the original for comparsion and for demo
  org.src = c.toDataURL();

  process(this, +tv.value);
}

function process(img, thold) {   //thold = % of hist max

  var width = img.width, height = img.height,
      idata, data,
      i, min = -1, max = -1,             // to find min-max
      maxH = 0,                          // to find scale of histogram
      scale,
      hgram = new Uint32Array(width);    // histogram buffer (or use Float32)
    
  // get image data
  idata = ctx.getImageData(0, 0, img.width, img.height); // needed for later
  data = idata.data;  // the bitmap itself
    
  // get lumas and build histogram
  for(i = 0; i < data.length; i += 4) {
    var luma = Math.round(rgb2luma(data, i));
    hgram[luma]++;   // add to the luma bar (and why we need an integer)
  }
    
  // find tallest bar so we can use that to scale threshold
  for(i = 0; i < width; i++) {
     if (hgram[i] > maxH) maxH = hgram[i];
  }

  // use that for threshold
  thold *= maxH;
    
  // find min value
  for(i = 0; i < width * 0.5; i++) {
    if (hgram[i] > thold) {
      min = i;
      break;
    }
  }
  if (min < 0) min = 0;             // not found, set to default 0

  // find max value
  for(i = width - 1; i > width * 0.5; i--) {
    if (hgram[i] > thold) {
      max = i;
      break;
    }
  }
  if (max < 0) max = 255;           // not found, set to default 255

  scale = 255 / (max - min) * 2;    // x2 compensates (play with value)
  out.innerHTML = "Min: " + min + " Max: " + max + 
    " Scale: " + scale.toFixed(1) + "x";
    
  // scale all pixels
  for(i = 0; i < data.length; i += 4) {
    data[i  ] = Math.max(0, data[i] - min) * scale;
    data[i+1] = Math.max(0, data[i+1] - min) * scale;
    data[i+2] = Math.max(0, data[i+2] - min) * scale;
  }
    
  ctx.putImageData(idata, 0, 0)
}

tv.oninput = function() {
  v.innerHTML = (tv.value * 100).toFixed(0) + "%";
  ctx.drawImage(img, 0, 0);
  process(img, +tv.value)
};

function rgb2luma(px, pos) {
  return px[pos] * 0.299 + px[pos+1] * 0.587 + px[pos+2] * 0.114
}
<label>Threshold:
<input id=tv type=range min=0 max=1 step= 0.01 value=0.1></label>
<span id=v>10%</span><br>
<canvas id=c></canvas><br>
<div id=out></div>
<h3>Original:</h3>
<img id=org>

关于javascript - 自动调整亮度/对比度以从图像中读取文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37986669/

相关文章:

ios - 如何创建样本缓冲区(CMSampleBufferRef)的实例?

opencv - 使用cv::SolvePnP进行外部校准

vector - 三.js 设置和读取相机外观矢量

c# - 使用中轴变换的图像骨架化

javascript - 使用三 Angular 形在 WebGL 中制作网格平面

javascript - 面向对象的Javascript : Should Private Functions Be Added to Class Prototype?

javascript - CSS : round_div is not responsive to its parent div

django - 保存时调整图像大小

php 图片从png创建

javascript - 当 Iframe 内容位于不同域时,如何根据其内容更改 Iframe 高度?