2013-10-06 243 views
1

我有以下功能來使圖像變亮/變暗。HTML5畫布增強圖像

<script> 
brightness = function(delta) { 
    return function (pixels, args) { 
     var d = pixels.data; 
     for (var i = 0; i < d.length; i += 4) { 
      d[i] += delta;  // red 
      d[i + 1] += delta; // green 
      d[i + 2] += delta; // blue 
     } 
     return pixels; 
    }; 
}; 
</script> 

只是想嘗試一些更有趣的,是有可能,我可以執行自動增強圖像?我的意思是使照片中的特定區域變亮/變暗。我應該如何檢測像素是否黑暗,然後我應該稍微增亮它?謝謝。

+2

_「我應該如何去檢測像素是否黑暗,例如」__首先_defining_首先考慮一個「黑暗」像素,然後檢查它的顏色值...? – CBroe

+0

是否有一個0到xx的暗色或標準範圍?到255爲明亮的顏色?我應該只修改所有的黑暗和明亮,還是應該修改所有像素的某些值?只是想知道是否有人在這方面有一些專業知識。 – Sky

回答

2

你想要做的是修改圖像的動態。
因此,對於歸一化像素的亮度範圍從0.0到1.0,您必須決定將應用於每個像素亮度的變換函數。

你尋求將不得不提高低光度(接近0°),並保持相當相同的亮度的高亮度,(接近1)的功能。

這裏有一個(。典型)transfert函數的例子:
enter image description here

所以你要伽瑪> 1.
你在這裏看到的,例如,如果輸入的亮度爲0.2時,輸出亮度爲0.45,這是原始值的兩倍多。
爲0.8輸入,我們有0.95的值,增加20%。

只改變亮度而不改變感知的顏色,我看到最簡單的解決方案是使用另一種色彩空間,如HSL。
用H,S,L,你代表的方式,是meaningfull人眼顏色:
h是色調:在「顏色」,
飽和度的顏色「實力」,
,l是光度。

因此,步驟是:

for each pixel 
    compute h,s,l of the pixel out of its r,g,b 
    apply one transform function on luminosity 
       a good one is : new l = Math.pow(l, 1/gamma); 
    compute new (r,g,b) out of (h, s, new l) 
    write those values. 

我犯了一個小提琴來說明:

小提琴結果:http://jsfiddle.net/gamealchemist/yqvmC/embedded/result/
小提琴本身:http://jsfiddle.net/gamealchemist/yqvmC/

編輯:這裏是一個修改版本,即以圖像作爲輸入,並且 返回圖像。

該參數可以是伽馬值(數),或變換你喜歡功能 。
我爲示例添加了gamma壓縮函數。您可以在結果 (向下滾動才能看到它)看到,壓縮是相當苛刻:所有亮度值 出行比例*(最大值 - 最小值),這使得圖像非常可讀的中心,但低對比度。

下面是代碼:

// pow is the power of the function 
// min is min value returned 
// max is max value returned. 
function gamma(pow, min, max, x) { 
    return min + Math.pow(x, 1/pow) * (max - min); 
} 

// pow is the 'gamma' used for both part of the curves 
// min is the minimum value returned/max the max 
// center is the luminosity where we stop reducing and start expanding 
// ratio states where reduced luminosity should lay between min and max. 
function gammaCompress(pow, min, max, center, ratio, x) { 
    var xr = 0; 
    if (x < center) { 
     xr = x/center; 
     return min + Math.pow(xr, 1/pow) * (max - min) * ratio; 
    } else { 
     xr = (x - center)/(1 - center); 
     return min + (max - min) * ratio + Math.pow(xr, 1/pow) * (max - min) * (1 - ratio); 
    } 
} 

function getEnligthedImage(sourceImage, transform) { 
    // if a number, not a bound transform function, was provided, 
    // assume it's a gamma targetting [0;1] 
    if (typeof transform != 'function') { 
     transform = gamma.bind(null, transform, 0, 1); 
    } 
    var tgtCv = document.createElement('canvas'); 
    tgtCv.width = sourceImage.width; 
    tgtCv.height = sourceImage.height; 
    var context = tgtCv.getContext('2d'); 
    context.drawImage(img, 0, 0); 
    var imgData = context.getImageData(0, 0, canvasWidth, canvasHeight); 
    var pix = imgData.data; 
    var hslValue = {  h: 0,  s: 0,  l: 0 }; 
    var rgbValue = {  r: 0,  g: 0,  b: 0 }; 
    for (var i = 0; i < pix.length; i += 4) { 
     rgbToHsl(pix[i], pix[i + 1], pix[i + 2], hslValue); 
     hslValue.l = transform(hslValue.l); 
     hslToRgb(hslValue.h, hslValue.s, hslValue.l, rgbValue); 
     pix[i] = rgbValue.r; 
     pix[i + 1] = rgbValue.g; 
     pix[i + 2] = rgbValue.b; 
    } 
    context.putImageData(imgData, 0, 0); 
    var newImage = new Image(); 
    newImage.src = tgtCv.toDataURL("image/png"); 
    return newImage; 
} 

var result = getEnligthedImage(img, 1.6); 
var pr = document.createElement('div'); 
pr.innerHTML = 'example for a gamma 1.6' 
document.body.appendChild(pr); 
document.body.appendChild(result); 

