<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>轮廓加权融合+卷积去模糊工具</title>
<style>
body {text-align:center;font-family:Arial;margin:20px;}
canvas {border:2px solid #333;margin:10px auto;display:block;background:#fff;}
button {padding:8px 20px;font-size:16px;cursor:pointer;background:#4CAF50;color:white;border:none;border-radius:4px;margin:10px;}
button:hover {background:#45a049;}
.container {width:800px;margin:0 auto;}
.slider {margin:15px auto;width:400px;}
</style>
</head>
<body>
<div class="container">
<h3>初始模糊图(模糊程度可调)</h3>
<input type="range" min="1" max="10" value="3" class="slider" id="blurSlider">
<span id="blurValue">模糊程度:3</span>
<canvas id="blurCanvas" width="400" height="300"></canvas>
<h3>最终去模糊结果图</h3>
<canvas id="resultCanvas" width="400" height="300"></canvas>
<button onclick="reset()">重置生成图形</button>
<button onclick="startProcess()">开始轮廓融合+卷积去模糊</button>
</div>
<script>
let blurCtx = blurCanvas.getContext('2d'), resCtx = resultCanvas.getContext('2d');
let blurSlider = document.getElementById('blurSlider');
let blurValue = document.getElementById('blurValue');
let originalImgData, blurLevel = 3;
let hiddenFrames = [];
blurSlider.oninput = function() {
blurLevel = parseInt(this.value);
blurValue.textContent = `模糊程度:${blurLevel}`;
drawRandomGraph();
generateBlurFrames();
};
// 原有核心:生成图形
function drawRandomGraph() {
blurCtx.clearRect(0,0,400,300);
for(let k=0;k<4;k++){
let n=3+Math.floor(Math.random()*5),x0=200+(Math.random()-0.5)*80,y0=150+(Math.random()-0.5)*80;
blurCtx.beginPath();
for(let i=0;i<n;i++) blurCtx.lineTo(x0+Math.cos(i/n*2*Math.PI)*(30+k*15),y0+Math.sin(i/n*2*Math.PI)*(30+k*15));
blurCtx.closePath();
blurCtx.fillStyle=`rgb(${Math.random()*255},${Math.random()*255},${Math.random()*255})`;
blurCtx.fill();
}
for(let i=0;i<3;i++){
let r=15+Math.random()*10,x=150+Math.random()*100,y=100+Math.random()*100;
blurCtx.beginPath();blurCtx.arc(x,y,r,0,2*Math.PI);
blurCtx.fillStyle=`rgb(${Math.random()*255},${Math.random()*255},${Math.random()*255})`;
blurCtx.fill();
}
originalImgData = blurCtx.getImageData(0,0,400,300);
}
// 新增:生成隐式模糊帧
function generateBlurFrames() {
hiddenFrames = [];
let w = 400, h = 300;
for(let f=0;f<5;f++){
let tempCtx = document.createElement('canvas').getContext('2d');
tempCtx.canvas.width = w;
tempCtx.canvas.height = h;
tempCtx.putImageData(originalImgData, 0, 0);
tempCtx.filter = `blur(${blurLevel}px)`;
tempCtx.drawImage(tempCtx.canvas, f*2, f*1, w, h, 0, 0, w, h);
hiddenFrames.push(tempCtx.getImageData(0,0,w,h));
}
blurCtx.filter = `blur(${blurLevel}px)`;
blurCtx.drawImage(blurCtx.canvas, 0, 0, w, h, 0, 0, w, h);
blurCtx.filter = 'none';
}
// 原有核心:提取轮廓 → 新增边缘淡化
function extractOutline(imgData) {
let w = imgData.width, h = imgData.height;
let outlineData = new ImageData(w, h);
let data = imgData.data, outData = outlineData.data;
function wheelMatrix(x,y,cx,cy,angle) {
let dx=x-cx, dy=y-cy;
let rotX=dx*Math.cos(angle)-dy*Math.sin(angle);
let dist=Math.sqrt(rotX**2+dy**2);
return dist%10 < 4 ? 1 : 0;
}
for(let round=0;round<5;round++){
let angle=round*Math.PI/4, cx=200+round*12, cy=150+round*8;
for(let y=0;y<h;y++)for(let x=0;x<w;x++){
let i=(y*w+x)*4;
if(!wheelMatrix(x,y,cx,cy,angle)) continue;
let isEdge=false;
for(let dy=-2;dy<=2;dy++)for(let dx=-2;dx<=2;dx++){
if(dx===0&&dy===0) continue;
let nx=x+dx, ny=y+dy;
if(nx>=0&&nx<w&&ny>=0&&ny<h){
let ni=(ny*w+nx)*4;
isEdge|=Math.abs(data[i]-data[ni])>15||Math.abs(data[i+1]-data[ni+1])>15||Math.abs(data[i+2]-data[ni+2])>15;
}
}
// 边缘颜色淡化:降低轮廓亮度,避免边缘过亮
outData[i] = isEdge ? 180 : 0;
outData[i+1] = isEdge ? 180 : 0;
outData[i+2] = isEdge ? 180 : 0;
outData[i+3] = isEdge ? 120 : 0; // 降低透明度进一步淡化
}
}
return outlineData;
}
// 加权融合
function weightFusion(imgData, outlineData, alpha = 0.7) {
let w = imgData.width, h = imgData.height;
let fusedData = new ImageData(w, h);
let d1 = imgData.data, d2 = outlineData.data, d3 = fusedData.data;
for(let i=0;i<d1.length;i+=4){
d3[i] = Math.round(d1[i] * alpha + d2[i] * (1 - alpha));
d3[i+1] = Math.round(d1[i+1] * alpha + d2[i+1] * (1 - alpha));
d3[i+2] = Math.round(d1[i+2] * alpha + d2[i+2] * (1 - alpha));
d3[i+3] = 255;
}
return fusedData;
}
// 局部卷积
function localConvolution(fusedData, frames) {
let w = fusedData.width, h = fusedData.height;
let convData = new ImageData(w, h);
let d = fusedData.data, cd = convData.data;
let kernel = [1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9];
let allFrames = [fusedData, ...frames];
for(let y=1;y<h-1;y++){
for(let x=1;x<w-1;x++){
let i = (y*w + x)*4;
let r = 0, g = 0, b = 0;
for(let dy=-1;dy<=1;dy++){
for(let dx=-1;dx<=1;dx++){
let idx = ((y+dy)*w + (x+dx))*4;
let k = (dy+1)*3 + (dx+1);
for(let f=0;f<allFrames.length;f++){
let fd = allFrames[f].data;
r += fd[idx] * kernel[k] / allFrames.length;
g += fd[idx+1] * kernel[k] / allFrames.length;
b += fd[idx+2] * kernel[k] / allFrames.length;
}
}
}
cd[i] = Math.round(r);
cd[i+1] = Math.round(g);
cd[i+2] = Math.round(b);
cd[i+3] = 255;
}
}
return convData;
}
// 新增:多轮原图叠加函数
function overlayOriginal(targetData, originalData, times = 3, alpha = 0.2) {
let d1 = targetData.data, d2 = originalData.data;
for(let t=0; t<times; t++){
for(let i=0; i<d1.length; i+=4){
d1[i] = Math.round(d1[i] * (1 - alpha) + d2[i] * alpha);
d1[i+1] = Math.round(d1[i+1] * (1 - alpha) + d2[i+1] * alpha);
d1[i+2] = Math.round(d1[i+2] * (1 - alpha) + d2[i+2] * alpha);
}
}
return targetData;
}
// 核心流程:新增 多轮原图叠加
function startProcess() {
let currentData = hiddenFrames[0];
// 多轮轮廓融合
for(let i=0;i<5;i++){
let outline = extractOutline(currentData);
currentData = weightFusion(currentData, outline);
}
// 卷积去模糊
let convData = localConvolution(currentData, hiddenFrames.slice(1));
// 关键修改:多轮与原图叠加,还原细节+淡化边缘
let finalData = overlayOriginal(convData, originalImgData, 4, 0.15);
resCtx.putImageData(finalData, 0, 0);
}
function reset() {
drawRandomGraph();
generateBlurFrames();
resCtx.clearRect(0,0,400,300);
}
window.onload = function() {
drawRandomGraph();
generateBlurFrames();
};
</script>
</body>
</html>