开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
相信大家都应该玩过找茬类游戏,在两张相似的图片上找出不同之处,比如像下面这张图片,你能找出多少处不同的地方呢?
找不到也没关系,接下来我们自己实现一个可以帮助我们更快找到两张相似图片之间不同之处的工具。
使用到的就是我们的【Canvas】了。
Canvas(画布)是H5的新特性之一,这个元素会占据一块页面区域,让JS可以动态在上面绘图,因此我们需要在创建
<canvas>
元素的时候就设置好其width
属性和height
属性,可以通过内联样式、class、js设置。设置好了元素的宽高,浏览器才能知道在多大的面积上绘图。
绘制图像
canvas有一个 drawImage
方法,可以将 <img>
标签绘制到指定的地方,它有多种参数模式,其中一种是传入5个参数:
- 第一个参数:传入一个
<img>
元素,表示绘制的目标; - 第二/三个参数:要绘制的图像左上角原点的xy坐标;
- 第四/五个参数:要以什么样的尺寸绘制图像sw和sh;
context.drawImage(img, 10, 10, 200, 200)
了解完这个方法,我们先把这两张图片绘制在页面上,具体代码如图所示:
上面的代码中,我们先在页面上写了两个img标签,引入了两张需要的图片(这里其实是我偷懒了,正常来说我们会使用 createElement
来动态创建img标签),然后还有就是canvas标签。这里我给3个元素都设置了id,为了方便一会获取DOM元素。
接下来是JS部分:
首先是将canvas的宽高设置为页面的宽高,然后获取两个img标签,这里需要注意的是,img标签引入图片加载图片的过程是异步的, 所以我们要检查img标签是否已经完成了图片的加载,不然的话会出现空白的情况。
检查img标签是否加载完图片有很多种方法,其中一种是onload事件,当img标签加载完图片后会触发这个事件,来告知我们已经加载完了,但是这个只能是单张单张的触发,当我们想知道多张图片是否都加载完成的时候,可以使用另一种方法,通过判断img标签的complete属性是否为true来判断图片是否加载完成。
上面的代码中,当两张图片都加载完成了才会执行 findDifference
函数,进行下一步的操作。
上面的代码就是将图像绘制到canvas上去。
获取图像原始数据
将图像绘制到canvas上之后,我们继续使用canvas的另一个方法 getImageData
来获取图像的原始数据(即每一个像素点的RGBA值),这个方法的语法如下
context.getImageData(x, y, w, h)
- 第一/二个参数:要取得数据中第一个像素的坐标(x,y);
- 第三/四个参数:要取得的像素宽度w和高度h;
这个方法会返回一个 ImageData
实例,每个实例中包含以下4个属性:
图像的每个像素的数据就存放在data数组中,每个像素由数组中的4个元素表示,比如说第一个像素的数据就包含在data数组的第0~3个元素中,分别代表红绿蓝和透明度。
data数组中每个元素的值都在 [0~255]
区间,可以直接操作data数组中元素的值来对图像进行修改;
思路
当我们获取到图像的原始数据后,我们可以通过遍历每个像素点,判断两个图像的像素点是否相同来找出两张图片的异同之处。
经过执行,可以得到下面的结果
得到的结果并不如意,因为我们对每个像素点的判断太过于严格了,导致很多区域被判定为不同像素,进而未能消除,因为,我们在判断的时候,需要加入误差判断,在误差允许的范围内,我们可以把两个RGB值不同的像素点视为同一个像素点。
加入误差判断
因为每个值最小是0,最大是255,所以我们将标准值(判断的依据)加减上误差(diff),并于0和255进行比较,以此来确定真正的误差范围,防止范围小于0又或者大于255。
最终效果
看看加了误差判断后的效果
左边未能被消除的像素,代表着是两张图片不相同的部分,我们可以重点关注这些地方,就可以很容易的找出尽可能多的不同之处啦。
快来数数你们找到了多少处吧
可以看到,这种方法的效果其实并不怎么好,而且逐个像素的遍历,很耗费性能,因此这个demo只是在canvas学习中,对学到的东西的一次应用。
暂无评论内容