实现图像手动变化html,HTML5/JavaScript 图像自动Gamma校订 — 打造图像处理类库第一步...

今天为你们带来的是一篇关于图像自动Gamma校订的文章,主要是利用了html5的canvas作图像处理。通常处理Gamma校订都是经过用户手动调节Gamma值来完成的,自动Gamma校订则是经过一系列的计算得出理想的Gamma值后再作处理。网上关于JavaScript作Gamma校订的文章不多,而自动Gamma校订的文章能够说是几乎找不到,这篇文章里图像自动Gamma校订的相关内容,是我经过查阅有限的资料实现的,因此仍是挺有成就感的。今天分享给你们,若是文中有不正确的地方,欢迎你们指出来;有更好的想法也欢迎你们提出来,咱们一块儿探讨学习。感兴趣的话可到文末的连接下载源码,程序的效果以下:javascript

33b0b8bf9cdd51f089093c052abc3765.png

忽略gif图片画质过差的问题,你会发现自动Gamma校订后,图片的总体亮度提升了,石头的细节部分也能看到了。由于这里选用的图片本来是比较暗的,因此最后图片变亮了,若是选用的图片过亮,通过自动Gamma校订后,图片则会变暗。

html

1. 关于Gamma(伽马)

1.1 什么是Gamma

Gamma(伽马)是图像处理和视频制做中经常使用的技术用语。它定义了一个像素的数值和它的实际亮度之间的关系。从数学的角度来讲,Gamma是用来改变某些输入值的“幂指数”。能够用以下简短的公式进行说明。html5

02280d5bea799c12ff0ff9cc36046708.png

下面分别以2,1和0.5的Gamma值为例来简单说明这个公式java

d35ff817b07427e97ec3d1a87bac93e7.png 根据函数图,Gamma与输入、输出值间的关系就一目了然了,简单总结以下:

①当Gamma值比1大时,在输入值相同的状况下,输出值减少;

②当Gamma值为1时,输出值不变;

③当Gamma值比1小时,在输入值相同的状况下,输出值增长。

1.2 什么是Gamma校订

我是之前使用Photoshop时,才第一次接触到伽马校订(Gamma Correction),但当时并不知道Gamma校订的含义,如今经过一系列调查,才对它有了一个清晰的认识。简而言之,Gamma校订是对动态范围内亮度的非线性存储/还原算法,即输入值进行的非线性操做,使输出值与输入值呈指数关系;从效果上来讲Gamma校订调整图像的总体亮度,没有校订的图像看起来可能会存在过亮或太暗的状况,因此想要图像显示效果更完美,Gamma校订就显得很重要了。

使用Photoshop作Gamma校订时,若是设置的Gamma比1大,输出值会增长,即图片会变亮;而若是设置的Gamma值比1小时,输出值会减少,即图片会变暗。彷佛不符合咱们上一节针对公式所作的总结,恰好是相反的,这是由于PhotoShop是以Gamma的倒数做为输入值的幂,来计算输出值,以下所示:node

eba73be08daee7576aeed79ef86d5521.png 咱们后面的实现也是基于这个公式。

1.3 为何须要Gamma校订

主要的缘由有两个方面:

① 人类对于外界刺激变化程度的感觉,不是线性的,是指数形式的,以下图所示:git

d4cd296c065ba79ef9ccecf2b32a454d.png

也就是亮度相同的几盏灯,人类对于1盏灯→2盏灯产生的亮度变化感觉,与2盏灯→4盏灯的变化感觉是相同的。github

并且人类对于较暗的细节更加敏感,光越亮咱们对于亮度的变化就不是那么敏感了。因此经过Gamma校订,能够尽量的保留暗的部分的细节,以知足人眼对暗部敏感的需求。算法

② 图片文件的色阶颇有限,24位色图片每一个通道只有2^8个色阶,总共只能显示2^24种颜色;并且亮度级别过于庞大,若是按照线性方案进行存储,那么存储/传输的代价就会变得很昂贵。npm

2. 基本运用

调整亮度,以及灰度图像中的Gamma校订,使用上一节介绍的指数函数把每一个像素的RGB值进行变换。具体执行下列转换公式(假定像素值的取值范围为0到255):canvas

38fde561f4256e97d25ab66abf6fc737.png

使用以前提到的输入值的倒数幂,来完成Gamma校订。

3. 如何实现Gamma校订

① 利用

canvas = document.createElement('canvas'); 建立出

canvas 元素;

② 再经过

canvas.getContext('2d')方法获得

CanvasRenderingContext2D 对象,这个对象实现了画布绘制所使用的大多数方法;

③ 而后调用

CanvasRenderingContext2D 对象的

drawImage() 方法将图片绘制到

canvas 上;

④ 以后使用

