如何将Byte[](解码为PNG或JPG)转换为Tensorflow的张量

3

我正在尝试在Unity项目中使用Tensorflowsharp。

我遇到的问题是,通常情况下你需要使用第二个图形将输入转换为张量,但所使用的DecodeJpg和DecodePng函数在Android上不受支持,那么如何将该输入转换为张量呢?

private static void ConstructGraphToNormalizeImage(out TFGraph graph, out TFOutput input, out TFOutput output, TFDataType destinationDataType = TFDataType.Float)
{

    const int W = 224;
    const int H = 224;
    const float Mean = 117;
    const float Scale = 1;
    graph = new TFGraph();
    input = graph.Placeholder(TFDataType.String);
    output = graph.Cast(graph.Div(
        x: graph.Sub(
            x: graph.ResizeBilinear(
                images: graph.ExpandDims(
                    input: graph.Cast(
                        graph.DecodeJpeg(contents: input, channels: 3), DstT: TFDataType.Float),
                    dim: graph.Const(0, "make_batch")),
                size: graph.Const(new int[] { W, H }, "size")),
            y: graph.Const(Mean, "mean")),
        y: graph.Const(Scale, "scale")), destinationDataType);
}

其他解决方案似乎会产生不准确的结果。

也许可以用Mat对象来实现?

我的编辑:

我在Unity中使用C#实现了类似的功能,部分工作正常。但是它根本不准确。我该如何找到平均值?而且我找不到关于RGB顺序的任何信息。我对此非常陌生,也许我只是忽略了它。(在Tensorflow.org上)使用在1.4中训练的MobileNet。

  public TFTensor transformInput(Color32[] pic, int texturewidth, int textureheight)
    {
        const int W = 224;
        const int H = 224;
        const float imageMean = 128;
        const float imageStd = 128;

        float[] floatValues = new float[texturewidth * textureheight * 3];

        for (int i = 0; i < pic.Length; ++i)
        {
            var color = pic[i];
            var index = i * 3;

            floatValues[index] = (color.r - imageMean) / imageStd;
            floatValues[index + 1] = (color.g - imageMean) / imageStd;
            floatValues[index + 2] = (color.b - imageMean) / imageStd;

        }
        TFShape shape = new TFShape(1, W, H, 3);
        return TFTensor.FromBuffer(shape, floatValues, 0, floatValues.Length);
    }

你好,能否提供更多关于网络的信息?你是自己训练的还是使用了预训练的网络?我在tensorflow.org上没有看到任何预训练的MobilNets。 - sladomic
这是一个使用他们的脚本重新训练的网络,主要用于花卉分类(加入了一些额外的图片和“无”类别以减少假阳性)。在Python中,该程序运行良好。但是,在C#中测试相同的图片时,使用该脚本的结果不准确(在Python之外的任何脚本中都不准确)。它采用1.0 224架构。所有Tensorflow实例似乎都是1.4版本的某个变体。 - Robert Kaa Frank
2个回答

5

不要先提供字节数组,然后再使用DecodeJpeg方法,你可以直接提供实际的浮点数数组,获取方式如下:

https://github.com/tensorflow/tensorflow/blob/3f4662e7ca8724f760db4a5ea6e241c99e66e588/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowImageClassifier.java#L134

float[] floatValues = new float[inputSize * inputSize * 3];
int[] intValues = new int[inputSize * inputSize];

bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for (int i = 0; i < intValues.length; ++i) {
      final int val = intValues[i];
      floatValues[i * 3 + 0] = (((val >> 16) & 0xFF) - imageMean) / imageStd;
      floatValues[i * 3 + 1] = (((val >> 8) & 0xFF) - imageMean) / imageStd;
      floatValues[i * 3 + 2] = ((val & 0xFF) - imageMean) / imageStd;
}

Tensor<Float> input = Tensors.create(floatValues);

为了使用"Tensors.create()",您需要至少拥有Tensorflow版本1.4。

首先感谢您的回答。我实现了类似的东西,但是图表几乎没有真正的准确性预测任何内容。这是一个MobilNet,我可能只需要找出需要哪些平均值和标准差? - Robert Kaa Frank
天哪,我在 decodejpeg 上遇到了很多问题,我简直无法相信手动加载它会这么简单。非常感谢!! - Gaspa79

2
您可能在将图像放入@sladomic函数之前没有裁剪和缩放图像。
我成功地将TensorflowSharp用于Unity中的对象分类示例。它可以使用来自官方Tensorflow Android示例的模型,也可以使用我自己训练的MobileNet模型。您只需要替换模型并设置您的平均值和标准差,而在我的情况下,它们都等于224。

谢谢,我会研究一下。后来我在图片中间剪切了所需的NN分辨率部分,但仍然不准确。我会研究一下你做的事情,谢谢。如果我有时间,我会更新我的问题,并分享我发现的内容,也许可以与你的方法配合使用。 - Robert Kaa Frank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接