<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<title>高斯模糊</title>
</head>
<body>
<div id="wrap" class="wrap">
<img src="img/12338563.jpg" alt="" id="imageSource" height="500" width="800"/>
<canvas id="myCanvas"></canvas>
</div>
<script type="text/javascript">
//-------------------------------做一个基于canvas的【图片上传,剪切】的插件
//---------------------------------测试需在服务器环境下
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var image = document.getElementById("imageSource");
// re-size the canvas deminsion
console.log(image.width)
canvas.width = image.width;
canvas.height = image.height;
// get 2D render object
var context = canvas.getContext("2d");
context.drawImage(image, 0, 0,canvas.width,canvas.height);
var canvasData = context.getImageData(0, 0, canvas.width, canvas.height); //获取图片信息
//对于一个数组来说,它的每一个元素并不拥有坐标,因此需要写一个方法,也就是告诉【x,y,radius】,就会返还一个数组,当然首先要确定的是【width,height】因为只有这样才能够给数组一个坐标
//对于canvas来说,确定【width,height】就确定了【canvasData.data】的长度为【width*height*4】
//但是坐标范围用width,height来固定
//-------------------------------------------------高斯模糊开始------------------------------------------------------
var radius = 20 ; //定义模糊半径
var quan = getQuan(radius);
var quanSub = ArrSub(quan);
quan = jiaQuan(quan,quanSub); //获取权值
var canvasDataCtrl = canvasData ;
var width = canvas.width ,
height = canvas.height ;
console.log(new Date().getSeconds()) //高斯模糊开始时间
for (var i=0;i<width ;i++ )
{
for (var j=0;j<height ;j++ )
{
var index= (width*4)*j+i*4;
canvasDataCtrl.data[index] = getValue(i,j,0,quan); //r
canvasDataCtrl.data[index+1] = getValue(i,j,1,quan); //g
canvasDataCtrl.data[index+2] = getValue(i,j,2,quan); //b
canvasDataCtrl.data[index+3] = getValue(i,j,3,quan); //a
}
}
context.putImageData(canvasDataCtrl, 0, 0);
console.log(new Date().getSeconds()) //高斯模糊结束时间
//console.log(value)
//在chrome上运行时间大概有30s,运行这么长时间,肯定是算法问题,网上的StackBlur运行时间就很短
//在计算量上,如果图片是像素是500×800,那这张图片所包含的rgba信息就有160,0000 之多
//再加上要对每个像素的rgba值进行高斯转换,计算量就相当之大了,怎么解决呢
console.log('模糊完成')
function gaosi(x,y,a){ //根据高斯二维公式,获取点的高斯值
var e = Math.E ;
var pi = Math.PI ;
return 1/(2*pi*a*a)*Math.pow(e,-((x*x+y*y)/(2*a*a)))
}
//假设radius=x,那么会获得一个(2*x+1)×(2*x+1)的数组矩阵
//数组第一个元素的坐标是【-x,x】
function getQuan(radius){ //获取每个点的高斯值,返回数组
var quan = []
for (var i=-radius;i<=radius ;i++ )
{
for (var j=radius;j>=-radius ;j-- )
{
quan.push(gaosi(i,j,20));
}
}
return quan ;
}
function ArrSub(arr){ //返回高斯数组所有元素的值的和
var sub = 0 ;
for (var i=0,len=quan.length;i<len ;i++ )
{
sub += quan[i] ;
}
return sub ;
}
function jiaQuan(arr,quanSub){ //获取权的数组
for (var i=0,len=arr.length;i<len ;i++ )
{
arr[i] = arr[i]/quanSub;
}
return arr ;
}
function getValue(x,y,index,quan){ //根据坐标以及rgba[index]来算出高斯模糊的最终值
var imgdata = getInfoArr(x,y,index)
var value = 0 ;
for (var i=0,len=imgdata.length;i<len ;i++ )
{
value += imgdata[i]*quan[i] ;
}
return Math.round(value) ;//返回整数
}
function getInfo(x,y,index){ //返回点的【rgba】值
if (x<0)
{
x=-x
}else if (x>width-1)
{
x=2*(width-1)-x
}
if (y<0)
{
y=-y
}else if (y>height-1)
{
y=2*(height-1)-y
}
var i = (width*4)*y+x*4+index;
return canvasData.data[i]
}
function getInfoArr(x,y,index){ //根据坐标和radius【模糊半径】,返回要和权数组相乘的数组
var arr = [];
for (var i=x-radius;i<=x+radius ;i++ )
{
for (var j=y+radius;j>=y-radius ;j-- )
{
arr.push(getInfo(i,j,index))
}
}
return arr ;
}
};
</script>
</body>
</html>
最近看了阮一峰老师关于实现高斯模糊效果的博客,自己就用js和canvas写了这么一个效果
无奈执行时间太长,看stackblur的源码,又看不太懂
希望大家指教一下
高斯模糊有两种方案做:
测试结果:
结果图:
实现代码如下:
代码较长,建议移步到我的博客看代码
html:
javascript: