微軟認知服務應用祕籍 – 漫畫翻譯篇

概述

微軟認知服務包括了影像、語音、語言、搜索、知識五大領域,經過對這些認知服務的獨立或者組合使用,能夠解決不少現實世界中的問題。做爲AI小白,咱們能夠選擇艱難地攀登崇山峻嶺,也能夠選擇像牛頓同樣站在巨人的肩膀上。本章節的內容就以"漫畫翻譯"爲例,介紹如何靈活使用微軟認知服務來實現本身的AI夢想。html

日本漫畫很是著名,如海賊王,神探柯南等系列漫畫在中國的少年一代中是很是普及。國內專門有一批志願者,全手工翻譯這些漫畫爲中文版本,過程艱辛複雜,花費時間很長。可否使用AI來幫助加快這個過程呢?前端

小提示:漫畫是有版權的,請你們要在尊重版權的前提下作合法的事。算法

漫畫翻譯,要作的事情有三步:express

  1. 調用微軟認知服務,用OCR(光學字符識別)服務識別出漫畫上全部文字;
  2. 調用微軟認知服務,用Text Translate(文本翻譯)服務把日文翻譯成中文;
  3. 本身寫邏輯代碼把中文文字貼回到之前的漫畫中,覆蓋之前的日文,生成新的漫畫幀。

下圖是展現最後的翻譯效果,左側是原漫畫,右側是翻譯成中文的結果:json

環境準備

安裝Windows 10版本 1803,低一些的Windows 10版本也可使用。Windows 7也能夠運行本示例程序,但不建議使用,Windows 7的官方技術支持到2020/01/14結束。canvas

小提示:若是您的機器不能運行Windows 10,說明硬件性能仍是有些不夠的。AI是創建在軟硬件快速發展的基礎上的,不建議您使用低配置的機器來作AI知識的學習。api

安裝Visual Studio 2017 Community。點擊這裏下載,對於本案例,安裝時選擇".NET桌面開發"便可知足要求。服務器

申請微軟認知服務密鑰

申請OCR服務密鑰

點擊進入此頁面網絡

 

 

 

在上圖所示頁面中"計算機影像"下點擊"免費試用":app

根據本身的實際狀況選擇以上三個選項之一,這裏以選擇第一個"來賓"選項爲例:

選擇一個熱愛的國家/地區,在上下兩個複選框上("我贊成","我接受")都打勾,點擊"下一步":

上圖中以選擇"Microsoft"帳戶爲例繼續:

 

最後獲得了上面這個頁面,這裏的密鑰(Key)和終結點(Endpoint)要在程序中使用,請保存好!

小提示:上面例子中的密鑰只能再使用1天了,由於是7天的免費試用版本。因此當你的程序之前運行正常,某一天突然從服務器不能獲得正常的返回值時而且獲得錯誤代碼Unauthorized (401),請首先檢查密鑰狀態。

小提示:當試用的Key過時後,你是沒法再申請試用Key的,只能申請正式的Key,這就要經過Azure門戶。在Azure門戶中申請好Computer Vision服務(包括OCR服務)的Key後,它會告訴你Endpoint是…../vision/v1.0,這個不用管它,在code裏還保持……/vision/v2.0就能夠了,二者的Key是通用的。

申請Text Translate文本翻譯服務密鑰

用本身的Azure帳號登陸Azure門戶:

在上圖中點擊左側的"All resources":

在上圖中點擊上方的 "+ Add"圖標來建立資源,獲得資源列表以下 :

在上圖中點擊右側列表中的"AI + Machine Learning",獲得下圖的具體服務項目列表:

這裏有個坑,文本翻譯不在右側的列表中,須要點擊右上方的"See all"來展開全部項目:

哦,好吧,仍是沒有!保持耐心,繼續點擊Cognitive Services欄目的右側的"More"按鈕,獲得更詳細的列表:

仍是沒有?卷滾一下看看?到底,到底!OK,終於有了Translator Text,就是Ta:

建立這個服務時,咱們選擇F0就能夠了。若是要是作商用軟件的話,你能夠選擇S1或其餘,100萬個字符才花10美圓,不貴不貴!

使用VS Tools for AI

是否是以上申請Key的過程太複雜了?那是由於Azure內容龐雜,網頁設計層次太多!其實這個過程是能夠簡化的,由於咱們有個Visual Studio Tools for AI擴展包!

打開VS2017,菜單上選擇"工具(Tools)->擴展和更新(Extensions and Updates)",在彈出的對話框左側選擇"聯機(Online)",在右側上方輸入"AI" 進行搜索,會看到"Microsoft Visual Studio Tools for AI"擴展包,下載完畢後關閉VS,這個擴展包就會自動安裝。

安裝完畢後,再次打開VS2017,點擊菜單View->Server Explorer。若是安裝了Tools for AI,此時會看到如下界面:

 

在AI Tools->Azure Cognitive Services下,能夠看到我已經申請了2個service,ComputerVisionAPI和TranslateAPI就是咱們想要的,這兩個名字是本身在申請服務時指定的。

假設你尚未這兩個服務,那麼在Azure Cognitive Services上鼠標右鍵,而後選擇Create New Cognitive Service,出現如下對話框:

在每一個下拉框中顯示的內容可能會每一個人都不同,絕大多數是用下拉框完成填充的,很方便。假設我想申請TextTranslation服務,那麼我在Service Name上填寫一個本身能看懂的名字就好了,好比我填寫了"TranslateAPI",這樣比較直接。同理能夠建立ComputerVisionAPI服務。服務的名字不會在Code中使用。

小結

咱們廢了老鼻子勁,獲得瞭如下兩個REST API的Endpoint和相關的Key:

OCR服務

Endpoint: https://westcentralus.api.cognitive.microsoft.com/vision/v2.0

Text Translate文本翻譯服務

Endpoint: https://api.cognitive.microsofttranslator.com/translate?api-version=3.0

小提示:以上兩個Endpoint的URL是目前最新的版本,請不要使用舊的版本如v1.0等等。

我們是洗洗睡了,仍是寫代碼?看天色還早,繼續寫代碼吧!

構建代碼

構建這個PC桌面應用,咱們須要幾個步驟:

在獲得第一次的顯示結果後,通過測試,有很大可能會根據結果再對界面進行調整,實際上也是一個局部的軟件工程中的迭代開發。

界面設計

啓動Visual Studio 2017, 建立一個基於C#語言的WPF(Windows Presentation Foundation)項目:

WPF是一個很是成熟的技術,在有界面展現和交互的狀況下,使用XAML設計/渲染引擎,比WinForm程序要強101倍,再加上有C#語言利器的幫助,是寫PC桌面前端應用的最佳組合。

給Project起個名字,好比叫"CartoonTranslate",選擇最新的.NET Framework (4.6以上),而後點擊"OK"。咱們先一塊兒來設計一下界面:

Input URL:用於輸入互聯網上的一張漫畫圖片的URL

Engine:指的是兩個不一樣的算法引擎,其中,OCR舊引擎能夠支持25種語言,識別效果能夠接受;而Recognize Text新引擎目前只能支持英文,但效果比較好。

Language:制定當前要翻譯的漫畫的語言,咱們只以英文和日文爲例,其它國家的漫畫相對較少,但一通百通,同樣能夠支持。

右側的一堆Button瞭解一下:

Show:展現Input URL中的圖片到下面的圖片區

OCR:調用OCR服務

Translate:調用文本翻譯服務,將日文或者英文翻譯成中文

下側大面積的圖片區瞭解一下:

Source Image:原始漫畫圖片

Target Image:翻譯成中文對白後的漫畫圖片

界面設計代碼

咱們在MainWindow.xaml文件裏面填好如下code:

<Window x:Class="CartoonTranslate.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"
        xmlns:local="clr-namespace:CartoonTranslate"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Grid.Row="0">
            <TextBlock Grid.Row="0" Text="Input URL:"/>
            <TextBox x:Name="tb_Url" Grid.Row="1" Width="600"
                     Text="http://stat.ameba.jp/user_images/20121222/18/secretcube/2e/19/j/o0800112012341269548.jpg"/>
            <Button x:Name="btn_Show" Content="Show" Click="btn_Show_Click" Width="100"/>
            <Button x:Name="btn_OCR" Content="OCR" Click="btn_OCR_Click" Width="100"/>
            <Button x:Name="btn_Translate" Content="Translate" Click="btn_Translate_Click" Width="100"/>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <TextBlock Text="Engine:"/>
            <RadioButton x:Name="rb_V1" GroupName="gn_Engine" Content="OCR" Margin="20,0" IsChecked="True" Click="rb_V1_Click"/>
            <RadioButton x:Name="rb_V2" GroupName="gn_Engine" Content="Recognize Text" Click="rb_V2_Click"/>
            <TextBlock Text="Language:" Margin="20,0"/>
            <RadioButton x:Name="rb_English" GroupName="gn_Language" Content="English"/>
            <RadioButton x:Name="rb_Japanese" GroupName="gn_Language" Content="Japanese" IsChecked="True" Margin="20,0"/>
        </StackPanel>
        <Grid Grid.Row="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="40"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="Source Image" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <TextBlock Grid.Column="2" Text="Target Image" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <Image x:Name="imgSource" Grid.Column="0" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
            <Image x:Name="imgTarget" Grid.Column="2" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
            <Canvas x:Name="canvas_1" Grid.Column="0"/>
            <Canvas x:Name="canvas_2" Grid.Column="2"/>
        </Grid>
</Grid>
</Window>

 

處理事件

關於XAML語法的問題不在本文的討論範圍以內。上面的XAML寫好後,編譯時會出錯,由於裏面定義了不少事件,在C#文件中尚未實現。因此,咱們如今把事件代碼補上。

局部變量定義(在MainWindow.xaml.cs的MainWindow class裏面):

        // using 「OCR」 or 「Recognize Text」
        private string Engine;
        // source language, English or Japanese
        private string Language;
        // OCR result object
        private OcrResult.Rootobject ocrResult;

 

按鈕"Show"的事件

點擊Show按鈕的事件,把URL中的漫畫的地址所指向的圖片加載到窗口中顯示:

 private void btn_Show_Click(object sender, RoutedEventArgs e)
        {
            if (!Uri.IsWellFormedUriString(this.tb_Url.Text, UriKind.Absolute))
            {
                // show warning message
                return;
            }

            // show image at imgSource
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.UriSource = new Uri(this.tb_Url.Text);
            bi.EndInit();
            this.imgSource.Source = bi;
            this.imgTarget.Source = bi;
        }

 

在上面的代碼中,同時給左右兩個圖片區域賦值,顯示兩張同樣的圖片。

 

按鈕"OCR"的事件

點擊OCR按鈕的事件,會調用OCR REST API,而後根據返回結果把全部識別出來的文字用紅色的矩形框標記上:

private async void btn_OCR_Click(object sender, RoutedEventArgs e)
        {
            this.Engine = GetEngine();
            this.Language = GetLanguage();

            if (Engine == "OCR")
            {
                ocrResult = await CognitiveServiceAgent.DoOCR(this.tb_Url.Text, Language);
                foreach (OcrResult.Region region in ocrResult.regions)
                {
                    foreach (OcrResult.Line line in region.lines)
                    {
                        if (line.Convert())
                        {
                            Rectangle rect = new Rectangle()
                            {
                                Margin = new Thickness(line.BB[0], line.BB[1], 0, 0),
                                Width = line.BB[2],
                                Height = line.BB[3],
                                Stroke = Brushes.Red,
                                //Fill =Brushes.White
                            };
                            this.canvas_1.Children.Add(rect);
                        }
                    }
                }
            }
            else
            {
            }
        }

 

 

在上面的代碼中,經過調用DoOCR()自定義函數返回了反序列化好的類,再依次把返回結果集中的每一個矩形生成一個Rectangle圖形類,它的left和top用Margin的方式來定義,width和height直接賦值便可,把這些Rectangle圖形類的實例添加到canvas_1的Visual Tree裏便可顯示出來(這個就是WPF的好處啦,不用處理繪圖事件,但性能不如用Graphics類直接繪圖)。

按鈕"Translate"的事件

點擊Translate按鈕的事件:

private async void btn_Translate_Click(object sender, RoutedEventArgs e)
        {
            List<string> listTarget = await this.Translate();
            this.ShowTargetText(listTarget);
        }
        
        private async Task<List<string>> Translate()
        {
            List<string> listSource = new List<string>();
            List<string> listTarget = new List<string>();
            if (this.Version == "OCR")
            {
                foreach (OcrResult.Region region in ocrResult.regions)
                {
                    foreach (OcrResult.Line line in region.lines)
                    {
                        listSource.Add(line.TEXT);
                        if (listSource.Count >= 25)
                        {
                            List<string> listOutput = await CognitiveServiceAgent.DoTranslate(listSource, Language, "zh-Hans");
                            listTarget.AddRange(listOutput);
                            listSource.Clear();
                        }
                    }
                }
                if (listSource.Count > 0)
                {
                    List<string> listOutput = await CognitiveServiceAgent.DoTranslate(listSource, Language, "zh-Hans");
                    listTarget.AddRange(listOutput);
                }
            }

            return listTarget;
        }
        private void ShowTargetText(List<string> listTarget)
        {
            int i = 0;
            foreach (OcrResult.Region region in ocrResult.regions)
            {
                foreach (OcrResult.Line line in region.lines)
                {
                    string translatedLine = listTarget[i];

                    Rectangle rect = new Rectangle()
                    {
                        Margin = new Thickness(line.BB[0], line.BB[1], 0, 0),
                        Width = line.BB[2],
                        Height = line.BB[3],
                        Stroke = null,
                        Fill =Brushes.White
                    };
                    this.canvas_2.Children.Add(rect);

                    TextBlock tb = new TextBlock()
                    {
                        Margin = new Thickness(line.BB[0], line.BB[1], 0, 0),
                        Height = line.BB[3],
                        Width = line.BB[2],
                        Text = translatedLine,
                        FontSize = 16,
                        TextWrapping = TextWrapping.Wrap,
                        Foreground = Brushes.Red
                    };
                    this.canvas_2.Children.Add(tb);
                    i++;
                }
            }
        }

 

上面這段代碼中,包含了兩個函數:this.Translate()和this.ShowTargetText()。

咱們先看第一個函數:最難理解的地方多是有個"25"數字,這是由於Translate API容許一次提交多個字符串並一塊兒返回結果,這樣比你提交25次字符串要快的多。翻譯好的結果按順序放在listOutput裏,供後面使用。

再看第二個函數:先根據原始文字的矩形區域,生成一些白色的實心矩形,把它們貼在右側的目標圖片上,達到把原始文字覆蓋(扣去)的目的。而後再根據每一個原始矩形生成一個TextBlock,設定好它的位置和尺寸,再設置好翻譯後的結果(translatedLine),這樣就能夠把中文文字貼到圖上了。

選項按鈕的事件

點擊Radio Button的事件:

private void rb_V1_Click(object sender, RoutedEventArgs e)
        {
            this.rb_Japanese.IsEnabled = true;
        }

        private void rb_V2_Click(object sender, RoutedEventArgs e)
        {
            this.rb_English.IsChecked = true;
            this.rb_Japanese.IsChecked = false;
            this.rb_Japanese.IsEnabled = false;
        }
        private string GetLanguage()
        {
            if (this.rb_English.IsChecked == true)
            {
                return "en";
            }
            else
            {
                return "ja";
            }
        }

        private string GetEngine()
        {
            if (this.rb_V1.IsChecked == true)
            {
                return "OCR";
            }
            else
            {
                return "RecText";
            }
        }

 

API數據訪問部分

咱們須要在CatroonTranslate工程中添加如下三個.cs文件:

  • CognitiveServiceAgent.cs
  • OcrResult.cs
  • TranslateResult.cs

與認知服務交互