var compressor = gammaCompress.bind(null, 1.4, 0.2, 1.0, 0.5, 0.5); 
var compressedResult = getEnligthedImage(img, compressor); 
pr = document.createElement('div'); 
pr.innerHTML = 'example using a gamma compressor. min is 0.2' 
document.body.appendChild(pr); 
document.body.appendChild(compressedResult); 

如果你想要做一些其他的事情與圖像,保存到文件,發送到服務器,或類似,搜索谷歌:-),這個環節可能會有所幫助:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement

+0

在這種情況下,圖像將通過調整gamma來操作,對吧?是否有可能創建一個函數,它會自動根據其原始rgb操作圖像? – Sky

+0

是和否:圖像是不可變的對象。然而,可以構建一個功能,從舊的+提供的伽瑪中創建一個新的修改後的圖像。如果您願意,我會用這樣的功能更新代碼。 – GameAlchemist

+0

我相信我會有興趣知道如何確定要針對個別圖像進行調整的伽馬值。所以實際上我想要的是生成一個已經應用了gamma值的修改後的圖像。順便謝謝你的努力。 – Sky

0

自動調整顏色的簡單功能。根據直方圖將圖像變亮或變暗。

僅在照片中的某個區域變亮/變暗很難,因爲很難連接更改和不變的區域。

對不起,我在這裏的圖像有問題。

<img alt="" src="bright.png" /> 
<br /><br /> 
<canvas id="cc"></canvas> 

<script> 
var img = new Image(); 
img.src = 'bright.png'; 
img.onload = function(){ 
    var canvas = document.getElementById("cc"); 
    var ctx = canvas.getContext("2d"); 
    canvas.width=300; 
    canvas.height=200; 
    ctx.drawImage(img, 0, 0); 

    auto_adjust(ctx, 300, 200); 
    } 

function auto_adjust(context, W, H){ 
    //settings 
    var white = 240; //white color min 
    var black = 30;  //black color max 
    var target_white = 1; //how much % white colors should take 
    var target_black = 0.5; //how much % black colors should take 
    var modify = 1.1; //color modify strength 

    var img = context.getImageData(0, 0, W, H); 
    var imgData = img.data; 
    var n = 0; //pixels count without transparent 

    //make sure we have white 
    var n_valid = 0; 
    for(var i = 0; i < imgData.length; i += 4){ 
      if(imgData[i+3] == 0) continue; //transparent 
      if((imgData[i] + imgData[i+1] + imgData[i+2])/3 > white) n_valid++; 
      n++; 
     } 
    target = target_white; 
    var n_fix_white = 0; 
    var done = false; 
    for(var j=0; j < 30; j++){ 
     if(n_valid * 100/n >= target) done = true; 
     if(done == true) break; 
     n_fix_white++; 

     //adjust 
     for(var i = 0; i < imgData.length; i += 4){ 
      if(imgData[i+3] == 0) continue; //transparent 
      for(var c = 0; c < 3; c++){ 
       var x = i + c; 
       if(imgData[x] < 10) continue; 
       //increase white 
       imgData[x] *= modify; 
       imgData[x] = Math.round(imgData[x]); 
       if(imgData[x] > 255) imgData[x] = 255; 
       } 
      } 

     //recheck 
     n_valid = 0; 
     for(var i = 0; i < imgData.length; i += 4){ 
      if(imgData[i+3] == 0) continue; //transparent 
       if((imgData[i] + imgData[i+1] + imgData[i+2])/3 > white) n_valid++; 
      } 
     } 

    //make sure we have black 
    n_valid = 0; 
    for(var i = 0; i < imgData.length; i += 4){ 
     if(imgData[i+3] == 0) continue; //transparent 
      if((imgData[i] + imgData[i+1] + imgData[i+2])/3 < black) n_valid++;  
     } 
    target = target_black; 
    var n_fix_black = 0; 
    var done = false; 
    for(var j=0; j < 30; j++){ 
     if(n_valid * 100/n >= target) done = true; 
     if(done == true) break; 
     n_fix_black++; 

     //adjust 
     for(var i = 0; i < imgData.length; i += 4){ 
      if(imgData[i+3] == 0) continue; //transparent 
      for(var c = 0; c < 3; c++){ 
       var x = i + c; 
       if(imgData[x] > 240) continue; 
       //increase black 
       imgData[x] -= (255-imgData[x]) * modify - (255-imgData[x]); 
       imgData[x] = Math.round(imgData[x]); 
       } 
      } 

     //recheck 
     n_valid = 0; 
     for(var i = 0; i < imgData.length; i += 4){ 
      if(imgData[i+3] == 0) continue; //transparent 
       if((imgData[i] + imgData[i+1] + imgData[i+2])/3 < black) n_valid++; 
      } 
     } 

    //save 
    context.putImageData(img, 0, 0); 
    //log('Iterations: brighten='+n_fix_white+", darken="+n_fix_black); 
    } 
</script> 
+0

感謝您的幫助。您是否碰巧嘗試過一個圖像,因爲當我在我身邊進行測試時,似乎沒有正在執行的操作。 – Sky

+0

是的,但嘗試與黑暗或明亮的圖像,如果圖像已經確定,效果會很小。 – ViliusL

+0

可以用下面的方法來問你:'(imgData [i] + imgData [i + 1] + imgData [i + 2])/ 3> white'通過獲得平均值,檢查更多'白色「? – Sky