CanvasRenderingContext2D 对象的

getImageData() 方法获得

ImageData对象,该对象拷贝了画布指定矩形的像素数据,即该对象中的每一个像素,都保存着 RGBA 值,也就是红、绿、蓝以及 alpha 通道,这些数据

(color/alpha信息)以数组形式存在,并存储于

ImageData对象的

data 属性中;

⑤ 对每一个像素的RGB值进行Gamma校订,调用的是咱们本身实现的

resetPixelColor() 方法;

⑥最后,调用

CanvasRenderingContext2D 对象的

putImageData()方法将图像数据拷贝回画布上,这时

canvas 上的数据就是通过Gamma校订后的了,若是要获得图片数据,再经过调用

canvas.toDataURL('image/png') 方法就能够获得Base64的图片数据。

下面把Gamma校订的代码贴出来:

function adjustImageGamma(img) {

image = img;

canvas = document.createElement('canvas');

canvas.id = img.id;

canvas.className = img.className;

//canvas.width = img.naturalWidth;

canvas.width = img.width;

//canvas.height = img.naturalHeight;

canvas.height = img.height;

ctx = canvas.getContext('2d');

//ctx.drawImage(img, 0, 0);

ctx.drawImage(img, 0, 0, img.width, img.height);

var image_parentNode = img.parentNode;

image_parentNode.replaceChild(canvas, img);

//imageData = ctx.getImageData(0, 0, img.naturalWidth, img.naturalHeight);

imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

var gammaVal = getGammaVal();

gammaCorrection = 1 / gammaVal;

setTimeout(function() {

//for ( y = 0; y < image.naturalHeight; y++) {

for ( y = 0; y < canvas.height; y++) {

//for ( x = 0; x < image.naturalWidth; x++) {

for ( x = 0; x < canvas.width; x++) {

var index = parseInt(x + canvas.width * y) * 4;

resetPixelColor(index);

}

}

ctx.putImageData(imageData, 0, 0);

//var dataURL = canvas.toDataURL('image/png');

}, 0);

}

function resetPixelColor(index) {

imageData.data[index + 0] = Math.pow(

(imageData.data[index + 0] / 255), gammaCorrection) * 255;

imageData.data[index + 1] = Math.pow(

(imageData.data[index + 1] / 255), gammaCorrection) * 255;

imageData.data[index + 2] = Math.pow(

(imageData.data[index + 2] / 255), gammaCorrection) * 255;

}

4. 如何实现自动Gamma校订

上一节的方法中调用过 getGammaVal()方法来计算出gamma值,这节就具体介绍下这个值的计算过程:

① 将图片的像素数据转变为非RGB的数据来计算均值,咱们这里是将其转变为灰度数据。之因此要转变成非RGB的的色彩模式,是由于若是使用RGB的数据来计算均值,可能会形成色彩平衡偏移。

② 将计算出来的均值带入 gammaVal = log(mean/255)/log(midrange) 这个公式中,就能够获得Gamma值了。

总的来讲,计算Gamma值的过程并不复杂,但以前在调查这部份内容花费了我挺多时间的,由于网上的资料实在是太少了。好了,接下来就把代码贴出来:

function getGammaVal() {

var pixData = imageData.data;

var grayNum = pixData.length / 4;

var totalGrayVal = 0;

for (var i = 0; i < pixData.length; i += 4) {

/* RGB to Luma:

* http://stackoverflow.com/questions/37159358/save-canvas-in-grayscale */

//var grayscale = pix[i] * 0.2126 + pix[i+1] * 0.7152 + pix[i+2] * 0.0722;

var grayscale = (pixData[i] + pixData[i+1] + pixData[i+2]) / 3;

totalGrayVal = totalGrayVal + grayscale;

}

var mean = totalGrayVal / grayNum;

var gammaVal = Math.log10(mean/255) / Math.log10(0.5);

return gammaVal;

}

须要注意的问题:

以前用火狐浏览器运行程序没报错,可是在谷歌的Chrome浏览器运行程序的时候,报了一个错 auto_gamma.js:31 Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.这是为了阻止欺骗,浏览器会追踪 imageData。当你把一个“跟canvas的域不一样的”图片放到canvas上,这个canvas就成为 “tainted”(被污染的,脏的),浏览器就不让你操做该canvas 的任何像素。这对于阻止多种类型的XSS/CSRF攻击(两种典型的跨站攻击)是很是有用的。

解决方案:

https://github.com/mrdoob/three.js/wiki/How-to-run-things-locally我参考的这个连接里的内容,将程序运行于Server上,使图片和canvas处于同一个域,由于恰好安装了node.js的环境,因此我就直接npm install http-server,而后再启动http-server 加载html就能够了。

程序源代码:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值