欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

canvas图片转素描

程序员文章站 2024-03-12 16:46:50
...

素描滤镜:
最基础的算法就是:
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为高斯模糊后的像素点。

效果图:

canvas图片转素描

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

相关标签: 前端 js canvas