HTML5 Canvas图像对比度

时间:2012-05-09 18:29:14

标签: html5 image-processing html5-canvas contrast

我一直在编写一个图像处理程序,它通过HTML5画布像素处理来应用效果。我已经实现了Thresholding,Vintaging和ColorGradient像素操作,但令人难以置信的是我无法改变图像的对比度! 我已经尝试了多种解决方案,但是我总是在图片中获得太多的亮度并且对比效果较少而且我不打算使用任何Javascript库,因为我试图在本地实现这些效果。

基本像素操作代码:

var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
 //Note: data[i], data[i+1], data[i+2] represent RGB respectively
data[i] = data[i];
data[i+1] = data[i+1];
data[i+2] = data[i+2];
}

像素操作示例

值处于RGB模式,这意味着data [i]是红色。所以如果data [i] = data [i] * 2;对于该像素的红色通道,亮度将增加到两倍。例如:

var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
 //Note: data[i], data[i+1], data[i+2] represent RGB respectively
 //Increases brightness of RGB channel by 2
data[i] = data[i]*2;
data[i+1] = data[i+1]*2;
data[i+2] = data[i+2]*2;
}

* 注意:我不是要求你们完成代码!那只会是一个忙!我要求一个算法(甚至伪代码),它显示像素操作中对比度的可能性! 如果有人能在HTML5画布中为图像对比提供一个好的算法,我会很高兴。

7 个答案:

答案 0 :(得分:26)

在尝试了Schahriar SaffarShargh的回答之后,它的表现并不像对比应该表现得那样。我终于遇到了这个算法,它就像一个魅力!

有关该算法的其他信息,请阅读this article及其评论部分。

function contrastImage(imageData, contrast) {

    var data = imageData.data;
    var factor = (259 * (contrast + 255)) / (255 * (259 - contrast));

    for(var i=0;i<data.length;i+=4)
    {
        data[i] = factor * (data[i] - 128) + 128;
        data[i+1] = factor * (data[i+1] - 128) + 128;
        data[i+2] = factor * (data[i+2] - 128) + 128;
    }
    return imageData;
}

用法:

var newImageData = contrastImage(imageData, 30);

希望这对某人节省时间。干杯!

答案 1 :(得分:16)

