如何使用浏览器端 javascript 将具有编码高度值的 32 位 RGB png 转换为 16 位 png?

How do you convert a 32bit RGB png with encoded height values to 16 bit png using browser side javascript?

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

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

我对理解这类信息还很陌生,我自己也想弄明白,但我需要一些帮助。

我找到了这个名为 image-js, docs for this program are here 的程序。注意我在浏览器中使用它而不是节点。

我认为它具有我需要的能力。但是,我真的不确定如何从原始图像中获取数据并使用根据上述公式计算出的新高度值创建一个新的 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 的浏览器端版本正常工作。我认为浏览器端流 reader/writers 和节点 reader/writers 之间存在差异,导致它无法正常工作。

谢谢!

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

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

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

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

我会建议

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

  2. 转换图像数据(在图像对象的 data property) to a single dimensional array of height values using the MapBox conversion algorithm. The layout of the (image.data) typed array appears to be the same as that used for ImageData

    中作为类型数组保存
  3. 使用

    创建新的 image-js 图像
    new Image(width, height, decodedHeightArray, {kind="GREY", bitDepth:16})
    

    其中decodedHeightArray为上一步准备的数组

只需将我的代码添加到 tracktor 提供的答案中 非常感谢拖拉机

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

我正在使用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 的原因