Canvas实现盒模糊效果时如何仅对指定颜色区域应用模糊
仅对指定颜色生效的盒模糊实现方案
你现有代码已经具备目标色识别、原始像素备份、3x3盒模糊计算的核心逻辑,只需要在模糊计算前增加目标色判断,非目标色像素直接保留原始值即可。需要注意你原有全图模糊代码存在通道采样错误,会导致模糊后色偏,修正后的完整可运行代码如下:
var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); var img = document.getElementById("scream"); ctx.drawImage(img, 0, 0); var imgData = ctx.getImageData(0, 0, c.width, c.height); var px = imgData.data; // 存储完全未修改的原始像素副本,所有模糊采样都从该副本取值,避免逐像素修改时污染计算结果 var tmPx = new Uint8ClampedArray(px); const imgWidth = imgData.width; // 目标色值,完全复用你之前颜色反演逻辑的判断条件 const targetR = 243, targetG = 83, targetB = 37, targetA = 255; // 按像素遍历,每个像素对应4个索引位(R/G/B/A) for (let i = 0; i < px.length; i += 4) { // 判断当前像素是否为目标色 const isTarget = tmPx[i] === targetR && tmPx[i+1] === targetG && tmPx[i+2] === targetB && tmPx[i+3] === targetA; if (!isTarget) { // 非目标色直接保留原始值,不做模糊处理 px[i] = tmPx[i]; px[i+1] = tmPx[i+1]; px[i+2] = tmPx[i+2]; px[i+3] = tmPx[i+3]; continue; } // 目标色像素执行3x3盒模糊计算,每个通道单独采样对应位置的原始值 // R通道计算 px[i] = ( tmPx[i] + (tmPx[i - 4] ?? tmPx[i]) + (tmPx[i + 4] ?? tmPx[i]) + (tmPx[i - 4 * imgWidth] ?? tmPx[i]) + (tmPx[i + 4 * imgWidth] ?? tmPx[i]) + (tmPx[i - 4 * imgWidth - 4] ?? tmPx[i]) + (tmPx[i + 4 * imgWidth + 4] ?? tmPx[i]) + (tmPx[i - 4 * imgWidth + 4] ?? tmPx[i]) + (tmPx[i + 4 * imgWidth - 4] ?? tmPx[i]) ) / 9; // G通道计算 px[i+1] = ( tmPx[i+1] + (tmPx[i - 4 + 1] ?? tmPx[i+1]) + (tmPx[i + 4 + 1] ?? tmPx[i+1]) + (tmPx[i - 4 * imgWidth + 1] ?? tmPx[i+1]) + (tmPx[i + 4 * imgWidth + 1] ?? tmPx[i+1]) + (tmPx[i - 4 * imgWidth - 4 + 1] ?? tmPx[i+1]) + (tmPx[i + 4 * imgWidth + 4 + 1] ?? tmPx[i+1]) + (tmPx[i - 4 * imgWidth + 4 + 1] ?? tmPx[i+1]) + (tmPx[i + 4 * imgWidth - 4 + 1] ?? tmPx[i+1]) ) / 9; // B通道计算 px[i+2] = ( tmPx[i+2] + (tmPx[i - 4 + 2] ?? tmPx[i+2]) + (tmPx[i + 4 + 2] ?? tmPx[i+2]) + (tmPx[i - 4 * imgWidth + 2] ?? tmPx[i+2]) + (tmPx[i + 4 * imgWidth + 2] ?? tmPx[i+2]) + (tmPx[i - 4 * imgWidth - 4 + 2] ?? tmPx[i+2]) + (tmPx[i + 4 * imgWidth + 4 + 2] ?? tmPx[i+2]) + (tmPx[i - 4 * imgWidth + 4 + 2] ?? tmPx[i+2]) + (tmPx[i + 4 * imgWidth - 4 + 2] ?? tmPx[i+2]) ) / 9; // Alpha通道保持原始值 px[i+3] = tmPx[i+3]; } ctx.putImageData(imgData, 0, 0); img.remove()
关键调整说明
- 颜色判断逻辑完全复用你之前写反演效果时的规则,如果需要增加颜色容差(允许相近颜色也被模糊),直接修改
isTarget的判断条件即可 - 修正了原全图模糊代码的通道错位问题:原代码计算G、B通道模糊值时,邻域采样始终取R通道位置的数值,会导致模糊后颜色偏移,上述代码为R/G/B三个通道分别做了对应位置的邻域采样
- 用空值合并运算符
??替代原逻辑的||,避免邻域像素值为0时被错误判定为越界 - 如果需要实现更自然的区域内模糊(模糊计算不混入周边非目标色的像素值),只需要在邻域采样时增加一层颜色判断:仅累加符合目标色的邻域像素值,最后用累加值除以实际参与计算的像素数量即可,不会出现目标色边缘晕入其他颜色的问题
内容的提问来源于stack exchange,提问作者Monarch
相关产品推荐
相关产品推荐

