使用TensorFlow Lite和Azure自定义视觉对Android上的图像进行分类

图像分类使我们的Xamarin应用程序可以识别照片中的对象。

拍照和识别其内容的能力越来越普遍。我们可以在银行应用程序中进行移动存款时,在照片应用程序中添加过滤器时以及在HotDog应用程序中观察到这一点,以确定我们的食物是否是热狗。

借助Azure自定义视觉服务,我们无需学习复杂的机器学习算法即可实现图像分类。

在本文中,我们将研究如何使用Azure Custom Vision服务TensorFlow Lite(开源机器学习平台)以及Xamarin.Android


注意:对于Xamarin.iOS,我们还可以将Azure Custom Vision服务CoreML结合使用,但最好将其保存在另一篇文章中。

图片

图像分类库


我们将使用Azure自定义视觉服务和TensorFlow Lite来实现图像分类。

1. Azure自定义视觉服务


Azure自定义视觉服务简化了机器学习模型的创建和培训-无需具备Artificail Intelligence(AI)或机器学习(ML)的经验。

使用Custom Vision服务Web门户,我们可以执行以下操作而无需编写任何AI / ML代码:

  1. 下载培训图片
  2. 在图像中标记标签/对象标签
  3. 重复(通过更多训练数据使模型变得更好)
  4. 就是这样-Custom Vision负责其余工作!

2. TensorFlow Lite


TensorFlow Lite是一个开放源代码的机器学习平台,使我们能够在物联网和移动设备中使用TensorFlow

TensorFlow Lite和TensorFlow可在GitHub上的开源上获得

使用Azure + Xamarin.Android实现图像分类


完整的示例图像分类应用程序可从GitHub上获得

1.模型训练


使用Custom Vision服务Web门户,我们首先训练图像分类模型。

1.Custom Vision服务Web门户上,单击“ 新建项目”。

图片

2.在“ 创建新项目”窗口中,设置以下参数:

  • 名称: XamarinImageClassification
  • 说明:识别图像中的对象
  • 资源: [创建新资源]
  • 项目类型:分类
  • 分类类型:多标签(每个图像有多个标签)
  • 域:常规(紧凑型)
  • 出口能力:基本平台

3.在“ 创建新项目”窗口中,单击“ 创建项目”

。4 .在XamarinImageClassification窗口中单击“ 添加图像”

。5.选择包含用于标识的对象的图像

。6.在“ 图像上载”窗口中,添加标签
注意:在此示例中,我们正在使用蘑菇图像

。7.在“ 图像”窗口中上传点击上传
注:守上传图片,直到你为每个标签至少5张图片

图片

8.在窗口右上角XamarinImageClassification窗口中,单击“ 训练模型”按钮(齿轮的绿色图像)

。9.在“ 选择训练类型”窗口中,选择“ 快速训练”

。10.在“ 选择训练类型”窗口中,选择“ 训练”。

图片

2.从Azure自定义视觉服务中导出经过训练的模型


现在我们已经训练了模型,现在将其导出以在我们的移动应用程序中使用

这将使我们能够在没有Internet连接的情况下使用该模型,这将确保用户的最佳隐私,因为他的照片永远不会离开移动设备。

要导出模型,请执行以下操作:

1.页面顶部XamarinImageClassifcation窗口中,选择Performance选项卡

2.Performace选项卡上,单击Export按钮(向下箭头)

3.Choose your platform窗口中,选择TensorFlow

图片

4.在“ 选择平台”下拉列表中,选择TensorFlow Lite

5.在“ 选择平台”窗口中,选择“ 下载”。

图片

3.将TensorFlow Lite导入我们的Xamarin.Android应用


1.在我们的Xamarin.Android项目中安装适当的NuGet软件包
注意:此NuGet软件包是由Microsoft Xamarin团队创建的一个开源项目它包含了C#绑定在原TensorFlow精简版库,它可以在我们的Xamarin.Android使用

2应用程序解压导出模型,我们从下载自定义视觉服务门户网站
注: ZIP文件是labels.txtmodel.tflite

  • labels.txt包含准备在Custom Vision网站上进行培训期间创建的图像标签
  • models.tflite是我们用于预测的机器学习模型。

3.在Visual Studio的Xamarin.Android项目中,右键单击Assets文件夹

。4 .在弹出菜单中,选择“ 添加” →“ 现有项...”

。5.在“ 添加现有项”菜单中,选择两个最近解压缩的文件:

  • 模型
  • labels.txt

6.在Visual Studio中,在Xamarin.AndroidAssets中,右键单击labels.txt。7

