canvas自从出来了以后,在前端的图像处理上面提供了各类各样的遍历,虽然不少的操做其实都是要应用到算法的,可是这个也给前端提供了不少的可能性,其中最终要的一个canvas函数(至少我认为)就是getImageData,这个函数能够提取图像每一个像素的RGBA值。由于有这个函数全部才有丰富多彩的canvas图像处理。php
2.1 获取一个canvas对象html
<canvas id="test"></canvas> <script> var test = document.querySelector("#test");// 方法一 var test_1=document.getElementById("test");// 方法二 console.log(test); console.log(test_1); </script>
2.2 建立一个画布的空间类型(2D,3D)前端
建立一个2D的画布算法
var ctx = test.getContext("2d");
2.3 getImageData对象canvas
getImageData对象能够获取画布中的图片对应的全部像素的RGBA值,这个有利于咱们对图片进行从新的计算。在使用这个属性的时候,须要配置好HTTP的访问环境。函数
2.4 Uint8ClampedArray动画
这个表明的是一个无类型8位的字符串,也就是说明最多存储到255this
2.5 Uint8ClampedArray与getImageData对象spa
Uint8ClampedArray包含在getImageData对象中,getImageData除了有Uint8ClampedArray以外,还有获取图片数据的长度和宽度。.net
经过canvas来渲染原图,首选咱们在网上随意找一张图片。
·
window.onload = function () { var img = new Image(); img.src = "rx.jpg"; // 加载完成图片以后才可以执行canvas的操做 img.onload = function () { var canvas = document.querySelector("#canvas"); var cxt = canvas.getContext("2d"); canvas.width=293; canvas.height=220; cxt.drawImage(img, 0, 0, 293, 220); } }
其中canvas的width,height属性都是必需要设置的,不设置的话,canvas会采用默认的width=300,height=150来设置图片。
图片反色的原理其实很简单很少作解释:将图片中的每个元素进行以下的公式运算就能够获得最终的结果
window.onload = function () { var img = new Image(); img.src = "rx.jpg"; img.onload = function () { var canvas = document.querySelector("#canvas"); var cxt = canvas.getContext("2d"); canvas.width = 293; canvas.height = 220; cxt.drawImage(img, 0, 0, canvas.width, canvas.height); var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height); var imageData_length = imageData.data.length / 4; // 解析以后进行算法运算 for (var i = 0; i < imageData_length; i++) { imageData.data[i * 4] = 255 - imageData.data[i * 4]; imageData.data[i * 4 + 1] = 255 - imageData.data[i * 4 + 1]; imageData.data[i * 4 + 2] = 255 - imageData.data[i * 4 + 2]; } cxt.putImageData(imageData, 0, 0); } }
运行以后的效果以下:
这里说的去色效果与第二种效果不一样的是,去色效果至关于就是老旧相机拍出来的黑白照片。
要获得去色效果的照片有不少种方法,可是卤煮比较推崇的作法是采用基于人眼感受的加权平均数来实现,这个算法的原理是采用人眼对RGB不一样颜色的敏感程度不一样,而后经过得出的加权平均数来运算出最后的结果
Gray = (Red * 0.3 + Green * 0.59 + Blue * 0.11)
代码以下实现:
window.onload = function () { var img = new Image(); img.src = "rx.jpg"; img.onload = function () { var canvas = document.querySelector("#canvas"); var cxt = canvas.getContext("2d"); canvas.width = 293; canvas.height = 220; cxt.drawImage(img, 0, 0, canvas.width, canvas.height); var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height); var imageData_length = imageData.data.length / 4; // 解析以后进行算法运算 for (var i = 0; i < imageData_length; i++) { var red = imageData.data[i * 4]; var green = imageData.data[i * 4 + 1]; var blue = imageData.data[i * 4 + 2]; var gray = 0.3 * red + 0.59 * green + 0.11 * blue; imageData.data[i * 4] = gray; imageData.data[i * 4 + 1] = gray; imageData.data[i * 4 + 2] = gray; } cxt.putImageData(imageData, 0, 0); } }
运行效果以下:
单颜色效果原理就是将当前像素的其余色值去除。
假设咱们要实现的单颜色效果是红色,那么实现的代码以下:
window.onload = function () { var img = new Image(); img.src = "rx.jpg"; img.onload = function () { var canvas = document.querySelector("#canvas"); var cxt = canvas.getContext("2d"); canvas.width = 293; canvas.height = 220; cxt.drawImage(img, 0, 0, canvas.width, canvas.height); var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height); var imageData_length = imageData.data.length / 4; // 解析以后进行算法运算 for (var i = 0; i < imageData_length; i++) { imageData.data[i * 4 + 1] = 0; imageData.data[i * 4 + 2] = 0; } cxt.putImageData(imageData, 0, 0); } }
效果图:
中国版画不一样于去色和反色的效果,在中国版画的效果中除了黑就是白色,不存在其余的颜色,下面就是一张传统的中国版画的效果。
这个的实现算法比较的灵活通常是根据你要获得的效果来进行参数配置的,原理就是经过判断当前元素的色值是否高于这个给定值,高于咱们就显示为黑色,小于咱们就显示为白色这样的一种方法来实现的。
按照卤煮通常的设置值来讲会设置为126.由于126是2的8次方的中间数。相对来讲比较的对称
实现的代码以下:
window.onload = function () { var img = new Image(); img.src = "rx.jpg"; img.onload = function () { var canvas = document.querySelector("#canvas"); var cxt = canvas.getContext("2d"); canvas.width = 293; canvas.height = 220; cxt.drawImage(img, 0, 0, canvas.width, canvas.height); var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height); var imageData_length = imageData.data.length / 4; // 解析以后进行算法运算 for (var i = 0; i < imageData_length; i++) { var red = imageData.data[i * 4]; var green = imageData.data[i * 4 + 1]; var blue = imageData.data[i * 4 + 2]; var gray = 0.3 * red + 0.59 * green + 0.11 * blue; var new_black; if (gray > 126) { new_black = 255; } else { new_black = 0; } imageData.data[i * 4] = new_black; imageData.data[i * 4 + 1] = new_black; imageData.data[i * 4 + 2] = new_black; } cxt.putImageData(imageData, 0, 0); } }
运行的效果以下:
若是是咱们要渲染更多的黑颜色的话,咱们应该要将值调高,反之将其调低,下面咱们把值调到150运行一下:
高斯模糊是一种两维的卷积模糊操做,简单的介绍就是经过让图片的每一个像素与四周的像素按照某种权重进行分布求值,要了解具体的同窗能够戳戳这里。
这里咱们就展现结论,推导不作介绍(二维高斯分布函数):
咱们直接贴出实现的代码:
function gaussBlur(imgData) { console.log(imgData); var pixes = imgData.data; var width = imgData.width; var height = imgData.height; var gaussMatrix = [], gaussSum = 0, x, y, r, g, b, a, i, j, k, len; var radius = 30; var sigma = 5; a = 1 / (Math.sqrt(2 * Math.PI) * sigma); b = -1 / (2 * sigma * sigma); //生成高斯矩阵 for (i = 0, x = -radius; x <= radius; x++, i++){ g = a * Math.exp(b * x * x); gaussMatrix[i] = g; gaussSum += g; } //归一化, 保证高斯矩阵的值在[0,1]之间 for (i = 0, len = gaussMatrix.length; i < len; i++) { gaussMatrix[i] /= gaussSum; } //x 方向一维高斯运算 for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { r = g = b = a = 0; gaussSum = 0; for(j = -radius; j <= radius; j++){ k = x + j; if(k >= 0 && k < width){//确保 k 没超出 x 的范围 //r,g,b,a 四个一组 i = (y * width + k) * 4; r += pixes[i] * gaussMatrix[j + radius]; g += pixes[i + 1] * gaussMatrix[j + radius]; b += pixes[i + 2] * gaussMatrix[j + radius]; // a += pixes[i + 3] * gaussMatrix[j]; gaussSum += gaussMatrix[j + radius]; } } i = (y * width + x) * 4; // 除以 gaussSum 是为了消除处于边缘的像素, 高斯运算不足的问题 // console.log(gaussSum) pixes[i] = r / gaussSum; pixes[i + 1] = g / gaussSum; pixes[i + 2] = b / gaussSum; // pixes[i + 3] = a ; } } //y 方向一维高斯运算 for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { r = g = b = a = 0; gaussSum = 0; for(j = -radius; j <= radius; j++){ k = y + j; if(k >= 0 && k < height){//确保 k 没超出 y 的范围 i = (k * width + x) * 4; r += pixes[i] * gaussMatrix[j + radius]; g += pixes[i + 1] * gaussMatrix[j + radius]; b += pixes[i + 2] * gaussMatrix[j + radius]; // a += pixes[i + 3] * gaussMatrix[j]; gaussSum += gaussMatrix[j + radius]; } } i = (y * width + x) * 4; pixes[i] = r / gaussSum; pixes[i + 1] = g / gaussSum; pixes[i + 2] = b / gaussSum; } } console.log(imgData); return imgData; }
运行以后的效果以下:
这里要感谢CSDN的算法专家gloomyfish,他的博文给我提供了一个好的思路,同时根据他的一个代码逻辑咱们能够得出以下的公式:
(C常量,Xa后一个像素的RGB,Xb前一个像素的RGB)
其中color表明的是最后的色值,Xa和Xb表明的是当前像素先后两点的RGB(中的某一个值),C表明的是一个常量【根据你的具体须要来定】
原理就是将某个像素与周边的差值较大的检测出来,而后替换成为255,通常咱们将这个常量C设置成为128【255的一半】
/** * after pixel value - before pixel value + 128 * 代码引用自 gloomyfish * 浮雕效果 */ reliefProcess: function(context, canvasData) { //caontext 画布对象 document.querySelector().getContext("2d"); // conavas document.querySelector().getContext("2d").getImageData(); console.log("Canvas Filter - relief process"); var tempCanvasData = this.copyImageData(context, canvasData); for ( var x = 0; x < tempCanvasData.width-1; x++) { for ( var y = 0; y < tempCanvasData.height-1; y++) { // Index of the pixel in the array var idx = (x + y * tempCanvasData.width) * 4; var bidx = ((x-1) + y * tempCanvasData.width) * 4; var aidx = ((x+1) + y * tempCanvasData.width) * 4; // calculate new RGB value var nr = tempCanvasData.data[aidx + 0] - tempCanvasData.data[bidx + 0] + 128; var ng = tempCanvasData.data[aidx + 1] - tempCanvasData.data[bidx + 1] + 128; var nb = tempCanvasData.data[aidx + 2] - tempCanvasData.data[bidx + 2] + 128; nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr); ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng); nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb); // assign new pixel value canvasData.data[idx + 0] = nr; // Red channel canvasData.data[idx + 1] = ng; // Green channel canvasData.data[idx + 2] = nb; // Blue channel canvasData.data[idx + 3] = 255; // Alpha channel } } },
运行的图像以下:
其中常量的数值越大,浮雕的颜色越浅,反之加深。咱们把它设置到50看下效果:
刻雕效果与浮雕效果基本同样,就是要调整公式里面的Xa和Xb的位置,调整以下:
因为canvas涉及到的知识点比较的深奥,因此里面有不少的内容无法再这里一一的进行说明,这一篇文章也就是对于canvas实际应用的一个简单的说明,在图形学方面,磨皮处理和高通滤波,低通滤波等等方面的处理尚未实现,在一些粒子化,动画,碰撞方面也不能一一道来,深表遗憾