如何使用 react-native 将图像张量转换为 PNG?

How to convert an Image tensor to PNG using react-native?

提问人:Sameer Trivedi 提问时间:11/18/2023 更新时间:11/18/2023 访问量:11

问:

我使用 react-native-tfjs 运行神经网络,它给了我一个 RGB 图像张量作为输出之一。如何将其保存为 PNG 图像?

到目前为止,我尝试了什么:

  • 尝试使用该函数,但这不起作用,因为绘制或保存它需要 html5 canvas 元素。tf.browser.toPixels
  • 搜索了 EncodePng 实现,不幸的是 react-native 没有类似的实现。tf.node.encodePng
  • 一堆其他事情,比如尝试将缓冲区转换为 base64,但都没有运气。

以下是我发现有效的 Jpeg 编码实现:

import * as tf from "@tensorflow/tfjs";
import * as jpeg from "jpeg-js";

async function tensorToImageUrl(imageTensor) {
  const [height, width] = imageTensor.shape;
  const buffer = await imageTensor.toInt().data();
  const frameData = new Uint8Array(width * height * 4);

  let offset = 0;
  for (let i = 0; i < frameData.length; i += 4) {
    frameData[i] = buffer[offset];
    frameData[i + 1] = buffer[offset + 1];
    frameData[i + 2] = buffer[offset + 2];
    frameData[i + 3] = 0xff;

    offset += 3;
  }

  const rawImageData = {
    data: frameData,
    width,
    height,
  };
  const jpegImageData = jpeg.encode(rawImageData, 100);
  const base64Encoding = tf.util.decodeString(jpegImageData.data, "base64");
  return base64Encoding;
}

我必须有一个无损图像才能进一步检索和处理,所以我不能使用,我试图为png寻找类似的库,但其中很多都已经过时或缺乏文档,如果有人可以帮助我实现该功能,但对于PNG,这将对我的项目非常有帮助。jpeg-jstensorToImageUrl

react-native expo tensorflow.js tfjs-node

评论


答:

0赞 Sameer Trivedi 11/18/2023 #1

好的,所以我设法让它工作,希望它能在未来帮助某人和其他类似的未解决的问题。我使用了 Jimp 图像处理库,它是纯用纯 JS 编写的,可以在 Node 和浏览器中工作,但有一个技巧可以让它在 react-native/react 中工作。

import * as tf from "@tensorflow/tfjs";

import * as _Jimp from "jimp";
const Jimp = typeof self !== "undefined" ? self.Jimp || _Jimp : _Jimp; // The hack

async function encodePng(imageTensor) {
  const [height, width] = imageTensor.shape;
  const buffer = await imageTensor.toInt().data();
  const frameData = new Uint8Array(width * height * 4);

  let offset = 0;
  for (let i = 0; i < frameData.length; i += 4) {
    frameData[i] = buffer[offset];
    frameData[i + 1] = buffer[offset + 1];
    frameData[i + 2] = buffer[offset + 2];
    frameData[i + 3] = 0xff; // Buffer has to be Uint8Array in RGBA raw data because Jimp expects the format, we stuff dummy alpha values here.

    offset += 3;
  }
  const rawImageData = {
    data: frameData,
    width,
    height,
  };
  var base64Data = "";
  try {
    const image = await Jimp.read(rawImageData);
    console.log(image);
    base64Data = await image.getBase64Async(Jimp.MIME_PNG); // JIMP support Jpeg, BMP, PNG etc. so you can modify this however you like.
  } catch (e) {
    console.log(e);
  }
  if (base64Data === "") console.log("operation unsucessful");
  return base64Data;
}