canvas图片转素描

素描滤镜:
最基础的算法就是:
1、去色;(去色公式:gray = 0.3 * red + 0.59 * green + 0.11 * blue)
2、复制去色图层,并且反色;
3、对反色图像进行高斯模糊;
4、模糊后的图像叠加模式选择颜色减淡效果。
减淡公式:C =MIN( A +(A×B)/(255-B),255),其中C为混合结果,A为去色后的像素点,B为高斯模糊后的像素点。

效果图:

sigma可以调节效果。(本来还想调节radius的,但一动就奔溃了)

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<div id="controls">
			<input type="file" name="" id="imgs" value=""/>
			<br />
			<!--<input type="range" name="" id="range_radius" value="10"  oninput="changeRadius()"/>
			radius:<span id="value_radius">1</span>
			<br />-->
			<input type="range" name="" id="range_sigma" value="40"  oninput="changeSigma()"/>
			sigma:<span id="value_sigma">0.8</span>
			<br />
			<a href="" download="canvas_love.png" id="save_href">下载</a>
		</div>
		<canvas id="canvas1" width="" height=""></canvas>
		<br>
		<canvas id="canvas2" width="" height=""></canvas>
		<script type="text/javascript">
			var eleImg = document.getElementById("imgs");
			var eleRadius = document.getElementById("range_radius");
			var eleSigma = document.getElementById("range_sigma");
			
			var valueRadius = document.getElementById("value_radius");
			var valueSigma = document.getElementById("value_sigma");
			
			var svaeHref = document.getElementById("save_href");
			
			var imgSrc = "img/2.jpg";
			var radius = 1;
			var sigma = 0.8;
			
			eleImg.addEventListener("input",function (e) {
				var fileObj = e.currentTarget.files[0]
				 if (window.FileReader) {    
		            var reader = new FileReader();    
		            reader.readAsDataURL(fileObj);    
		            //监听文件读取结束后事件    
		            reader.onloadend = function (e) {
		            	imgSrc = e.target.result;    //e.target.result就是最后的路径地址
		            	sketch()
		            };    
		       	} 
		    });
		    
		    var butSave = document.getElementById("save");

			function changeRadius() {
				valueRadius.innerText = eleRadius.value/10;
				radius = eleRadius.value/10;
				sketch()
			}
			
			function changeSigma() {
				valueSigma.innerText = eleSigma.value/50;
				sigma = eleSigma.value/50;
				sketch()
			}
			
			var canvas1 = document.querySelector("#canvas1");
		    var cxt1 = canvas1.getContext("2d");
		    
		    var canvas = document.querySelector("#canvas2");
		    var cxt = canvas.getContext("2d");
			
			function sketch() {
				cxt1.clearRect(0,0,canvas1.width,canvas1.height); 
				cxt.clearRect(0,0,canvas.width,canvas.height); 
				var img = new Image();
		        img.src = imgSrc;
		        img.onload = function () {
		        	
		            canvas1.width = 600;
		            canvas1.height = (img.height/img.width)*600;
		            cxt1.drawImage(img, 0, 0, canvas1.width, canvas1.height);
		            
		            canvas.width = 600;
		            canvas.height = (img.height/img.width)*600;
		            cxt.drawImage(img, 0, 0, canvas.width, canvas.height);
		            var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);  //对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值
		            var imageData_length = imageData.data.length/4;
//		            var originData = JSON.parse(JSON.stringify(imageData))

		            // 解析之后进行算法运算
		            var originData = [];
		            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;//去色
		                originData.push(gray)
		                originData.push(gray)
		                originData.push(gray)
		                originData.push(imageData.data[i * 4 + 3])
		                var anti_data = 255 - gray;//取反
		                

		                imageData.data[i * 4] = anti_data;
		                imageData.data[i * 4 + 1] = anti_data;
		                imageData.data[i * 4 + 2] = anti_data;
		            }
					imageData = gaussBlur(imageData, radius, sigma)//高斯模糊
					
					for (var i = 0; i < imageData_length; i++) {
		                var dodge_data = Math.min((originData[i*4] + (originData[i*4]*imageData.data[i * 4])/(255-imageData.data[i * 4])), 255)//减淡

		                imageData.data[i * 4] = dodge_data;
		                imageData.data[i * 4 + 1] = dodge_data;
		                imageData.data[i * 4 + 2] = dodge_data;
		            }
		            console.log(imageData)
		            cxt.putImageData(imageData, 0, 0);
		            var tempSrc = canvas.toDataURL("image/png");
			    	svaeHref.href=tempSrc;
		        }
			}
		        
		    sketch()
			
			function gaussBlur(imgData, radius, sigma) {
			    var pixes = imgData.data,
			        width = imgData.width,
			        height = imgData.height;
			
			    radius = radius || 5;
			    sigma = sigma || radius / 3;
			
			    var gaussEdge = radius * 2 + 1;    // 高斯矩阵的边长
			
			    var gaussMatrix = [],
			        gaussSum = 0,
			        a = 1 / (2 * sigma * sigma * Math.PI),
			        b = -a * Math.PI;
			
			    for (var i=-radius; i<=radius; i++) {
			        for (var j=-radius; j<=radius; j++) {
			            var gxy = a * Math.exp((i * i + j * j) * b);
			            gaussMatrix.push(gxy);
			            gaussSum += gxy;    // 得到高斯矩阵的和,用来归一化
			        }
			    }
			    var gaussNum = (radius + 1) * (radius + 1);
			    for (var i=0; i<gaussNum; i++) {
			        gaussMatrix[i] = gaussMatrix[i] / gaussSum;    // 除gaussSum是归一化
			    }
			
			    //console.log(gaussMatrix);
			
			    // 循环计算整个图像每个像素高斯处理之后的值
			    for (var x=0; x<width;x++) {
			        for (var y=0; y<height; y++) {
			            var r = 0,
			                g = 0,
			                b = 0;
			
			            //console.log(1);
			
			            // 计算每个点的高斯处理之后的值
			            for (var i=-radius; i<=radius; i++) {
			                // 处理边缘
			                var m = handleEdge(i, x, width);
			                for (var j=-radius; j<=radius; j++) {
			                    // 处理边缘
			                    var mm = handleEdge(j, y, height);
			
			                    var currentPixId = (mm * width + m) * 4;
			
			                    var jj = j + radius;
			                    var ii = i + radius;
			                    r += pixes[currentPixId] * gaussMatrix[jj * gaussEdge + ii];
			                    g += pixes[currentPixId + 1] * gaussMatrix[jj * gaussEdge + ii];
			                    b += pixes[currentPixId + 2] * gaussMatrix[jj * gaussEdge + ii];
			
			                }
			            }
			            var pixId = (y * width + x) * 4;
			
			            pixes[pixId] = ~~r;
			            pixes[pixId + 1] = ~~g;
			            pixes[pixId + 2] = ~~b;
			        }
			    }
			    imgData.data = pixes;
			    return imgData;
			}
			
			function handleEdge(i, x, w) {
			    var  m = x + i;
			    if (m < 0) {
			        m = -m;
			    } else if (m >= w) {
			        m = w + i - x;
			    }
			    return m;
			}
		</script>
	</body>
</html>

参考文章

1、http://www.360doc.com/content/18/0208/15/16915_728619698.shtml

2、https://blog.csdn.net/lynnandwei/article/details/43955021

3、https://segmentfault.com/q/1010000002609423

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值