更快的选项(基于Escher's approach)是:

function contrastImage(imgData, contrast){  //input range [-100..100]
    var d = imgData.data;
    contrast = (contrast/100) + 1;  //convert to decimal & shift range: [0..2]
    var intercept = 128 * (1 - contrast);
    for(var i=0;i<d.length;i+=4){   //r,g,b,a
        d[i] = d[i]*contrast + intercept;
        d[i+1] = d[i+1]*contrast + intercept;
        d[i+2] = d[i+2]*contrast + intercept;
    }
    return imgData;
}

类似于以下的推导;这个版本在数学上是相同的,但运行得更快。

原始答案

以下是方法already discussed的简化版及解释(基于this article):

function contrastImage(imageData, contrast) {  // contrast as an integer percent  
    var data = imageData.data;  // original array modified, but canvas not updated
    contrast *= 2.55; // or *= 255 / 100; scale integer percent to full range
    var factor = (255 + contrast) / (255.01 - contrast);  //add .1 to avoid /0 error

    for(var i=0;i<data.length;i+=4)  //pixel values in 4-byte blocks (r,g,b,a)
    {
        data[i] = factor * (data[i] - 128) + 128;     //r value
        data[i+1] = factor * (data[i+1] - 128) + 128; //g value
        data[i+2] = factor * (data[i+2] - 128) + 128; //b value

    }
    return imageData;  //optional (e.g. for filter function chaining)
}

注释

  1. 我选择使用contrast范围+/- 100代替原+/- 255。对于不了解基本概念的用户或程序员来说,百分比值似乎更直观。此外,我的用法总是与UI控件绑定;从-100%到+ 100%的范围允许我直接标记和绑定控制值,而不是调整或解释它。

  2. 此算法不包括范围检查,即使calculated values can far exceed the allowable range - 这是因为ImageData对象底层的数组是Uint8ClampedArrayAs MSDN explainsUint8ClampedArray范围检查将为您处理:

  3.   

    &#34;如果指定了超出[0,255]范围的值,则将设置0或255。&#34;

    用法

    请注意,虽然基础公式相当对称(允许往返),但数据在高级别的过滤时会丢失,因为像素只允许整数值。例如,当您将图像去饱和到极端水平(> 95%左右)时,所有像素基本上是均匀的中灰色(在平均可能值128的几位数内)。再次将对比度重新调整会导致颜色范围变窄。

    此外,在应用多个对比度调整时,操作顺序非常重要 - 饱和值&#34;吹出&#34; (快速超过夹紧的最大值255),意味着高度饱和然后去饱和将导致整体图像变暗。然而,去饱和然后饱和并没有那么多的数据丢失,因为高光和阴影值被静音,而不是被削减(见下面的解释)。

    一般来说,在应用多个过滤器时,最好使用原始数据开始每个操作并依次重新应用每个调整,而不是尝试反转先前的更改 - 至少对于图像质量。对于每种情况,性能速度或其他要求可能会有所不同。

    Mandrill contrast examples

    代码示例:

    &#13;
    &#13;
    function contrastImage(imageData, contrast) {  // contrast input as percent; range [-1..1]
        var data = imageData.data;  // Note: original dataset modified directly!
        contrast *= 255;
        var factor = (contrast + 255) / (255.01 - contrast);  //add .1 to avoid /0 error.
    
        for(var i=0;i<data.length;i+=4)
        {
            data[i] = factor * (data[i] - 128) + 128;
            data[i+1] = factor * (data[i+1] - 128) + 128;
            data[i+2] = factor * (data[i+2] - 128) + 128;
        }
        return imageData;  //optional (e.g. for filter function chaining)
    }
    
    $(document).ready(function(){
      var ctxOrigMinus100 = document.getElementById('canvOrigMinus100').getContext("2d");
      var ctxOrigMinus50 = document.getElementById('canvOrigMinus50').getContext("2d");
      var ctxOrig = document.getElementById('canvOrig').getContext("2d");
      var ctxOrigPlus50 = document.getElementById('canvOrigPlus50').getContext("2d");
      var ctxOrigPlus100 = document.getElementById('canvOrigPlus100').getContext("2d");
      
      var ctxRoundMinus90 = document.getElementById('canvRoundMinus90').getContext("2d");
      var ctxRoundMinus50 = document.getElementById('canvRoundMinus50').getContext("2d");
      var ctxRound0 = document.getElementById('canvRound0').getContext("2d");
      var ctxRoundPlus50 = document.getElementById('canvRoundPlus50').getContext("2d");
      var ctxRoundPlus90 = document.getElementById('canvRoundPlus90').getContext("2d");
      
      
      var img = new Image();
      img.onload = function() {
        //draw orig
        ctxOrig.drawImage(img, 0, 0, img.width, img.height, 0, 0, 100, 100); //100 = canvas width, height
        
        //reduce contrast
        var origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, -.98);
        ctxOrigMinus100.putImageData(origBits, 0, 0);
        
        var origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, -.5);
        ctxOrigMinus50.putImageData(origBits, 0, 0);
        
        // add contrast
        var origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, .5);
        ctxOrigPlus50.putImageData(origBits, 0, 0);
        
        var origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, .98);
        ctxOrigPlus100.putImageData(origBits, 0, 0);
        
        
        //round-trip, de-saturate first
        origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, -.98);
        contrastImage(origBits, .98);
        ctxRoundMinus90.putImageData(origBits, 0, 0);
        
        origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, -.5);
        contrastImage(origBits, .5);
        ctxRoundMinus50.putImageData(origBits, 0, 0);
        
        //do nothing 100 times
        origBits = ctxOrig.getImageData(0, 0, 100, 100);
        for(i=0;i<100;i++){
          contrastImage(origBits, 0);
        }
        ctxRound0.putImageData(origBits, 0, 0);
        
        //round-trip, saturate first
        origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, .5);
        contrastImage(origBits, -.5);
        ctxRoundPlus50.putImageData(origBits, 0, 0);
        
        origBits = ctxOrig.getImageData(0, 0, 100, 100);
        contrastImage(origBits, .98);
        contrastImage(origBits, -.98);
        ctxRoundPlus90.putImageData(origBits, 0, 0);
      };
      
      img.src = "data:image/png;base64,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";
      
    });
    &#13;
    canvas {width: 100px; height: 100px}
    div {text-align:center; width:120px; float:left}
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <div>
      <canvas id="canvOrigMinus100" width="100" height="100"></canvas>
      -98%
    </div>
    
    <div>
      <canvas id="canvOrigMinus50" width="100" height="100"></canvas>
      -50%
    </div>
    
    <div>
      <canvas id="canvOrig" width="100" height="100"></canvas>
      Original
    </div>
    
    <div>
      <canvas id="canvOrigPlus50" width="100" height="100"></canvas>
      +50%
    </div>
    
    <div>
      <canvas id="canvOrigPlus100" width="100" height="100"></canvas>
      +98%
    </div>
    
      <hr/>
    
    <div style="clear:left">
      <canvas id="canvRoundMinus90" width="100" height="100"></canvas>
      Round-trip <br/> (-98%, +98%)
    </div>
    
    <div>
      <canvas id="canvRoundMinus50" width="100" height="100"></canvas>
      Round-trip <br/> (-50%, +50%)
    </div>
    
    <div>
      <canvas id="canvRound0" width="100" height="100"></canvas>
      Round-trip <br/> (0% 100x)
    </div>
    
    <div>
      <canvas id="canvRoundPlus50" width="100" height="100"></canvas>
      Round-trip <br/> (+50%, -50%)
    </div>
    
    <div>
      <canvas id="canvRoundPlus90" width="100" height="100"></canvas>
      Round-trip <br/> (+98%, -98%)
    </div>
    &#13;
    &#13;
    &#13;

    说明

    免责声明 - 我不是图像专家或数学家。我试图用最少的技术细节提供常识解释。下面有一些挥手,例如255 = 256以避免索引问题,以及127.5 = 128,用于简化数字。

    因为,对于给定像素,颜色通道的非零值的可能数量是255 ,&#34;无对比度&#34;,平均值一个像素是128 (或127或127.5,如果你想争论,但差异可以忽略不计)。出于这种解释的目的,&#34;对比度&#34;是从当前值到平均值的距离(128)。调整对比度意味着增加或减少当前值和平均值之间的差异。

    算法解决的问题是:

    1. 选择一个恒定因子来调整对比度
    2. 对于每个像素的每个颜色通道,缩放&#34;对比度&#34; (与平均值的距离)乘以常数因子
    3. 或者,如CSS spec所示,只需选择一条线的斜率和截距:

        

      <feFuncR type="linear" slope="[amount]" intercept="-(0.5 * [amount]) + 0.5"/>

      注意术语type='linear';我们在RGB color space进行线性对比度调整,而不是二次缩放功能,luminence-based调整或histogram matching

      如果从几何类中回忆,行的公式为y=mx+by是我们追求的最终值,斜率m是对比度(或factor),x是初始像素值,b是y轴的截距(x = 0),垂直移动直线。回想一下,由于y轴截距不在原点(0,0),公式也可以表示为 y=m(x-a)+b ,其中a是x偏移水平移动线。

      Formula for slope of a line

      出于我们的目的,此图表示输入值(x轴)和结果(y轴)。我们已经知道b,y截距(对于m=0,没有对比度)必须是128(我们可以检查规格中的0.5 - 0.5 * 256的整个范围= 128) 。 x是我们的原始值,因此我们只需要找出斜率m和x偏移量a

      首先,斜率m是&#34;在运行&#34;或(y2-y1)/(x2-x1)上升 - 所以我们需要知道在所需线上的2个点。找到这些要点需要将一些东西放在一起:

      • 我们的函数采用线截距图的形状
      • y-intercept位于b = 128 - 无论斜率(对比度)如何。
      • 预期的最大值&#39; y&#39;值为255,最小值为0
      • 可能的范围&#39; x&#39;值为256
      • 中性值应始终保持中性:128 =&gt; 128无论坡度
      • 0的对比度调整应该导致输入和输出之间没有变化;也就是说,斜率为1:1。

      将所有这些结合在一起,我们可以推断出无论应用的对比度(斜率)如何,我们得到的线都将以128,128为中心(并绕其移动)。由于我们的y轴截距不为零,x截距也是非零的;我们知道x范围是256宽并且在中间居中,所以它必须偏移可能范围的一半:256/2 = 128。

      Contrast function slopes

      现在对于y=m(x-a)+b,我们知道除m之外的所有内容。回想一下几何类中的两个重要点:

      • 即使线的位置发生变化,线也有相同的斜率;也就是说,无论ma的值如何,b都保持不变。
      • 可以使用线上的任意2个点找到线的斜率

      为了简化斜率讨论,让我们将坐标原点移动到x截距(-128)并暂时忽略ab。我们的原始行现在将穿过(0,0),我们知道该行的第二个点位于x(输入)和y(输出)的全部范围(255,255)

      我们让新线在(0,0)处转动,因此我们可以将其用作新线上将跟随我们的最终对比度斜率m的点之一。第二个点可以通过将当前结束点移动(255,255)一定量来确定;由于我们仅限于单个输入(contrast)并使用线性函数,因此第二个点将在图表的xy方向上均匀移动。

      Adjusting the contrast slope

      4个可能的新点的(x,y)坐标为255 +/- contrast。由于增加或减少x和y都会使我们保持原始的1:1行,所以让我们只看+x, -y-x, +y,如图所示。

      较陡的线(-x,+ y)与正contrast调整相关联;它的(x,y)坐标是(255 - contrast255 + contrast)。较浅的线(负contrast)的坐标以相同的方式找到。请注意, contrast的最大有意义值将是255 - 最初可以转换(255,255)的初始点,然后产生垂直线(完全对比度,全黑或白色) )或水平线(无对比度,全灰色)。

      所以现在我们在新行上有两个点的坐标 - (0,0)和(255 - contrast255 + contrast)。我们将其插入斜率方程,然后使用之前的所有部分将其插入到整线方程中:

        

      y = m(x-a) + b

           

      m = (y2-y1)/(x2-x1) =&gt;
        ((255 + contrast) - 0)/((255 - contrast) - 0) =&gt;
        (255 + contrast)/(255 - contrast)

           

      a = 128
        b = 128

           

      y = (255 + contrast)/(255 - contrast) * (x - 128) + 128 QED

      数学思维会注意到结果mfactor是标量(无单位)值;您可以使用contrast所需的任何范围,只要它与255计算中的常量(factor)匹配即可。例如,contrast范围+/-100factor = (100 + contrast)/(100.01 - contrast),这是我真正用来消除缩放到255的步骤;我刚刚在顶部的代码中留下255来简化说明。

      注意&#34;魔法&#34; 259

      source article使用&#34;魔法&#34; 259,虽然作者承认他不记得原因:

        

      &#34;我不记得我是自己计算过这个,还是在书本或网上看过。&#34;。

      259应该是255或256也许 - 每个像素的每个通道可能的非零值的数量。请注意,在原始的factor计算中,259/255取消了 - 技术上是1.01,但最终值是整数,所以1用于所有实际目的。所以这个外部术语可以丢弃。实际上,使用255作为分母中的常数,会在公式中引入“除以零”错误的可能性;调整到稍大的值(例如,259)可避免此问题,而不会对结果造成重大错误。我选择使用255.01而不是因为误差较低而且(希望)似乎更少&#34;魔法&#34;对一个新人。

      据我所知,it doesn't make much difference which you use - 你会得到相同的值,除了低对比度值的窄带中的微小对称差异和低正对比度增加。我很好奇地反复往返两个版本并与原始数据进行比较,但这个答案已经花了太长时间。 :)

答案 2 :(得分:3)

我发现你必须通过分离黑暗和光线来使用效果,或者技术上任何小于127(R + G + B / 3的平均值)的rgb标度是黑色的,超过127是白色,因此根据你的对比度你减去一个值,说黑色与10相反,并为白人增加相同的值!

这是一个例子: 我有两个RGB颜色的像素,[105,40,200] | [255200150] 所以我知道我的第一个像素105 + 40 + 200 = 345,345 / 3 = 115 并且115小于255的一半,即127,所以我认为像素更接近[0,0,0],因此如果我想减去10对比度,那么我从它的每种颜色中取出10的平均值 因此,我必须将每个颜色的值除以总和的平均值,在这种情况下为115,并按照我的对比度计算,并减去特定颜色的最终值:

例如我从我的像素中取105(红色),所以我将其除以总RGB的平均值。这是我的对比度值为10,(105/115)* 10,它给你一些9左右的东西(你必须把它围起来!),然后从105那里取出9,这样颜色就变成96了所以我的对比值是115在暗像素上产生10对比度后出现红色。

所以,如果我继续使用我的像素值,那么[96,37,183]! (注意:对比度的大小取决于你!但我最终应该将它转换为某种比例,如从1到255)

对于较亮的像素,我也做同样的事情,除了不加减去对比度值,我加上它!如果您达到255或0的限制,那么您将停止针对该特定颜色的加法和减法!因此,我的第二个较亮像素的像素变为[255,210,157]

