当前位置: 首页 > news >正文

前端融合图片mask

之前实现了tif文件的融合,现在实现图片的融合,效果如下
在这里插入图片描述
第一张是融合右边两张图的结果
我的思路是:

  1. 初始使用canvas加载原图,此时未显示标注
  2. 点击显示标注后,将原图和mask图传给worker
  3. worker接受数据后,转为blob格式再经过createImageBitmap处理拿到宽高
  4. 接着使用OffscreenCanvas渲染原地形图
  5. 再创建一个OffscreenCanvas处理地形mask图
  6. 将该地形mask的imageData值拿到,循环并处理对应的颜色
  7. 把处理后的mask图重新绘制回去
  8. 将处理后的mask的OffscreenCanvas绘制在地形图OffscreenCanvas上
  9. 最后将最新的地形图OffscreenCanvas进行转换返回给主线程

这是index.html代码:

<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title></title><style type="text/css">* {margin: 0;padding: 0;}h1 {position: absolute;top: 0;z-index: 99;color: red;}</style>
</head><body><input id="checkSVGLabel" type="checkbox" name=""> 显隐标注<br><!-- <img id="defaultImg" src="" alt=""> --><canvas id="canvas"></canvas><script type="text/javascript">// const terrainImageUrl = 'http://192.168.10.159:5502/images/orz.png'; // 替换为你的地形图URLconst terrainImageUrl = 'http://192.168.10.159:5502/images/orz5.png'; // 替换为你的地形图URLconst maskImageUrl = 'http://192.168.10.159:5502/images/mask1.png'; // 替换为你的黑底白框图URL// const terrainImageUrl = 'http://192.168.10.159:5502/images/orz3.jpg'; // 替换为你的地形图URL// const maskImageUrl = 'http://192.168.10.159:5502/images/mask4.jpg'; // 替换为你的黑底白框图URLconst canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');const checkSVGLabel = document.getElementById('checkSVGLabel');// const defaultImg = document.getElementById('defaultImg');let changeImgUrl = terrainImageUrllet imageWorker = nullfunction handleMaskImg (e){if (e.target.checked && imageWorker) {mergeMaskImg(terrainImageUrl, maskImageUrl, 'mergeMask')} else {mergeMaskImg(terrainImageUrl, maskImageUrl)}}// 融合色块function mergeMaskImg (orz, mask, type){if (type === 'mergeMask') {imageWorker.postMessage({orz,mask,type: 'creatMaskImg'})} else {const image = new Image();image.src = orz;image.onload = function (){canvas.width = image.width;canvas.height = image.height;ctx.drawImage(image, 0, 0);}}}function clearWorker (){if (worker) {worker.terminate()}worker = null}window.onload = function (){mergeMaskImg(terrainImageUrl, maskImageUrl)imageWorker = new Worker("../js/imageWorker.js")imageWorker.onmessage = (e) =>{const { type } = e.data;if (type === 'putMaskImg') {// 读取影像// defaultImg.src = e.data.dataUrl// 使用画布console.log(e)const { imageBitmap, canvasWidth, canvasHeight } = e.data;canvas.width = canvasWidth;canvas.height = canvasHeight;ctx.drawImage(imageBitmap, 0, 0, canvasWidth, canvasHeight);}}}checkSVGLabel.addEventListener('change', handleMaskImg);</script>
</body></html>

这是worker代码

