您的位置:首页 > Web前端 > JavaScript

[JavaScript/canvas] 创建基于坐标访问的图形数据对象

2019-07-29 18:27 387 查看
原文链接:https://www.geek-share.com/detail/2556700640.html

在HTML5中,canvas节点所提供的2d上下文(context),具备一组对像素进行操作的方法:getImageData/putImageData/createImageData。通过这三个方法,我们可以进行像素级别的图像处理。比如可以移植传统的各种滤镜算法,在web页面中开发出一套类似于PS的图片处理应用,等等。

一般来讲,我们首先会通过getImageData方法,获取canvas上一个区域的像素数据。例如:

context.getImageData(10, 10, 100, 80);

这样我们会得到坐标为{10, 10},宽100、高80的一个区域的像素。返回对象ImageData有三个属性:width/height/data:

 

 

这里需要注意的是data。从上图中我们可以看到,它的数据类型是Uint8ClampedArray,是一个8位的无符号数组。请移步至http://www.khronos.org/registry/typedarray/specs/latest/,了解一下ES5中有关Typed Array的规范。

data是个一维的数组,每4个数字对应一个点的RGBA色值。所以可以知道,这个数组长度应该是总像素数*4。对像素的描述,是从左到右、从上到下逐行扫描的过程。这种存储方式,或者说一维的描述图像的方式,与我们所习惯的二维坐标系方式不同。所以我希望能创建一个对象,实现二维到一维的转换,把自己从苦逼算点的工作中解脱出来;同时也希望通过本文,让各位初学者能够了解对像素如何进行基本的操作。

首先,我设计一个接口,它应该具备以下几个功能:

 

//
interface ISmartImageData{
long getPointCount(); //获取像素总数
Color getValue(long index); //获取索引为index的[像素]的色值
long getPointIndex(x, y); //转换坐标为像素索引
Color getPointValue(x, y); //获取坐标点的色值
}

 

 

这里我们还需要一个辅助对象Color。Color使用了数组作为基础结构,为了后续一些运算上的方便,绑定了一些额外的方法。

 

//
function _extend(a, b){    //a -> b
for(var p in a) b

= a[p]; } var _ColorMethods = { //两个色值相加 add : function(v){ this[0] += v[0]; this[1] += v[1]; this[2] += v[2]; this[3] += v[3]; }, //色值平均到c个点 avg : function(c){ this[0] = Math.round(this[0] / c); this[1] = Math.round(this[1] / c); this[2] = Math.round(this[2] / c); this[3] = Math.round(this[3] / c); }, //色值是否相等(Alpha值暂时忽略) eq : function(v){ return this[0] === v[0] && this[1] === v[1] && this[2] === v[2] //&& this[3] === v[3] ; }, //与色值v比较,各个色值差允许在sub以内。可以作为降噪的一种方式。 fuzzy : function(v, sub){ return Math.abs(this[0] - v[0]) <= sub && Math.abs(this[1] - v[1]) <= sub && Math.abs(this[2] - v[2]) <= sub //&& Math.abs(this[3] - v[3]) <= sub ; } } function Color(c){ _extend(_ColorMethods, c); return c; }

[p]如果需要让Color对象具备更多的方法,可以对_ColorMethods进行扩展。额外说一点:Color使用数组还是{R:0,G:0,B:0,A:0}这种方式,在实际中性能上几乎没有的区别。

现在我们开始构建SmartImageData对象。首先我们使用一个ImageData来初始化。

//
function SmartImageData(imageData){
this.data = imageData.data;
this.width = imageData.width;
this.height = imageData.height;
}

 

在实际操作中发现一个问题。如果你频繁调用imageData原始对象的width/height属性时,会造成性能上的较大损耗。原因不明。所以我将三个属性分别独立出来。下面实现ISmartImageData接口。

//
SmartImageData.prototype = {
getPointCount : function(){
return this.width * this.height;
},
getValue : function(index){
var i = index * 4;
var d = this.data;
return Color([d[i+0],d[i+1],d[i+2],d[i+3]]);
},
getPointIndex : function(x, y){
return (y * this.width + x) * 4;
},
getPointValue : function(x, y){
var index = this.getPointIndex(x, y);
return this.getValue(index);
}
}

 

剩下的工作就没什么悬念了,可以借助这套系统,扩展出一系列的set方法,将处理过的数据,通过putImageData再放回到canvas中。

比如最近在做的马赛克的处理,至于是降低采样,还是算区域的平均值来得到区块的颜色,都可以通过坐标系来实现。

PS1:在刚结束的HTML5开发者嘉年华上,腾讯的工程师们实现了通过摄像头捕捉用户动作、进行体感操作。相信各位在今晚好好学习、通宵的努力,一定也能解决这个难题。

PS2:祝各位七夕快乐!

转载于:https://www.cnblogs.com/muse/archive/2012/08/23/2652338.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