当您添加更多对比度时,它会减轻较浅的颜色并使较暗的颜色变暗,从而增加对比度!

以下是一个示例Javascript代码(我还没有尝试过):

var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
 var contrast = 10;
 var average = Math.round( ( data[i] + data[i+1] + data[i+2] ) / 3 );
  if (average > 127){
    data[i] += ( data[i]/average ) * contrast;
    data[i+1] += ( data[i+1]/average ) * contrast;
    data[i+2] += ( data[i+2]/average ) * contrast;
  }else{
    data[i] -= ( data[i]/average ) * contrast;
    data[i+1] -= ( data[i+1]/average ) * contrast;
    data[i+2] -= ( data[i+2]/average ) * contrast;
  }
}

答案 3 :(得分:2)

这个javascript实现符合&#34;对比&#34;的SVG / CSS3定义。 (以下代码将以相同的方式渲染画布图像):

/*contrast filter function*/
//See definition at https://drafts.fxtf.org/filters/#contrastEquivalent
//pixels come from your getImageData() function call on your canvas image
contrast = function(pixels, value){
    var d = pixels.data;
    var intercept = 255*(-value/2 + 0.5);
    for(var i=0;i<d.length;i+=4){
        d[i] = d[i]*value + intercept;
        d[i+1] = d[i+1]*value + intercept;
        d[i+2] = d[i+2]*value + intercept;
        //implement clamping in a separate function if using in production
        if(d[i] > 255) d[i] = 255;
        if(d[i+1] > 255) d[i+1] = 255;
        if(d[i+2] > 255) d[i+2] = 255;
        if(d[i] < 0) d[i] = 0;
        if(d[i+1] < 0) d[i+1] = 0;
        if(d[i+2] < 0) d[i+2] = 0;
    }
    return pixels;
}

