Azure认知服务之使用墨迹识别功能识别手写汉字
前面我們使用Azure Face實(shí)現(xiàn)了人臉識(shí)別、使用Azure表格識(shí)別器提取了表格里的數(shù)據(jù)。這次我們?cè)囋囀褂肁zure墨跡識(shí)別API來(lái)對(duì)筆跡進(jìn)行識(shí)別。
墨跡識(shí)別
墨跡識(shí)別器認(rèn)知服務(wù)提供基于云的 REST API 用于分析和識(shí)別數(shù)字墨跡內(nèi)容。與使用光學(xué)字符識(shí)別 (OCR) 的服務(wù)不同,該 API 需要使用數(shù)字墨跡筆劃數(shù)據(jù)作為輸入。數(shù)字墨跡筆劃是 2D 點(diǎn)(X,Y 坐標(biāo),表示數(shù)字手寫(xiě)筆或手指的動(dòng)作)的時(shí)序集。然后,墨跡識(shí)別器會(huì)識(shí)別輸入中的形狀和手寫(xiě)內(nèi)容,并返回包含所有已識(shí)別實(shí)體的 JSON 響應(yīng)。
引用自微軟文檔
它不是ocr對(duì)圖像進(jìn)行識(shí)別,而是對(duì)墨跡數(shù)據(jù)進(jìn)行識(shí)別。墨跡數(shù)據(jù)的原理主要是一些手寫(xiě)輸入設(shè)備,比如平板,手寫(xiě)板等。
創(chuàng)建墨跡識(shí)別資源
跟前面的內(nèi)容一樣,在portal控制臺(tái)找到墨跡識(shí)別,點(diǎn)擊創(chuàng)建,取一個(gè)實(shí)例名。墨跡識(shí)別也是一個(gè)免費(fèi)服務(wù),定價(jià)選F0方案,額度為5次/分,20000事務(wù)/月。
獲取秘鑰和終結(jié)點(diǎn)
我們調(diào)用墨跡識(shí)別API需要秘鑰跟終結(jié)點(diǎn)信息。點(diǎn)擊菜單“密鑰和終結(jié)點(diǎn)”查看信息。
新建一個(gè)WPF項(xiàng)目
我們這次同樣實(shí)現(xiàn)一個(gè)WPF小程序。界面上放置一個(gè)InkCanvas用來(lái)手寫(xiě),一個(gè)文本框用來(lái)顯示識(shí)別的文本,一個(gè)按鈕用來(lái)觸發(fā)識(shí)別。
MainWindow.xaml
修改MainWindow.xaml為如下代碼:
<Window x:Class="InkRec2.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"xmlns:local="clr-namespace:NoteTaker"xmlns:controls="clr-namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls"Title="MainWindow"><Grid ><Grid.RowDefinitions><RowDefinition Height="4*" /><RowDefinition Height="1*" /><RowDefinition Height="50" /></Grid.RowDefinitions><Border Grid.Row ="0" BorderBrush="Black" BorderThickness="1"><controls:InkCanvas x:Name="inkCanvas" Loaded="inkCanvas_Loaded"/></Border><Border Grid.Row ="1" BorderBrush="Black" BorderThickness="1"><ScrollViewer><TextBox x:Name="output" FontSize="18" TextWrapping="Wrap"/></ScrollViewer></Border><StackPanel Grid.Row="2" Orientation="Horizontal"><Button Click="Button_InkRec">開(kāi)始識(shí)別</Button></StackPanel></Grid> </Window>注意:InkCanvas控件需要使用的是Microsoft.Toolkit.Wpf.UI.Controls包下的,如果本地沒(méi)有使用nuget進(jìn)行安裝
采集墨跡
inkCanvas load事件里設(shè)置輸入設(shè)備的類(lèi)型:
private void inkCanvas_Loaded(object sender, RoutedEventArgs e){inkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Touch;}先定義幾個(gè)模型用來(lái)存儲(chǔ)墨跡數(shù)據(jù):
public class InkStroke{public int id { get; set; }public string points { get; set; }}public class InkData{public string language { get; set; }public List<InkStroke> strokes { get; set; }}從InkCanvas獲取墨跡數(shù)據(jù)組裝成InkData:
private InkData GetInkData(){var data = new InkData();data.language = "zh-CN";data.strokes = new List<InkStroke>();int id = 0;foreach (var stroke in this.inkCanvas.InkPresenter.StrokeContainer.GetStrokes()){var points = stroke.GetInkPoints();var convertPoints = ConvertPixelsToMillimeters(points);var inkStorke = new InkStroke();inkStorke.id = id++;var sb = new StringBuilder();foreach (var point in convertPoints){sb.Append(point.X);sb.Append(",");sb.Append(point.Y);sb.Append(",");}inkStorke.points = sb.ToString().TrimEnd(',');data.strokes.Add(inkStorke);}return data;}private List<System.Windows.Point> ConvertPixelsToMillimeters(IReadOnlyList<InkPoint> pointsInPixels){float dpiX = 96.0f;float dpiY = 96.0f;var transformedInkPoints = new List<System.Windows.Point>();const float inchToMillimeterFactor = 25.4f;foreach (var point in pointsInPixels){var transformedX = (point.Position.X / dpiX) * inchToMillimeterFactor;var transformedY = (point.Position.Y / dpiY) * inchToMillimeterFactor;transformedInkPoints.Add(new System.Windows.Point(transformedX, transformedY));}return transformedInkPoints;}調(diào)用墨跡API
這里需要前面復(fù)制好的密鑰跟終結(jié)點(diǎn)地址。識(shí)別其實(shí)很簡(jiǎn)單,就是把墨跡數(shù)據(jù)轉(zhuǎn)換成json后給服務(wù)器發(fā)生一個(gè)put請(qǐng)求,識(shí)別成功后就會(huì)返回一個(gè)json字符串的結(jié)果。
private async Task<string> InkRec(InkData data){string inkRecognitionUrl = "/inkrecognizer/v1.0-preview/recognize";string endPoint = "x";string subscriptionKey = "x";using (HttpClient client = new HttpClient { BaseAddress = new Uri(endPoint) }){System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);var jsonData = JsonConvert.SerializeObject(data);var content = new StringContent(jsonData, Encoding.UTF8, "application/json");var res = await client.PutAsync(inkRecognitionUrl, content);if (res.IsSuccessStatusCode){var result = await res.Content.ReadAsStringAsync();return result;}else{var err = $"ErrorCode: {res.StatusCode}";return err;}}}解析識(shí)別結(jié)果
識(shí)別成功后,結(jié)果會(huì)以json字符串的形式進(jìn)行返回。結(jié)果是一個(gè)數(shù)組,里面存放了每一個(gè)筆跡的識(shí)別結(jié)果,以及最終的識(shí)別結(jié)果。
結(jié)果示例:
有了結(jié)果那么我們只要對(duì)其進(jìn)行反序列化取出想要的識(shí)別結(jié)果就行了。
public class InkRecResponse{public List<InkRecResponseUnit> recognitionUnits { get; set; }}public class InkRecResponseUnit{public string category { get; set; }public string recognizedText { get; set; }}private async void Button_InkRec(object sender, RoutedEventArgs e){var inkData = GetInkData();var response = await InkRec(inkData);var jsonObj = JsonConvert.DeserializeObject<InkRecResponse>(response);var recognizedText = jsonObj.recognitionUnits.First(o => o.category == "line").recognizedText;this.output.Text = recognizedText;}運(yùn)行一下
我們的程序?qū)懞昧?#xff0c;運(yùn)行一下。在canvas上隨便寫(xiě)上幾個(gè)漢字點(diǎn)擊識(shí)別按鈕。字雖然丑了點(diǎn),但是結(jié)果還是完美的。
總結(jié)
使用Azure墨跡識(shí)別可以輕松的識(shí)別手寫(xiě)輸入設(shè)備的筆跡。墨跡識(shí)別功能并不是見(jiàn)到的orc識(shí)別,它可以對(duì)每一個(gè)筆畫(huà)進(jìn)行識(shí)別,提供候選結(jié)果。以上代碼雖然多,其實(shí)主要是獲取墨跡數(shù)據(jù)比較麻煩,其實(shí)真正識(shí)別墨跡只是一個(gè)http put請(qǐng)求而已,這是非常簡(jiǎn)單的。有了這個(gè)API我們可以實(shí)現(xiàn)很多創(chuàng)意,比如稍微改進(jìn)下上面的代碼就可以實(shí)現(xiàn)手寫(xiě)文字的連續(xù)識(shí)別功能,一邊寫(xiě)一邊不斷的識(shí)別,封裝進(jìn)平板就是一款可以實(shí)時(shí)識(shí)別手寫(xiě)板啦。
關(guān)注我的公眾號(hào)一起玩轉(zhuǎn)技術(shù)
總結(jié)
以上是生活随笔為你收集整理的Azure认知服务之使用墨迹识别功能识别手写汉字的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 路线错误的教训对如今的模范企业也有借鉴意
- 下一篇: 如何做一个懂产品的程序员?