首页 > 解决方案 > 如何使用浏览器端 javascript 将具有编码高度值的 32 位 RGB png 转换为 16 位 png?

问题描述

我正在尝试从 32 位 Rgb 编码的高度值 png 创建一个 16 位高度图 png。

根据mapbox,我可以使用这个公式将它们的 png 像素值解码为以米为单位的高度值。 height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)

我是新了解此类信息的新手,并试图自己弄清楚,但我需要一些帮助。

我找到了这个名为image-js的程序,这个程序的文档在这里。注意我在浏览器中使用它而不是节点。

我认为它有我需要的能力。但是,我真的不确定如何从原始图像中获取数据并使用根据上述公式计算的新高度值创建一个新的 16 位 png。

如果您查看图像下的文档,我可以设置许多属性,例如

bitDepth 并将其设置为 16

getPixelsArray() 这个函数会给我一个像素值数组,格式为 r,g,b。我想我可以通过上面的公式运行每个像素来获得高度。之后如何将这个高度数据转换回 16 位灰度高度图 png?

谢谢!

示例图像。32bit Rgb 编码高度值 png 在此处输入图像描述

16位高度图.png 您必须放大才能看到图像的变化 在此处输入图像描述

更新:

感谢 traktor 的建议。我想在我的问题中添加一些信息。

我不一定需要使用 image-js。我的主要目标是从 32 位 RGB 中获得 16 位高度图。所以任何其他浏览器端的 javscript 方法都可以。我也在使用浏览器端 createWritable(); 流将文件写入磁盘。

我有一个从这个不错的模块https://github.com/colkassad/terrain-rgb-height使用的方法,但是我无法让 pngjs 的浏览器端版本正常工作。我认为浏览器端流读取器/写入器和节点读取器/写入器之间存在差异,使其无法正常工作。

谢谢!

标签: javascriptimagemapboxmapbox-gl-jsheightmap

解决方案


Image-js在 GitHub 上查看 package 的源代码,发现options调用库中使用的对象在源文件中进行了验证,该源文件kind.js枚举了赋值语句中支持的选项属性:

const { components, alpha, bitDepth, colorModel } = definition;

但是,许多选项默认使用kind选项属性,其本身默认为“RGBA”。

了解有关选项属性的更多信息允许使用它们(我在代码之外找不到选项文档)。

我会建议

  1. 从 32 位编码高度 png 创建一个 Image-js 图像。省略一个kind属性以使用 3 个颜色通道和一个 Alpha 通道的默认 32 位 PNG 像素模型。

  2. 使用 MapBox 转换算法将图像数据(作为图像对象data属性中的类型化数组保存)转换为高度值的一维数组。( image.data) 类型数组的布局似乎与用于ImageData的布局相同

  3. 使用创建一个新的 image-js 图像

    new Image(width, height, decodedHeightArray, {kind="GREY", bitDepth:16})
    

    decodedHeightArray上一步准备的数组在哪里。

只需将我的代码添加到提供的跟踪器答案中 非常感谢 traktor

这非常有效。对于任何想要代码的人

我正在使用image-js对图像进行编码和解码

 let file_handleSixteen = await dir_handle.getFileHandle(sixteen_file_name, {create: true})

 let writableSixteen = await file_handleSixteen.createWritable();


async function convert16(arrayBuff) {

  let image = await Image.load(arrayBuff);

  let width = image.width
  let height = image.height

  let decodedHeightArray = []
  let pixelsArray = image.getPixelsArray()
  for (const pixel of pixelsArray) {
    let r = pixel[0]
    let g = pixel[1]
    let b = pixel[2]
    let height = getHeightFromRgb(r, g, b);
    decodedHeightArray.push(height)
  }
  let newImage = new Image(width, height, decodedHeightArray, {kind: "GREY", bitDepth: 16})
  return newImage.toBlob()
}

function getHeightFromRgb(r, g, b) {
  return -10000 + ((r * 256 * 256 + g * 256 + b) * 0.1);
}


  const file = await file_handleRgb.getFile();
  let imageBuffer = await file.arrayBuffer()
  let convertedArray = await convert16(imageBuffer)

 await writableSixteen.write(convertedArray)
 await writableSixteen.close();

我还使用浏览器流 api 将文件写入磁盘。请注意,文件流 writable.write 仅接受某些值,其中之一是 Blob,这就是为什么在将其传递给 write 方法之前将其转换为 Blob



推荐阅读