答案 4 :(得分:1)

您可以查看OpenCV文档,了解如何完成此任务:Brightness and contrast adjustments

然后是演示代码:

 double alpha; // Simple contrast control: value [1.0-3.0]
 int beta;     // Simple brightness control: value [0-100]

 for( int y = 0; y < image.rows; y++ )
 { 
      for( int x = 0; x < image.cols; x++ )
      { 
          for( int c = 0; c < 3; c++ )
          {
              new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
          }
      }
 }

我认为你有能力翻译成javascript。

答案 5 :(得分:1)

通过vintaging我假设您尝试应用LUTS ..最近我一直在尝试为画布窗口添加色彩处理。如果你想将“LUTS”实际应用到画布窗口,我相信你需要实际映射imageData返回到LUT的RGB数组的数组。

(来自光幻觉) 举个例子,1D LUT的开头看起来像这样: 注意:严格来说这是3x 1D LUT,因为每种颜色(R,G,B)是1D LUT

R, G, B 
3, 0, 0 
5, 2, 1 
7, 5, 3 
9, 9, 9

这意味着:

For an input value of 0 for R, G, and B, the output is R=3, G=0, B=0 
For an input value of 1 for R, G, and B, the output is R=5, G=2, B=1 
For an input value of 2 for R, G, and B, the output is R=7, G=5, B=3 
For an input value of 3 for R, G, and B, the output is R=9, G=9, B=9

这是一个奇怪的LUT,但你看到对于给定的R,G或B输入值,有一个给定的R,G和B输出值。

因此,如果像素的RGB输入值为3,1,0,则输出像素为9,2,0。

在此过程中我也意识到在使用imageData后它会返回一个Uint8Array并且该数组中的值是十进制的。大多数3D LUTS都是Hex。因此,在完成所有映射之前,首先必须对整个数组执行某种类型的十六进制到十进制转换。

答案 6 :(得分:0)

这是您正在寻找的公式......

var data = imageData.data;
if (contrast > 0) {

    for(var i = 0; i < data.length; i += 4) {
        data[i] += (255 - data[i]) * contrast / 255;            // red
        data[i + 1] += (255 - data[i + 1]) * contrast / 255;    // green
        data[i + 2] += (255 - data[i + 2]) * contrast / 255;    // blue
    }

} else if (contrast < 0) {
    for (var i = 0; i < data.length; i += 4) {
        data[i] += data[i] * (contrast) / 255;                  // red
        data[i + 1] += data[i + 1] * (contrast) / 255;          // green
        data[i + 2] += data[i + 2] * (contrast) / 255;          // blue
    }
}

希望它有所帮助!