资讯专栏INFORMATION COLUMN

用 canvas 的 getImageData 做点有趣的事

chenatu / 1211人阅读

摘要:回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。代码请点这里这里有一个示例,展示下用回溯法怎么找到这些形状的。

说明
canvas元素标签强大之处在于可以直接在HTML上进行图形操作,具有极大的应用价值。

canvas 可以实现对图像的像素操作,这就要说到 getImageData() 方法了。

解释

CanvasRenderingContext2D.getImageData() 返回一个 ImageData 对象,用来描述 canvas 区域隐含的像素数据,这个区域通过矩形表示,起始点为(sx, sy)、宽为sw、高为sh。

语法

ctx.getImageData(sx, sy, sw, sh);

参数

sx:将要被提取的图像数据矩形区域的左上角 x 坐标。

sy:将要被提取的图像数据矩形区域的左上角 y 坐标。

sw:将要被提取的图像数据矩形区域的宽度。

sh:将要被提取的图像数据矩形区域的高度。

返回值

一个 ImageData 对象,包含 canvas 给定的矩形图像数据。

ImageData 对象会有三个属性,heightwidthdata

ImageData.height
使用像素描述 ImageData 的实际高度,这个值其实等于 getImageData() 方法中的参数 sh

ImageData.width
使用像素描述 ImageData 的实际宽度。这个值其实等于 getImageData() 方法中的参数 sw

ImageData.data
一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示。

注意

如果高度(sh)或者宽度(sw)变量为0,则会抛出错误。

示例

以上是需要知道的基本知识,下来看几个例子吧!

颜色选择器

效果图

实现思路

1、先把图片画到 canvas 上,
2、获取鼠标移动时的坐标并通过 getImageData() 方法,获取这一个点的像素,
3、得到像素信息后,拼接出 rgba 的字符串,再设置下面的小正方形的背景是这个颜色。

代码请点这里

图片灰度

效果图

实现思路

1、先在 canvas 上画出图片,
2、通过 getImageData() 方法,获取整个 canvas 上的像素信息,
3、点击按钮时,遍历获取到的像素信息的每个像素的 红色值、绿色值 和 蓝色值,相加求出平均值,再把平均值赋值给红色、绿色和蓝色,这么做是为了求出每个像素的灰度,
4、然后把改变后的像素信息,通过 putImageData() 方法重新添加到 canvas中,就实现了图片灰度的效果。

代码请点这里

除了图片可以实现灰度的效果外,因为 canvas 中也可以放视频,对于视频也可以实现灰度的效果,原理都是一样的,操作其实也一样,其实视频做灰度效果,可以理解为给很多张图片做灰度效果。

效果图

代码请点这里

文字粒子

效果图

实现思路

我们先不说,怎么实现最后的动画效果,我们先来想怎么获取文字所有像素在 canvas 上的坐标,

1、先获取文字在canvas上的像素信息

1.1 先在 canvas 上填充一个白色矩形

1.2 用红色,在 canvas 上写文字

1.3 获取 canvas 的像素信息 ImageData

1.4 清除整个 canvas

1.5 在 ImageData 中找出是红色的像素,记录他们的 x 和 y 坐标,找出的每个像素的坐标都保存在一个对象(Dot)中,所有的对象又都保存在一个数组(dotList)中,

计算机的速度是很快的,所以用户是看不到红色文字的,如果你觉得这种方式不好,也可以在用一个 canvas 专门来获取文字像素,这个canvas 不要让用户看到就好了。

我们知道文字的像素信息,知道每个像素的坐标,就能实现各种效果,像示例中的效果,仅仅只是改变一个 x 坐标的值而已。

2、遍历保存文字像素的数组(dotList),每个像素(Dot)对象还有一个 nowX 属性,初始值是0,每次画最后的圆点的时候,都是用这个属性作为圆的 x 坐标,nowX 属性不断的增加,直到最后等于像素(Dot)对象的 x 属性值就停止。

代码请点这里

这种效果我也是在 Canvas基础-粒子动画Part3 这篇文章中看到的,作者写的很好,推荐看看。
在github上也有一个不错的项目 shape-shifter,可以了解一下。

计算图片中的图形个数和面积

问题

平面上有若干个不特定的形状,如下图所示。请写程序求出物体的个数,以及每个不同物体的面积。

效果图

实现思路

1、创建存储图片像素点的二维数组(coordinates ),图中只有两种颜色,空白区域一种颜色,形状区域一种颜色,空白区域的像素标记为0,形状区域标记为1,类似下面这样

 0,0,0,0,0,0,0,0,0,0,0,0
 0,0,1,1,1,0,0,0,0,0,0,0
 0,1,1,1,1,0,0,0,0,0,0,0
 0,1,1,1,0,0,0,1,1,1,1,0
 0,0,0,0,0,0,1,1,1,0,0,0
 0,0,0,0,0,0,1,1,1,0,0,0
 0,0,0,0,0,0,0,0,0,0,0,0