CognitiveServiceAgent.cs文件完成與REST API交互的工做,包括調用OCR服務的和調用翻譯服務的代碼:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace CartoonTranslate
{
    class CognitiveServiceAgent
    {
        const string OcrEndPointV1 = "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/ocr?detectOrientation=true&language=";
        const string OcrEndPointV2 = "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/recognizeText?mode=Printed";
        const string VisionKey1 = "4c20ac56e1e7459a05e1497270022b";
        const string VisionKey2 = "97992f0987e4be6b5be132309b8e57";
        const string UrlContentTemplate = "{{\"url\":\"{0}\"}}";

        const string TranslateEndPoint = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&from={0}&to={1}";
        const string TKey1 = "04023df3a4c499b1fc82510b48826c";
        const string TKey2 = "9f76381748549cb503dae4a0d80a80";

        public static async Task<List<string>> DoTranslate(List<string> text, string fromLanguage, string toLanguage)
        {
            try
            {
                using (HttpClient hc = new HttpClient())
                {
                    hc.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", TKey1);
                    string jsonBody = CreateJsonBodyElement(text);
                    StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
                    string uri = string.Format(TranslateEndPoint, fromLanguage, toLanguage);
                    HttpResponseMessage resp = await hc.PostAsync(uri, content);
                    string json = await resp.Content.ReadAsStringAsync();
                    var ro = Newtonsoft.Json.JsonConvert.DeserializeObject<List<TranslateResult.Class1>>(json);
                    List<string> list = new List<string>();
                    foreach(TranslateResult.Class1 c in ro)
                    {
                        list.Add(c.translations[0].text);
                    }
                    return list;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return null;
            }
        }

        private static string CreateJsonBodyElement(List<string> text)
        {
            var a = text.Select(t => new { Text = t }).ToList();
            var b = JsonConvert.SerializeObject(a);
            return b;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="imageUrl"></param>
        /// <param name="language">en, ja, zh</param>
        /// <returns></returns>
        public static async Task<OcrResult.Rootobject> DoOCR(string imageUrl, string language)
        {
            try
            {
                using (HttpClient hc = new HttpClient())
                {
                    ByteArrayContent content = CreateHeader(hc, imageUrl);
                    var uri = OcrEndPointV1 + language;
                    HttpResponseMessage resp = await hc.PostAsync(uri, content);
                    string result = string.Empty;
                    if (resp.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        string json = await resp.Content.ReadAsStringAsync();
                        Debug.WriteLine(json);
                        OcrResult.Rootobject ro = Newtonsoft.Json.JsonConvert.DeserializeObject<OcrResult.Rootobject>(json);
                        return ro;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                Debug.Write(ex.Message);
                return null;
            }
        }

        private static ByteArrayContent CreateHeader(HttpClient hc, string imageUrl)
        {
            hc.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", VisionKey1);
            string body = string.Format(UrlContentTemplate, imageUrl);
            byte[] byteData = Encoding.UTF8.GetBytes(body);
            var content = new ByteArrayContent(byteData);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            return content;
        }
    }
}

 小提示:以上兩個Key是沒法直接使用的,請使用本身申請的Key。

其中,DoTranslate()函數和DoOCR()函數都是HTTP調用,很容易理解。只有CreateJsonBodyElement函數須要解釋一下。前面提到過咱們一次容許給服務器提交25個字符串作批量翻譯,所以傳進來的是個List<string>,通過這個函數的簡單處理,會獲得如下JSON格式的數據做爲HTTP的Body:

// JSON Data as Body
[
        {「Text」 : 」第1個字符串」},
        {「Text」 : 」第2個字符串」},
        ……..
        {「Text」 : 」第25個字符串」},
]

 

OCR服務的數據類定義

OcrResult.cs文件是OCR服務返回的JSON數據所對應的類,用於反序列化:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CartoonTranslate.OcrResult
{
    public class Rootobject
    {
        public string language { get; set; }
        public string orientation { get; set; }
        public float textAngle { get; set; }
        public Region[] regions { get; set; }
    }

    public class Region
    {
        public string boundingBox { get; set; }
        public Line[] lines { get; set; }
    }

    public class Line
    {
        public string boundingBox { get; set; }
        public Word[] words { get; set; }

        public int[] BB { get; set; }
        public string TEXT { get; set; }


        public bool Convert()
        {
            CombineWordToSentence();
            return ConvertBBFromString2Int();
        }

        private bool ConvertBBFromString2Int()
        {
            string[] tmp = boundingBox.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (tmp.Length == 4)
            {
                BB = new int[4];
                for (int i = 0; i < 4; i++)
                {
                    int.TryParse(tmp[i], out BB[i]);
                }
                return true;
            }
            return false;
        }

        private void CombineWordToSentence()
        {
            StringBuilder sb = new StringBuilder();
            foreach (Word word in words)
            {
                sb.Append(word.text);
            }
            this.TEXT = sb.ToString();
        }

    }

    public class Word
    {
        public string boundingBox { get; set; }
        public string text { get; set; }
    }
}

  

須要說明的是,服務器返回的boundingBox是個string類型,在後面使用起來不太方便,須要把它轉換成整數,因此增長了CovertBBFromString2Int()函數。還有就是返回的是一個個的詞(Word),而不是一句話,因此增長了CombineWordToSentence()來把詞連成句子。

翻譯服務的數據類定義

TranslateResult.cs文件翻譯服務返回的JSON所對應的類,用於反序列化:

namespace CartoonTranslate.TranslateResult
{
    public class Class1
    {
        public Translation[] translations { get; set; }
    }

    public class Translation
    {
        public string text { get; set; }
        public string to { get; set; }
    }
}

 

小提示:在VS2017中,這種類不須要手工鍵入,能夠在Debug模式下先把返回的JSON拷貝下來,而後新建一個.cs文件,在裏面用Paste Special從JSON直接生成類就能夠了。

運行程序

好啦,大功告成!如今要作的事就是點擊F5來編譯執行程序。若是一切順利的話,將會看到界面設計部分所展現的窗口。

咱們第一步先點擊"Show"按鈕,會獲得:

再點擊"OCR"按鈕,等兩三秒(取決於網絡速度),會看到左側圖片中紅色的矩形圍攏的一些文字。有些文字沒有被識別出來的話,就沒有紅色矩形。

最後點擊"Translate"按鈕,稍等一小會兒,會看到右側圖片的變化:

Wow! 大部分的日文被翻譯成了中文,並且位置也擺放得很合適。

習題與進階學習

增長容錯代碼讓程序健壯

目前的代碼中沒有不少容錯機制,好比當服務器返回錯誤時,訪問API的代碼會返回一個NULL對象,在上層沒有作處理,直接崩潰。再好比,當用戶不按照從左到右的順序點擊上面三個button時,會產生意想不到的狀況。

改進本應用讓其自動化和產業化

本應用處理單頁的漫畫,而且提供了交互,目的是讓你們直觀理解工做過程,實際上這個過程能夠作成批量自動化的,也就是輸入一大堆URL,作後臺識別/翻譯/從新生成圖片後,把圖片批量保存在本地,再進行後處理。

固然,識別引擎不是萬能的,不少時候不可能準確識別/翻譯出全部對白文字。因此,能夠考慮提供一個相似本應用的交互工具,讓漫畫翻譯從業者在機器處理以後,對有錯誤的地方進行糾正。

小提示:請嚴格遵照知識產權保護法!在合法的狀況下作事。

使用新版本的Engine作字符識別

還記得前面提到過新舊引擎的話題嗎?咱們在界面上作了一個Radio Button "Recognize Text",可是並無使用它。由於這個新引擎目前還只能支持英文的OCR,因此,若是你們對漫威Marvel漫畫(英文爲主)感興趣的話,就能夠用到這個引擎啦,與舊OCR引擎相比,不能同日而語,超級棒!

舊OCR引擎的文檔在這裏:https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fc

新Recognize Text引擎的文檔在這裏:

https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/587f2c6a154055056008f200

新的引擎在API交互設計上,有一個不一樣的地方:當你提交一個請求後,服務器會馬上返回Accepted (202),而後給你一個URL,用於查詢狀態的。因而須要在客戶端程序裏設個定時器,每隔一段時間(好比200ms),訪問那個URL,來得到最終的OCR結果。

返回的結果JSON格式也有所不一樣,你們能夠本身試着實現一下:

OCR糾錯處理

在下圖中,如綠色橢圓區域所示,OCR引擎犯了一個小錯誤,它把上下兩個不一樣對白氣泡的文字框在了一塊兒。

這個是能夠在本身的程序裏作後期糾錯處理來矯正的。你們能夠仔細分析OCR的返回結果,看看如何實現。文檔在這裏:

https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fc

聚類處理待翻譯的文字

觀察力好的同窗,可能會發現一個問題,以下圖所示,左側圖的一個對白氣泡裏,有四句話,但其實它們是一句話,分開寫到4列而已。

這種狀況帶來的問題是:這四句話分別送給翻譯引擎作翻譯,會形成先後不連貫,語句不通順。能夠考慮的解決方案是,先根據矩形的位置信息,把這四句話合併成同一句話,再送給翻譯引擎。這就是標準的聚類問題,經過搜索引擎能夠找到一大堆參考文檔,好比這些:

https://blog.csdn.net/summer_upc/article/details/51475512

https://www.ibm.com/developerworks/cn/analytics/library/ba-1607-clustering-algorithm/index.html

相關文章
相關標籤/搜索