.在弹出菜单中,选择Properties

8.Properties窗口中,选择Build ActionAndroid Asset9

在Visual Studio中,在Xamarin.Android资产,右键点击models.tflite

10.在弹出的菜单中选择属性

11.属性窗口,选择生成操作Android的资产

图片

4. Xamarin.Android的图像分类代码的实现


现在我们已经导入了模型,是时候进行一些代码编写了。

提醒一下,GitHub上提供了完整的示例图像分类应用程序

Xamarin.Android项目中,添加ImageClassifcationModel.csTensorflowClassifier.cs

ImageClassificationModel.cs


public class ImageClassificationModel 
{ 
    public ImageClassificationModel(string tagName, float probability) 
    { 
        TagName = tagName; 
        Probability = probability; 
    } 
   
    public float Probability { get; } 
    public string TagName { get; } 
}

TensorflowClassifier.cs


using System.Collections.Generic;
using System.IO;
using System.Linq;
using Android.App;
using Android.Graphics;
using Java.IO;
using Java.Nio;
using Java.Nio.Channels;

public class TensorflowClassifier
{
    //FloatSize     4,        4 
    const int FloatSize = 4;
    //PixelSize -     3,        : ,   .
    const int PixelSize = 3;

    public List<ImageClassificationModel> Classify(byte[] image)
    {
        var mappedByteBuffer = GetModelAsMappedByteBuffer();
        var interpreter = new Xamarin.TensorFlow.Lite.Interpreter(mappedByteBuffer);

        //   ,       
        var tensor = interpreter.GetInputTensor(0);
        var shape = tensor.Shape();

        var width = shape[1];
        var height = shape[2];

        var byteBuffer = GetPhotoAsByteBuffer(image, width, height);

        // StreamReader    labels.txt
        var streamReader = new StreamReader(Application.Context.Assets.Open("labels.txt"));

        // labels.txt  List<string>
        var labels = streamReader.ReadToEnd().Split('\n').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList();

        //     Java.Lang.Object,    Xamarin.TensorFlow.List.Interpreter.
        var outputLocations = new float[1][] { new float[labels.Count] };
        var outputs = Java.Lang.Object.FromArray(outputLocations);

        interpreter.Run(byteBuffer, outputs);
        var classificationResult = outputs.ToArray<float[]>();

        // classificationResult     ,  ,     
        var classificationModelList = new List<ImageClassificationModel>();

        for (var i = 0; i < labels.Count; i++)
        {
            var label = labels[i]; classificationModelList.Add(new ImageClassificationModel(label, classificationResult[0][i]));
        }

        return classificationModelList;
    }

    // model.tflite  Java.Nio.MappedByteBuffer,    Xamarin.TensorFlow.Lite.Interpreter.
    private MappedByteBuffer GetModelAsMappedByteBuffer()
    {
        var assetDescriptor = Application.Context.Assets.OpenFd("model.tflite");
        var inputStream = new FileInputStream(assetDescriptor.FileDescriptor);

        var mappedByteBuffer = inputStream.Channel.Map(FileChannel.MapMode.ReadOnly, assetDescriptor.StartOffset, assetDescriptor.DeclaredLength);

        return mappedByteBuffer;
    }

    //     TensorFlow
    private ByteBuffer GetPhotoAsByteBuffer(byte[] image, int width, int height)
    {
        var bitmap = BitmapFactory.DecodeByteArray(image, 0, image.Length);
        var resizedBitmap = Bitmap.CreateScaledBitmap(bitmap, width, height, true);

        var modelInputSize = FloatSize * height * width * PixelSize;
        var byteBuffer = ByteBuffer.AllocateDirect(modelInputSize);
        byteBuffer.Order(ByteOrder.NativeOrder());

        var pixels = new int[width * height];
        resizedBitmap.GetPixels(pixels, 0, resizedBitmap.Width, 0, 0, resizedBitmap.Width, resizedBitmap.Height);

        var pixel = 0;

        //     Java.Nio.ByteBuffer
        for (var i = 0; i < width; i++)
        {
            for (var j = 0; j < height; j++)
            {
                var pixelVal = pixels[pixel++];

                byteBuffer.PutFloat(pixelVal >> 16 & 0xFF);
                byteBuffer.PutFloat(pixelVal >> 8 & 0xFF);
                byteBuffer.PutFloat(pixelVal & 0xFF);
            }
        }

        bitmap.Recycle();

        return byteBuffer;
    }
}

就这样!现在我们可以将图像传递给TensorflowClassifier.Classify以获得ImageClassificationModel

进一步研究的材料


检查下方的链接:


All Articles