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为高斯模糊后的像素点。
效果图:
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
上一篇: JavaWeb 简单分页实现代码