簡體   English   中英

自動調整亮度/對比度以讀取圖像中的文本

[英]Auto adjust brightness/contrast to read text from images

我想知道是否有人可以向我指出正確的方向,以使用javascript自動調整從手機攝像頭拍攝的圖像的亮度/對比度,從而使從圖像中讀取文本更加容易。

感謝任何幫助,

非常感謝。

為了自動調整圖像,我們可以使用從圖像生成的直方圖,然后使用閾值找到黑點/白點,以將像素值縮放到相對兩端的最大值。

在HTML5中,我們需要使用canvas元素才能讀取像素信息。

建立直方圖

直方圖是圖像中最能代表其值的概覽。 對於亮度對比,我們將對亮度值(像素的感知亮度)感興趣。

直方圖示例
亮度直方圖示例

要計算亮度值,我們可以使用REC.709(建議使用AKA BT.709,此處使用)或REC.601公式。

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

我們需要將其轉換為整數( iluma = Math.round(luma); ),否則我們將很難構建基於整數值[0,255]進行存儲的直方圖(請參見下面的示例代碼)。

確定使用哪個范圍的策略可能會有所不同,但是為簡單起見,我們可以基於兩端像素的最小表示量選擇閾值策略。

直方圖閾值
紅線顯示示例閾值

為了根據閾值找到最暗的顏色,我們將從左到右掃描,當我們得到一個高於閾值的亮度值時,將其用作最小值。 如果我們到達中心(或什至只有33%),我們可能會中止並默認為0。

對於最亮的,我們將執行相同的操作,但是從右到左,如果未找到閾值,則默認為255。

當然,您可以為每個端點使用不同的閾值-在找到適合自己情況的東西之前,都需要反復試驗這些閾值。

現在,我們應該有兩個表示最小-最大范圍的值:

最小-最大范圍
基於閾值的最小-最大范圍

縮放一般亮度水平

首先根據最小-最大范圍計算我們需要使用的比例因子:

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-sa許可,需要提供署名 )。

它以10%的閾值開始。 使用滑塊使用閾值查看結果差異。 閾值可以通過除此處所示之外的其他方法來計算。 實驗!

使用整頁運行代碼段-

 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> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM