【语言与知识主题月】图片文字翻译
让天涯 发布于2020-07-29 浏览:1517 回复:2
0
收藏
最后编辑于2020-07-30

一、功能介绍

使用百度AI技术《通用文字识别(高精度)》和《通用翻译API(标准版)》来实现图片/文字翻译功能,本教程仅实现中英文翻译,其他语言翻译在此基础上稍加修改就能实现。

二、应用场景

通用翻译API可广泛应用于APP、网站及客户端,提供实时优质的多语言翻译服务。
将此翻译功能部署到网站上,可实现手机拍照翻译的效果(部分手机浏览器的图片上传功能可实现直接拍照上传图片),添加多语种翻译后,基本上就是一个简单的在线拍照翻译网站了。
对于出国游玩、纸质文献翻译等场景,拍照翻译就显得很有必要了。

三、使用攻略

说明:本文采用C# 语言,开发环境为.Net Core 3.1,采用在线API接口方式实现。

(1)接口文档

(1-1)通用文字识别(高精度)

文档地址:https://ai.baidu.com/ai-doc/OCR/1k3h7y3db

接口描述:在通用文字识别的基础上,提供更高精度的识别服务,支持更多语种识别(丹麦语、荷兰语、马来语、瑞典语、印尼语、波兰语、罗马尼亚语、土耳其语、希腊语、匈牙利语),并将字库从1w+扩展到2w+,能识别所有常用字和大部分生僻字。

(1-2)通用翻译API(标准版)

文档地址:http://fanyi-api.baidu.com/doc/21

接口描述:通用翻译API通过HTTP接口对外提供多语种互译服务。您只需要通过调用通用翻译API,传入待翻译的内容,并指定要翻译的源语言(支持源语言语种自动检测)和目标语言种类,就可以得到相应的翻译结果。
具体关于输入参数、输出参数、错误码等说明,请参考开发文档,这里不再罗列。
(2)源码共享

(2-1)根据 API Key 和 Secret Key 获取 AccessToken

/// 
/// 获取百度access_token
/// 
/// API Key
/// Secret Key
/// 
public static string GetAccessToken(string clientId, string clientSecret)
{
    string authHost = "https://aip.baidubce.com/oauth/2.0/token";
    HttpClient client = new HttpClient();
    List> paraList = new List>();
    paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
    paraList.Add(new KeyValuePair("client_id", clientId));
    paraList.Add(new KeyValuePair("client_secret", clientSecret));

    HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
    string result = response.Content.ReadAsStringAsync().Result;
    JObject jo = (JObject)JsonConvert.DeserializeObject(result);

    string token = jo["access_token"].ToString();
    return token;
}

(2-2)调用API接口获取识别结果

(2-2-1)在Startup.cs 文件 的 Configure(IApplicationBuilder app, IHostingEnvironment env) 方法中开启虚拟目录映射功能:

string webRootPath = HostingEnvironment.WebRootPath;//wwwroot目录

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(webRootPath, "Uploads", "BaiduAIs")),
    RequestPath = "/BaiduAIs"
});

(2-2-2) 建立Index.cshtml文件

(2-2-2-1)前台代码:

    由于html代码无法原生显示,只能简单说明一下:

    主要是一个form表单,需要设置属性enctype="multipart/form-data",否则无法上传图片;

    form表单里面有几个控件:

一个input:type="file",asp-for="FileUpload" ,上传图片;

一个textarea:asp-for="Text" ,输入要翻译的内容;

一个input:type="submit",asp-page-handler="Words" ,实现文字翻译功能。

一个input:type="submit",asp-page-handler="Accurate" ,实现图片识别文字翻译功能。

一个img:src="@Model.curPath",显示需要识别的图片。

最后显示后台 msg 字符串列表信息,如果需要输出原始Html代码,则需要使用@Html.Raw()函数。 

(2-2-2-2) 后台代码: 

主程序代码:

[BindProperty]
public IFormFile FileUpload { get; set; }
[BindProperty]
public string ImageUrl { get; set; }
[BindProperty]
public string Text { get; set; }
public List msg = new List();
public StringBuilder sourceLanguage = new StringBuilder();
public string curPath { get; set; }
string webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");

string BaiduAI_OCRPath="Uploads//BaiduAIs//";
string BaiduAI_OCRUrl="/BaiduAIs/";
string OCR_API_KEY="你的API KEY";
string OCR_SECRET_KEY="你的SECRET KEY";

string Trans_APP_ID="你的百度翻译APP_ID";
string Trans_API_KEY="你的百度翻译SECRET_KEY";

public TransModel()
{
}

public void OnGet()
{

}

/// 
/// 获取翻译后的目标语言
/// 
/// 源语言
/// 
private string GetTargetLanguage(string sorceLanguage)
{
    string salt = GetRandomString();
    string sign = EncryptString(Trans_APP_ID + sorceLanguage + salt + Trans_API_KEY);
    string targetLanguage = GetFormTransJson(sorceLanguage, salt, sign, Trans_APP_ID, Trans_API_KEY);
    JObject jo = (JObject)JsonStringToObj(targetLanguage);
    return jo["trans_result"].ToList()[0]["dst"].ToString();
}

public async Task OnPostWordsAsync()
{
    if (string.IsNullOrEmpty(Text))
    {
        ModelState.AddModelError(string.Empty, "请输入翻译内容!");
    }
    if (!ModelState.IsValid)
    {
        return Page();
    }
    msg = new List();
    sourceLanguage = new StringBuilder();

    try
    {
        sourceLanguage.Append(Text.ToString());

        DateTime startTime = DateTime.Now;
        string targetLanguage = sourceLanguage.Length > 0 ? GetTargetLanguage(sourceLanguage.ToString()) : "";
        DateTime endTime = DateTime.Now;
        TimeSpan ts = endTime - startTime;

        msg.Add("文字翻译结果(耗时" + ts.TotalSeconds + "秒):\n");
        msg.Add("源语言:\n" + sourceLanguage.ToString());
        msg.Add("\n目标语言:\n" + targetLanguage);
    }
    catch (Exception e)
    {
        msg.Add(e.ToString());
    }
    return Page();
}

public async Task OnPostAccurateAsync()
{
    if (FileUpload is null)
    {
        ModelState.AddModelError(string.Empty, "请先选择需要识别的图片!");
    }
    if (!ModelState.IsValid)
    {
        return Page();
    }
    msg = new List();
    sourceLanguage = new StringBuilder();

    string fileDir = Path.Combine(webRootPath, BaiduAI_OCRPath);
    string imgName = GetRandomName();
    imgName = await UploadFile(FileUpload, fileDir);

    string fileName = Path.Combine(fileDir, imgName);
    string imgBase64 = GetFileBase64(fileName);
    curPath = Path.Combine(BaiduAI_OCRUrl, imgName);

    DateTime startTime = DateTime.Now;
    string result = GetOCRJson(imgBase64, OCR_API_KEY, OCR_SECRET_KEY);
    DateTime endTime = DateTime.Now;
    TimeSpan ts = endTime - startTime;

    JObject jo = (JObject)JsonStringToObj(result);

    try
    {
        msg.Add("文字识别(高精度)(耗时" + ts.TotalSeconds + "秒)翻译结果:\n");

        List msgList = jo["words_result"].ToList();
        foreach (JToken ms in msgList)
        {
            sourceLanguage.Append(ms["words"].ToString());
        }

        startTime = DateTime.Now;
        string targetLanguage = sourceLanguage.Length > 0 ? GetTargetLanguage(sourceLanguage.ToString()) : "";
        endTime = DateTime.Now;
        ts = endTime - startTime;

        msg.Add("源语言:\n" + sourceLanguage.ToString());
        msg.Add("\n目标语言(耗时" + ts.TotalSeconds + "秒):\n" + targetLanguage);
    }
    catch (Exception e)
    {
        msg.Add(result);
    }
    return Page();
}

其他相关函数:

/// 
/// 百度翻译字符串
/// 
/// 原文
/// 随机数
/// 签名
/// APP ID
/// 密钥
/// 源语言
/// 目标语言
/// 
public static string GetFormTransJson(string q, string salt, string sign, string appId, string secretKey, string from = "zh", string to = "en")
{
    string url = "http://api.fanyi.baidu.com/api/trans/vip/translate?";
    url += "q=" + HttpUtility.UrlEncode(q);
    url += "&from=" + from;
    url += "&to=" + to;
    url += "&appid=" + appId;
    url += "&salt=" + salt;
    url += "&sign=" + sign;
    Encoding encoding = Encoding.Default;
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "GET";
    request.ContentType = "text/html;charset=UTF-8";
    request.UserAgent = null;
    request.Timeout = 6000;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
    string result = reader.ReadToEnd();
    return result;
}

/// 
/// 文字识别Json字符串
/// 
/// 图片base64编码
/// API Key
/// Secret Key
/// 
public static string GetOCRJson( string strbaser64, string clientId, string clientSecret)
{
    string token = GetAccessToken(clientId, clientSecret);
    string host = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + token;
    Encoding encoding = Encoding.Default;
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
    request.Method = "post";
    request.ContentType = "application/x-www-form-urlencoded";
    request.KeepAlive = true;
    string str = "image=" + HttpUtility.UrlEncode(strbaser64);
    byte[] buffer = encoding.GetBytes(str);
    request.ContentLength = buffer.Length;
    request.GetRequestStream().Write(buffer, 0, buffer.Length);
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
    string result = reader.ReadToEnd();
    return result;
}

/// 
/// 获取百度access_token
/// 
/// API Key
/// Secret Key
/// 
public static string GetAccessToken(string clientId, string clientSecret)
{
    string authHost = "https://aip.baidubce.com/oauth/2.0/token";
    HttpClient client = new HttpClient();
    List> paraList = new List>();
    paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
    paraList.Add(new KeyValuePair("client_id", clientId));
    paraList.Add(new KeyValuePair("client_secret", clientSecret));

    HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
    string result = response.Content.ReadAsStringAsync().Result;
    JObject jo = (JObject)JsonConvert.DeserializeObject(result);

    string token = jo["access_token"].ToString();
    return token;
}

/// 
/// 计算MD5值
/// 
/// 文本
/// 
public static string EncryptString(string str)
{
    MD5 md5 = MD5.Create();
    // 将字符串转换成字节数组
    byte[] byteOld = Encoding.UTF8.GetBytes(str);
    // 调用加密方法
    byte[] byteNew = md5.ComputeHash(byteOld);
    // 将加密结果转换为字符串
    StringBuilder sb = new StringBuilder();
    foreach (byte b in byteNew)
    {
        // 将字节转换成16进制表示的字符串,
        sb.Append(b.ToString("x2"));
    }
    // 返回加密的字符串
    return sb.ToString();
}

/// 
/// 获取一个随机数
/// 
/// 
public static string GetRandomString()
{
    Random rd = new Random();
    string salt = rd.Next(100000).ToString();
    return salt;
}

/// 
/// 生成一个随机唯一文件名(Guid)
/// 
/// 
public static string GetRandomName()
{
    return Guid.NewGuid().ToString("N");
}

/// 
/// 返回图片的base64编码
/// 
/// 文件绝对路径名称
/// 
public static String GetFileBase64(string fileName)
{
    FileStream filestream = new FileStream(fileName, FileMode.Open);
    byte[] arr = new byte[filestream.Length];
    filestream.Read(arr, 0, (int)filestream.Length);
    string baser64 = Convert.ToBase64String(arr);
    filestream.Close();
    return baser64;
}

/// 
/// json转为对象
/// 
/// Json字符串
/// 
public static Object JsonStringToObj(string jsonString)
{
    Object s = JsonConvert.DeserializeObject(jsonString);
    return s;
}

/// 
/// 上传文件,返回文件名
/// 
/// 文件上传控件
/// 文件绝对路径
/// 
public static async Task UploadFile(IFormFile formFile, string fileDir)
{
    if (!DirectoryExists(directory))
    {
        Directory.CreateDirectory(directory);
    }
    string extension = Path.GetExtension(formFile.FileName);
    string imgName = Guid.NewGuid().ToString("N") + extension;
    var filePath = Path.Combine(fileDir, imgName);

    using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
    {
        await formFile.CopyToAsync(fileStream);
    }

    return imgName;
}

四、效果测试

1、页面:

2、识别结果:

2.1

2.2

2.3

2.4

2.5

五、测试结果及建议

从测试结果来看,文字翻译结果在简单的语句上是比较准的,速度也是比较快的,0.3秒左右,但是当语句比较复杂且没有分隔符的时候(图2.3,图2.4)翻译结果就比较差了,当然这个情况也比较少见,不过也是一个需要优化的地方:实现智能断句,正确翻译。

其实图片拍照翻译这个用处还是比较大的,随手一拍,直接显示翻译结果,简单方便,特别是出国旅游/纸质文献翻译等场景下,基本上算得上刚需了。

百度也有专门的拍照翻译SDK/API一体化,大家也可以去试试看。

收藏
点赞
0
个赞
共2条回复 最后由鹿鼎记肯定回复于2020-07-30
#3鹿鼎记肯定回复于2020-07-30

看到了,,原来机器翻译也有啊

0
#2鹿鼎记肯定回复于2020-07-30

这个是不是偏题了呀

0
TOP
切换版块