self.addEventListener('message', async ({ data }) => {if (data.type === 'creatMaskImg') {let { orz, mask } = data// 加载地形图和蒙版图像const [terrainImage, maskImage] = await Promise.all([loadImageBitmap(orz),loadImageBitmap(mask)])const canvasWidth = terrainImage.widthconst canvasHeight = terrainImage.heightconst offscreenCanvas = new OffscreenCanvas(canvasWidth, canvasHeight)const ctx = offscreenCanvas.getContext('2d')// 绘制地形图ctx.drawImage(terrainImage, 0, 0, canvasWidth, canvasHeight)// 创建一个临时canvas来处理蒙版const tempCanvas = new OffscreenCanvas(maskImage.width,maskImage.height)const tempCtx = tempCanvas.getContext('2d')// 将黑底白框图绘制到临时canvastempCtx.drawImage(maskImage, 0, 0)// 获取图像数据const maskImageData = tempCtx.getImageData(0,0,tempCanvas.width,tempCanvas.height)const imgData = maskImageData.datafor (let i = 0; i < imgData.length; i += 4) {// 获取当前像素的RGB值const red = imgData[i]const green = imgData[i + 1]const blue = imgData[i + 2]if (red === 0 && green === 0 && blue === 0) {imgData[i + 3] = 0 // 透明度设置为0} else {if (red === 255 && green === 255 && blue === 255) {// 黑色// imgData[i] = 0// imgData[i + 1] = 0// imgData[i + 2] = 0// 紫色imgData[i] = 254imgData[i + 1] = 0imgData[i + 2] = 255imgData[i + 3] = imgData[i + 3] * 0.5// 透明图// imgData[i] = null// imgData[i + 1] = null// imgData[i + 2] = null}}}// 将处理后的蒙版图像数据放回临时canvastempCtx.putImageData(maskImageData, 0, 0)// 将临时canvas上的蒙版绘制到地形图上ctx.drawImage(tempCanvas, 0, 0, canvasWidth, canvasHeight)// ----------------- 传blob图像数据// 将处理后的 offscreenCanvas 转换为 Blob// const blob = await offscreenCanvas.convertToBlob()// const dataUrl = await blobToDataURL(blob)// self.postMessage({// 	dataUrl,// 	canvasWidth,// 	canvasHeight,// 	type: 'putMaskImg'// })// ----------------- 传canvas数据// 将处理后的 offscreenCanvas 转换为 ImageBitmap 并返回到主线程const imageBitmap = offscreenCanvas.transferToImageBitmap()self.postMessage({ imageBitmap, canvasWidth, canvasHeight, type: 'putMaskImg' },[imageBitmap])}
})async function loadImageBitmap(url) {const response = await fetch(url)const blob = await response.blob()return createImageBitmap(blob)
}function blobToDataURL(blob) {return new Promise((resolve, reject) => {const reader = new FileReader()reader.onloadend = () => resolve(reader.result)reader.onerror = rejectreader.readAsDataURL(blob)})
}

在worker中其实还可以将mask图片的黑色区域进行转换,也可以设置透明值,非常方便,如果不需要复杂的颜色处理,在处理后还可以结合mask-image去实现蒙版效果。

相关文章:

  • 高级java每日一道面试题-2025年4月13日-微服务篇[Nacos篇]-Nacos如何处理网络分区情况下的服务可用性问题?
  • ubantu18.04(Hadoop3.1.3)之MapReduce编程
  • pnpm解决幽灵依赖问题
  • Model Context Protocol (MCP) 开放协议对医疗多模态数据整合的分析路径【附代码】
  • Kaamel隐私与安全分析报告:Microsoft Recall功能评估与风险控制
  • hadoop和Yarn的基本介绍
  • 使用Java动态数据生成PDF报告:简化您的报告导出流程
  • AI语音助手 React 组件使用js-audio-recorder实现,将获取到的语音转成base64发送给后端,后端接口返回文本内容
  • kafka菜鸟教程
  • Android 证书 是什么
  • 在服务器上安装安装mysql
  • C#获取当前方法的命名空间、类名称、方法名称以及方法的参数信息
  • 【区块链通用服务平台及组件】京北方分布式身份管理平台 | FISCO BCOS 应用案例
  • axios 模拟实现
  • AI驱动商业变革:零售行业的智能化跃迁
  • NOIP2013提高组.货车运输
  • vue,uniapp解决h5跨域问题
  • Linux中的管道
  • UE5有些场景的导航生成失败解决方法
  • PHP使用pandoc把markdown文件转为word
  • 第六次“太空会师”,神舟二十号3名航天员顺利进驻中国空间站
  • 我国民营经济首季运行向新向好,对国民经济发展形成有力支撑
  • 从神舟五号到神舟二十号,每次任务标识藏着哪些逐梦星辰的密码
  • 在因关税战爆火的敦煌网上,美国人爱买什么中国商品
  • 福建浯屿岛垃圾排海追踪:堆存已清理,当地称今后会日产日清日运
  • 盗播热门影视剧、电影被追究刑事附带民事责任,最高法发声