Add AI feature to Xamarin.Forms app
Now, AI is one of important technologies.
Almost all platforms have API sets of AI. Following list is technology names per platform.
- Windows 10: Windows ML
- Android: TensorFlow
- iOS: CoreML
Xamarin can call native API sets using C#. It means you can implement AI feature on your app using Xamarin. This article will be introducing how to use AI APIs with Xamarin.Forms.
Create a project
Open Visual Studio 2017, then create a new project that is Mobile App (Xamarin.Form) of Cross-Platform category. And then select Blank, select Android, iOS, Windows(UWP) and .NET Standard.
Create a Xamarin.Forms project
Add base feature that exclude AI to here. I'll use a take photo feature in this app. So, add Xam.Plugin.Media NuGet package to all projects, then setup projects in accordance with the readme file shown. And then edit MainPage.xaml like below:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="AIApp.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
xmlns:local="clr-namespace:AIApp"
Title="Safe Area"
ios:Page.UseSafeArea="True">
<StackLayout>
<Image
x:Name="picture"
Aspect="AspectFill"
VerticalOptions="FillAndExpand" />
<Label x:Name="output" HorizontalOptions="CenterAndExpand" />
<StackLayout Orientation="Horizontal">
<Button
Clicked="PickPhotoButton_Clicked"
HorizontalOptions="FillAndExpand"
Text="Pick a picture" />
<Button
Clicked="TakePhotoButton_Clicked"
HorizontalOptions="FillAndExpand"
Text="Take a picture" />
</StackLayout>
</StackLayout>
</ContentPage>
At next, edit the code behind like below:
using Plugin.Media;
using Plugin.Media.Abstractions;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace AIApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private async void TakePhotoButton_Clicked(object sender, EventArgs e)
{
await ProcessPhotoAsync(true);
}
private async void PickPhotoButton_Clicked(object sender, EventArgs e)
{
await ProcessPhotoAsync(false);
}
private async Task ProcessPhotoAsync(bool useCamera)
{
await CrossMedia.Current.Initialize();
if (useCamera ? !CrossMedia.Current.IsTakePhotoSupported : !CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert("Info", "Your phone doesn't support photo feature.", "OK");
return;
}
var photo = useCamera ?
await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions()) :
await CrossMedia.Current.PickPhotoAsync();
if (photo == null)
{
picture.Source = null;
return;
}
picture.Source = ImageSource.FromFile(photo.Path);
var service = DependencyService.Get<IPhotoDetector>();
if (service == null)
{
await DisplayAlert("Info", "Not implemented the feature on your device.", "OK");
return;
}
using (var s = photo.GetStream())
{
var result = await service.DetectAsync(s);
output.Text = $"It looks like a {result}";
}
}
}
}
In this code, using IPhotoDetector interface to detect a photo. The interface is just a method that is DetectAsync.
using System.IO;
using System.Threading.Tasks;
namespace AIApp
{
public interface IPhotoDetector
{
Task<FriesOrNotFriesTag> DetectAsync(Stream photo);
}
public enum FriesOrNotFriesTag
{
None,
Fries,
NotFries,
}
}
Create ML models
I use Microsoft Cognitive Services Custom Vision(https://customvision.ai) to create ML models. Create Fries and NotFries tags on the project of Custom Vision.
Custom Vision service has a feature that generate CoreML, TensorFlow and ONNX files. Please read the following document to know more information.
Export your model for use with mobile devices | Microsoft Docs
The point is that select General (compact) of Domains category when creating project.
Create new project
After training the model, you can export the ML models from Export button at Performance tab.
Export models
Choose your platform
Add Windows 10 implementation
Windows 10 has Windows ML feature.
Windows Machine Learning | Microsoft Docs
Add the onnx file to Assets folder on the UWP project, then generated a C# file for use the onnx file.
Add an ONNX model
Add PhotoDetector.cs file to UWP project, and then edit the file like below:
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Windows.AI.MachineLearning;
using Windows.Graphics.Imaging;
using Windows.Media;
using Windows.Storage;
using Xamarin.Forms;
[assembly: Dependency(typeof(AIApp.UWP.PhotoDetector))]
namespace AIApp.UWP
{
public class PhotoDetector : IPhotoDetector
{
private FriesOrNotFriesModel _model;
public async Task DetectAsync(Stream photo)
{
await InitializeModelAsync();
var bitmapDecoder = await BitmapDecoder.CreateAsync(photo.AsRandomAccessStream());
var output = await _model.EvaluateAsync(new FriesOrNotFriesInput
{
data = ImageFeatureValue.CreateFromVideoFrame(VideoFrame.CreateWithSoftwareBitmap(await bitmapDecoder.GetSoftwareBitmapAsync())),
});
var label = output.classLabel.GetAsVectorView().FirstOrDefault();
return Enum.Parse(label);
}
private async Task InitializeModelAsync()
{
if (_model != null)
{
return;
}
var onnx = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FriesOrNotFries.onnx"));
_model = await FriesOrNotFriesModel.CreateFromStreamAsync(onnx);
}
}
}
Add Android implementation
On Android platform, TensorFlow is popular library. In Java or Kotlin, there is tensorflow-android library.
TensorFlow AAR For Android Inference Library and Java API | Maven Repository
On Xamarin, there is wrapper library.
Xam.Android.Tensorflow | NuGet
The library was introduced following article of Xamarin Blog.
Using TensorFlow and Azure to Add Image Classification to Your Android Apps | Xamarin Blog
Add a model file and label file to Android project.
Add TensorFlow model
At next, I add the library to Android project, then create PhotoDetector.cs file to the project. At next, edit the file like below:
using Android.Graphics;
using Org.Tensorflow.Contrib.Android;
using Plugin.CurrentActivity;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
[assembly: Dependency(typeof(AIApp.Droid.PhotoDetector))]
namespace AIApp.Droid
{
public class PhotoDetector : IPhotoDetector
{
private static readonly string ModelFile = "model.pb";
private static readonly string LabelFile = "labels.txt";
private static readonly string InputName = "Placeholder";
private static readonly string OutputName = "loss";
private static readonly int InputSize = 227;
private readonly TensorFlowInferenceInterface _inferenceInterface;
private readonly string[] _labels;
public PhotoDetector()
{
_inferenceInterface = new TensorFlowInferenceInterface(CrossCurrentActivity.Current.Activity.Assets, ModelFile);
using (var sr = new StreamReader(CrossCurrentActivity.Current.Activity.Assets.Open(LabelFile)))
{
_labels = sr.ReadToEnd().Split('\n').Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).ToArray();
}
}
public async Task DetectAsync(Stream photo)
{
var bitmap = await BitmapFactory.DecodeStreamAsync(photo);
var floatValues = GetBitmapPixels(bitmap);
var outputs = new float[_labels.Length];
_inferenceInterface.Feed(InputName, floatValues, 1, InputSize, InputSize, 3);
_inferenceInterface.Run(new[] { OutputName });
_inferenceInterface.Fetch(OutputName, outputs);
var index = Array.IndexOf(outputs, outputs.Max());
return (FriesOrNotFriesTag)Enum.Parse(typeof(FriesOrNotFriesTag), _labels[index]);
}
private async Task LoadByteArrayFromAssetsAsync(string name)
{
using (var s = CrossCurrentActivity.Current.Activity.Assets.Open(name))
using (var ms = new MemoryStream())
{
await s.CopyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);
return ms.ToArray();
}
}
private static float[] GetBitmapPixels(Bitmap bitmap)
{
var floatValues = new float[InputSize * InputSize * 3];
using (var scaledBitmap = Bitmap.CreateScaledBitmap(bitmap, InputSize, InputSize, false))
{
using (var resizedBitmap = scaledBitmap.Copy(Bitmap.Config.Argb8888, false))
{
var intValues = new int[InputSize * InputSize];
resizedBitmap.GetPixels(intValues, 0, resizedBitmap.Width, 0, 0, resizedBitmap.Width, resizedBitmap.Height);
for (int i = 0; i > 8) & 0xFF) - 117);
floatValues[i * 3 + 2] = (((val >> 16) & 0xFF) - 123);
}
resizedBitmap.Recycle();
}
scaledBitmap.Recycle();
}
return floatValues;
}
}
}
Add iOS implementation
The last platform is iOS. iOS has CoreML feature.
Core ML | Apple Developer Documentation
In Xamarin platform, you can use CoreML APIs. The documentation is below:
Introduction to CoreML in Xamarin.iOS | Microsoft Docs
Add the CoreML file to Resources folder of iOS project, and set CoreMLModel to Build Action.
Add CoreML file
At next, add PhotoDetector.cs to iOS project, then edit the file like below:
using CoreFoundation;
using CoreImage;
using CoreML;
using Foundation;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Vision;
using Xamarin.Forms;
[assembly: Dependency(typeof(AIApp.iOS.PhotoDetector))]
namespace AIApp.iOS
{
public class PhotoDetector : IPhotoDetector
{
private readonly MLModel _mlModel;
private readonly VNCoreMLModel _model;
public PhotoDetector()
{
var assetPath = NSBundle.MainBundle.GetUrlForResource("FriesOrNotFries", "mlmodelc");
_mlModel = MLModel.Create(assetPath, out var _);
_model = VNCoreMLModel.FromMLModel(_mlModel, out var __);
}
public Task DetectAsync(Stream photo)
{
var taskCompletionSource = new TaskCompletionSource();
void handleClassification(VNRequest request, NSError error)
{
var observations = request.GetResults();
if (observations == null)
{
taskCompletionSource.SetException(new Exception("Unexpected result type from VNCoreMLRequest"));
return;
}
if (!observations.Any())
{
taskCompletionSource.SetResult(FriesOrNotFriesTag.None);
return;
}
var best = observations.First();
taskCompletionSource.SetResult((FriesOrNotFriesTag)Enum.Parse(typeof(FriesOrNotFriesTag), best.Identifier));
}
using (var data = NSData.FromStream(photo))
{
var ciImage = new CIImage(data);
var handler = new VNImageRequestHandler(ciImage, new VNImageOptions());
DispatchQueue.DefaultGlobalQueue.DispatchAsync(() =>
{
handler.Perform(new VNRequest[] { new VNCoreMLRequest(_model, handleClassification) }, out var _);
});
}
return taskCompletionSource.Task;
}
}
}
How does it run?
This is results run on Windows 10.
Chirashi sushi is not fries, French fries is fries.
On Android:
French fries is fries, Fried egg is not fries.
On iOS:
French fries is fries, Soup is not fries.
Conclusion
AI is very important technology. You can use it your apps on all platforms.
If you created apps using Xamarin, then you could add the AI feature by steps of this article.
Have a good programing.
Add AI feature to Xamarin.Forms app的更多相关文章
- Xamarin.Forms App Settings
配合James Montemagno的Component [Settings Plugin],实现Xamarin.Forms的设置. 更新系统配置且不需要进行重启app. 方式一xml Xamarin ...
- Xamarin.Forms 开发资源集合(复制)
复制:https://www.cnblogs.com/mschen/p/10199997.html 收集整理了下 Xamarin.Forms 的学习参考资料,分享给大家,稍后会不断补充: UI样式 S ...
- Xamarin.Forms 开发资源集合
收集整理了下 Xamarin.Forms 的学习参考资料,分享给大家,稍后会不断补充: UI样式 Snppts: Xamarin Forms UI Snippets. Prebuilt Templat ...
- 整理 Xamarin.Forms - Plugins
Open Source Components for Xamarin Xamarin官方整理的一些开源组件,有需要可以先到这里找 GitHub: xamarin/XamarinComponents: ...
- Add Languages to Your Xamarin Apps with Multilingual App Toolkit
With Xamarin, you can extend your cross-platform apps with support for native speakers, reaching mar ...
- 菜鸟的Xamarin.Forms前行之路——从新建项目到APP上架各种报错问题解决方法合集(不定时更新)
出自:博客园-半路独行 原文地址:http://www.cnblogs.com/banluduxing/p/7425791.html 本文出自于http://www.cnblogs.com/banlu ...
- 【Xamarin.Forms 1】App的创建与运行
引言 本篇文章将从介绍Xamarin.Forms创建开始. 开发环境 Visual Studio 2019 16.6.2 Xamarin.Forms 4.6.0.726 Android 5.0 (AP ...
- 【Xamarin.Forms 2】App基础知识与App启动
系列目录 1.[Xamarin.Forms 1]App的创建与运行 引言 本篇文章将介绍Xamarin.Forms中 App 基础知识和 App的启动. 开发环境 Visual Studio 2019 ...
- Xamarin.Forms开发APP
Xamarin.Forms+Prism(1)—— 开发准备 准备: 1.VS2017(推荐)或VS2015: 2.JDK 1.8以上: 3.Xamarin.Forms 最新版: 4.Prism 扩展, ...
随机推荐
- Java并发——线程介绍
前言: 互联网时代已经发展到了现在.从以前只考虑小流量到现在不得不去考虑高并发的问题.扯到了高并发的问题就要扯到线程的问题.你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法.下 ...
- Java异常实战——OutOfMemoryError
在Java虚拟机规范描述中,除了程序计数器外,虚拟机内存的其他几个运行区域都有发生 OOM 异常的可能.在这里,用代码验证各个运行时区域存储的内容并讨论该如何进行处理 Java堆溢出 Java 堆用于 ...
- Nginx支持 React browser router
修改nginx配置文件,添加try_file配置如下,即可实现对 React browser router 的支持. location / { root /var/www/mysite; try_fi ...
- Odoo 中使用 celery 实现高性能异步任务队列
详见:http://www.oejia.net/blog/2018/07/09/odoo_task_queue.html 概述 在 odoo 中可以用自带的cron实现异步任务,这个cron基于多线程 ...
- 超简单的canvas绘制地图
本文使用geojson数据,通过缩放和平移把地图的地理坐标系转换canvas的屏幕坐标系,然后将转换后的数据绘制到canvas上. 首先要计算数据的最大最小值,遍历所有坐标点的最大最小 ...
- base64图片存储
将图片转换为Base64编码,可以让你很方便地在没有上传文件的条件下将图片插入其它的网页.编辑器中. 这对于一些小的图片是极为方便的,因为你不需要再去寻找一个保存图片的地方. Base64编码在ora ...
- 【原】无脑操作:IDEA使用时,提示"8080端口被占用"的解决
1.问题描述:IDEA使用时,提示"8080端口被占用" Description: The Tomcat connector configured to listen on ...
- c/c++ 继承与多态 文本查询的小例子(非智能指针版本)
问题:在上一篇继承与多态 文本查询的小例子(智能指针版本)在Query类里使用的是智能指针,只把智能指针换成普通的指针,并不添加拷贝构造方法,会发生什么呢? 执行时,代码崩掉. 分析下面一行代码: Q ...
- ubuntu18.04修改网卡名称为eth0
1.修改grub文件 vim /etc/default/grub 查找 GRUB_CMDLINE_LINUX="" 修改为 GRUB_CMDLINE_LINUX="net ...
- Ranger-Kafka插件安装
Ranger-Kafka插件安装, 使用Ranger0.7.0版本,集成Kafka插件到Kafka集群, Kafka Plugin需要安装到所有的Kafka的集群节点上面. 1.登陆Kafka的安装用 ...