如何将图像处理代码完全迁移到Web Worker中

huangapple go评论55阅读模式
英文:

How to move image processing code entirely to web-worker

问题

我想将完全控制权转交给工作线程,并使用离屏画布。但有一个Image()与UI关联,可以参考函数makeImg。我并不打算显示这个图像,它纯粹用于构建网格的数据。突出显示的代码完全依赖于UI。是否可能(以及如何确切地实现)在完全在Web工作线程中完成它,直到计算完成并生成了最终网格,准备好显示?例如,以下位图包含高度信息:
如何将图像处理代码完全迁移到Web Worker中
不带透视效果的页面,包含完整的源代码,在这里
我正在使用上面的位图作为高度图来构建地形,代码在GitHub上,在页面heightMap.html中。因此,我使用像素值来生成顶点、计算法线和纹理坐标。结果是地形将在页面中显示,此处显示不带纹理:
如何将图像处理代码完全迁移到Web Worker中

async function readImgHeightMap(src, crossOrigin) {
   return new Promise((resolve, reject) => {
      readImg(src, crossOrigin).then((imgData) => {
         let heightmap = [];
         // j, row -- z coordinate; i, column -- x coordinate
         // imgData.data, height -- y coordinate
         for (let j = 0, j0 = 0; j < imgData.height; j++, j0 += imgData.width * 4) {
            heightmap[j] = [];
            for (let i = 0, i0 = 0; i < imgData.width; i++, i0 += 4)
               heightmap[j][i] = imgData.data[j0 + i0];
         }
         resolve({ data: heightmap, height: imgData.height, width: imgData.width });
      });
   });
}

async function readImg(src, crossOrigin) {
   return new Promise((resolve, reject) => {
      makeOffscreenFromImg(src, crossOrigin).then((canvas) => {
         let ctx = canvas.getContext("2d");
         let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height, { colorSpace: "srgb" });
         resolve(imgData);
      });
   });
}

async function makeOffscreenFromImg(src, crossOrigin) {
   let img = makeImg(src, crossOrigin);
   return new Promise((resolve, reject) => {
      img.addEventListener('load', () => {
         let cnv = new OffscreenCanvas(img.width, img.height);
         cnv.getContext("2d").drawImage(img, 0, 0);
         resolve(cnv);
      });
      img.addEventListener('error', (event) => { console.log(event); reject(event); });
   });
}

function makeImg(src, crossOrigin) {
   let image = new Image();
   let canvas = document.createElement("canvas");
   if (crossOrigin) image.crossOrigin = crossOrigin;
   image.src = src;
   return image;
}

##################
PS: 以防万一,要从不同角度查看陨石坑,可以在按住SHIFT键时用鼠标移动摄像机,或在按住CTRL键时旋转摄像机。还可以通过点击事件进行永久动画,或在移动设备上进行轻触。
PS1: 请不要将高度图像用于个人用途。这些图片有商业版权。

英文:

I want to transfer full control to worker and use off screen canvas. But there is an Image() which is tied to UI, see function makeImg. I am not intending to show the image, it has pure data usage for building a mesh. The highlighted code fully depends on UI. Is it possible (and how exactly) to do it entirely in web worker, without interchanging data with UI until calculations done and the final mesh fully generated, ready to be shown? For instance following bitmap contains the heights:
如何将图像处理代码完全迁移到Web Worker中
The page without perspective with full source codes is here.
I am building height terrain using above bitmap as heightmap, code is here on GitHub, in the page heightMap.html. So, I use pixel values being used to generate vertices, calculate normals, texture coordinate. The result is the terrain going to be shown in the page, here shown without texture:
如何将图像处理代码完全迁移到Web Worker中

async function readImgHeightMap (src, crossOrigin) {
   return new Promise ((resolve, reject) =&gt; {
      readImg (src, crossOrigin).then ((imgData) =&gt; {
         let heightmap = [];
         //j, row -- z coordinate; i, column -- x coordinate
         //imgData.data, height -- y coordinate
         for (let j = 0, j0 = 0; j &lt; imgData.height; j++, j0 += imgData.width * 4) {
            heightmap[j] = [];
            for (let i = 0, i0 = 0; i &lt; imgData.width; i++, i0 += 4)
               heightmap[j][i] = imgData.data[j0 + i0];
         }
		 resolve( {data:heightmap, height:imgData.height, width:imgData.width} );
	  });
   });
}

async function readImg (src, crossOrigin) {
   return new Promise  ( (resolve, reject) =&gt; {
      makeOffscreenFromImg (src, crossOrigin).then((canvas) =&gt; {
         let ctx     = canvas.getContext(&quot;2d&quot;);
         let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height, { colorSpace: &quot;srgb&quot; });
         resolve(imgData);
      });
   });
}

async function makeOffscreenFromImg (src, crossOrigin) {
   let img  = makeImg(src, crossOrigin);
   return new Promise((resolve, reject) =&gt; {
      img.addEventListener(&#39;load&#39;,  () =&gt; {
         let cnv = new OffscreenCanvas(img.width, img.height);
         cnv.getContext(&quot;2d&quot;).drawImage(img, 0, 0);
         resolve(cnv);
      });
      img.addEventListener(&#39;error&#39;, (event) =&gt; { console.log(event); reject (event); } );
   });
}
function makeImg (src, crossOrigin)
{
   let image  = new Image ();
   let canvas = document.createElement(&quot;canvas&quot;);
   if (crossOrigin) image.crossOrigin  =  crossOrigin;
   image.src  =  src;
   return image;
}

##################
PS: Just in case, to see the crater from different angles, camera can be moved with mouse when pressing SHIFT, or rotated when pressing CTRL. Also click event for permanent animation, or tap if on mobile device.
PS1: Please do not use heightmap images for personal purposes. These have commercial copyright.

答案1

得分: 3

使用createImageBitmap 在您的 Worker 中,传递一个从图像 URL 获取的 Blob:

const resp = await fetch(imageURL);
if (!resp.ok) {
  throw "网络错误";
}
const blob = await resp.blob();
const bmp = await createImageBitmap(blob);
const { width, height } = bmp;
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext("2d");
ctx.drawImage(bmp, 0, 0);
bmp.close();
const imgData = ctx.getImageData(0, 0, width, height);

如有需要,您还可以在主线程中从<img>标签创建ImageBitmap,然后将其传递到您的 Worker。

英文:

Use createImageBitmap from your Worker, passing a Blob you'd have fetched from the image URL:

const resp = await fetch(imageURL);
if (!resp.ok) {
  throw &quot;network error&quot;;
}
const blob = await resp.blob();
const bmp = await createImageBitmap(blob);
const { width, height } = bmp;
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext(&quot;2d&quot;);
ctx.drawImage(bmp, 0, 0);
bmp.close();
const imgData = ctx.getImageData(0, 0, width, height);

If required, you could also create the ImageBitmap from the &lt;img&gt; tag in the main thread, and transfer it to your Worker.

huangapple
  • 本文由 发表于 2023年2月7日 00:36:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/75364110.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定