2、计算有多少个形状,就是看二维数组中有多少个连续为1的块,计算形状的面积,就是算一个连续为1的块,有多少个1。
这就要通过 递归回溯算法 来计算了。

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。    
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。

代码请点这里

这里有一个示例,展示下用回溯法怎么找到这些形状的。

这个例子出自 前端面试的一道算法题(使用canvas解答)这篇文章,文章讲的也很好,推荐看看

总结

用 getImageData() 方法 要考虑两个问题

1、跨域问题
getImageData() 方法不允许操作非此域名外的图片资源,所以如果想本地试试文章中的例子,直接写图片路径就会报错,

不过可以将图片转换成base64编码,直接把base64编码赋值给图片的src属性就可以简单的解决这个问题了。这种方式仅仅适用于图片,如果是视频的话,还是需要服务器端的配合。
具体可以看看这篇文章 解决canvas图片getImageData,toDataURL跨域问题

2、性能问题
getImageData() 方法一般获取的像素信息是很多的,所以这就要考虑性能的问题,至于怎么优化也是要看具体场景了,比如在文中的文字粒子效果的示例中,可以先用 measureText() 方法计算文字宽度,结合 fontSize 就能知道 文字在哪块区域,只通过这个块区域获取文字的像素就好了。

getImageData() 方法,一句话总结就是获取 canvas 上的像素信息,文中实现的各种效果不管是简单的还是复杂的,都是在操作像素。
通过getImageData() 方法,能做的事情还有很多,远不止文章中提到的这些,比如实现其他的滤镜效果,文中只是说了一个灰度,我们还可以去实现反相,模糊,浮雕等,文中实现了文字粒子效果,其实图片也可以实现粒子效果,除此之外还有很多好玩的事情,但是本人才疏学浅,好多我也不知道。
最后,如果文中有不足或者错误的地方,还请小伙伴们指出,万分感谢。

参考

Canvas基础-粒子动画Part3
前端面试的一道算法题(使用canvas解答)
leetcode题解(递归和回溯法)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97858.html

相关文章

  • 使CANVAS实现交互性圆形马赛克效果

    摘要:在中任意从本地选择一张图片,然后通过鼠标移动或者移动端就能实现圆形分裂的效果。个人习惯在构造函数最后加上方法,方法里做一些准备工作,完成前的一些必要的事情。绘制第一个,也是最大的一个圆形。 在看D3.js的时候,无意间看到了一个例子,觉得很有趣,像是会分裂的圆形马赛克。看了下代码,使用svg完成的,但是具体实现方式使得在手机端无法把玩,于是就自己实现了一个canvas版本的。代码很简单...

    Aklman 评论0 收藏0
  • 使CANVAS实现交互性圆形马赛克效果

    摘要:在中任意从本地选择一张图片,然后通过鼠标移动或者移动端就能实现圆形分裂的效果。个人习惯在构造函数最后加上方法,方法里做一些准备工作,完成前的一些必要的事情。绘制第一个,也是最大的一个圆形。 在看D3.js的时候,无意间看到了一个例子,觉得很有趣,像是会分裂的圆形马赛克。看了下代码,使用svg完成的,但是具体实现方式使得在手机端无法把玩,于是就自己实现了一个canvas版本的。代码很简单...

    starsfun 评论0 收藏0
  • 万圣节动画-canvas像素点

    摘要:万圣节到了,写一个小例子了解一下画图方法,可以实现一些有趣的效果,动画实现。移动路径方法把路径移动到画布中指定点,不创建线条。实现初始画布显示文字万圣节快乐闪电打雷反转画布重置画布总结万圣节快乐 万圣节到了,写一个小例子了解一下canvas画图方法,canvas可以实现一些有趣的效果,动画实现。以一个简单的页面实现了解一下基础的画图方法。原文链接 canvas可以实现一些有趣的效果,动...

    tainzhi 评论0 收藏0
  • 【30分钟学完】canvas动画|游戏基础(extra1-1):美图我也行

    摘要:前言本文是接续系列教程的,主要是介绍颜色系统在中的应用。本来是与一起成文的,因为莫名其妙的字数限制只能分割放送了。提供可以获取画布上任何一个像素,并可以自由的操作他们。绘制指定的位置绘制对象的内容。 前言 本文是接续系列教程的extra1,主要是介绍颜色系统在canvas中的应用。 本来是与extra1一起成文的,因为segmentfault莫名其妙的字数限制bug只能分割放送了。 ...

    Hydrogen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<