前言
最近在网上买了些东西,感觉不好,想退, 在办理退件过程中发现个好玩意,类似这样的输入框,
上传商户发的退货地址,自动识别退货信息。 也可粘贴文本自动识别。
感觉有点意思。考虑过各种实现原理,什么字典库,大数据之类。。。。,但是这些对个体小户来说不现实。最后还是靠baidu。
我的实现思路:
1、上传图像 ...(废话), 转base64 .
2、识别图像中文字,即OCR , 目前有很多实现此功能的插件和接口,我使用的baiduapi,在百度开发者账户中可以申请的。 链接在此。 https://cloud.baidu.com/product/ocr 。
3、分词。 将图像转成的文字进行分词,识别人名,公司名,电话,省市区,详细地址。分词也有很多组件,我还是使用的baiduapi, 自然语言词法分析 http://ai.baidu.com/tech/nlp/lexical 。
4、转换。将分析的词进一步解析,比如将省市区转换为自己数据库中对应的省市区ID。
5、回传显示
实现步骤
1、准备好百度api相关配置信息
//百度申请得到的AK http://lbsyun.baidu.com/apiconsole/key
public string Baidu_AK = "AAAAAAAAAAAAAAAAAAAAAA";
// 文字识别 https://cloud.baidu.com/product/ocr
public string Baidu_OCRApiKey = "BBBBBBBBBBBBBBBBBBB";
public string Baidu_OCRSecret = "CCCCCCCCCCCCCCCCCCCC";
//词法分析 http://ai.baidu.com/tech/nlp/lexical
public string Baidu_NLPApiKey = "DDDDDDDDDDDDDDDDDDDDDDDD";
public string Baidu_NLPSecret = "EEEEEEEEEEEEEEEEEEEEEEEEE";
2、上传图像,转base64 .
上传略去,,, 转base64 给代码
///
/// 图像路径
///
///
///
public static string ImgToBase64Str(string filepath)
{
try
{
Bitmap bmp = new Bitmap(filepath);
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length);
ms.Close();
return Convert.ToBase64String(arr);
}
catch (Exception ex)
{
return null;
}
}
2、图像识别
使用图像识别前要先获取AccessToken ,和微信开发一样的。
///
/// 获取AccessToken
///
///
private String getAccessToken(string Baidu_ApiKey, string Baidu_SecretKey)
{
string xpath = "//BaiduApi[@ApiKey='" + Baidu_ApiKey + "']";
XmlNode apinode = XMLCache.SelectSingleNode(xpath);
if (apinode != null)
{
string nodestr = apinode.InnerText;
if (!string.IsNullOrEmpty(nodestr))
{
BaiduAccessToken AccessToken = JsonConvert.DeserializeObject(nodestr);
if (AccessToken != null && AccessToken.ExpireTime > DateTime.Now.AddMinutes(3))
{
return AccessToken.access_token;
}
}
}
// 缓存中若没有,重新获取
String authHost = "https://aip.baidubce.com/oauth/2.0/token";
List> paraList = new List>();
paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
paraList.Add(new KeyValuePair("client_id", Baidu_ApiKey));
paraList.Add(new KeyValuePair("client_secret", Baidu_SecretKey));
String result = WebUtil.HttpClientPost(authHost, paraList);
BaiduAccessToken token = JsonConvert.DeserializeObject(result);
if (token != null && !string.IsNullOrEmpty(token.access_token))
{
token.ExpireTime = DateTime.Now.AddSeconds(token.expires_in);
if (apinode != null)
{
apinode.InnerText = JsonConvert.SerializeObject(token);
}
else
{
XmlNode node = XMLCache.SelectSingleNode(ROOT);
XmlElement baiduapi = XMLCache.CreateElement("BaiduApi");
baiduapi.InnerText = JsonConvert.SerializeObject(token);
XmlAttribute apikey = XMLCache.CreateAttribute("ApiKey");
apikey.Value = Baidu_ApiKey;
baiduapi.Attributes.Append(apikey);
node.AppendChild(baiduapi);
}
XMLCache.Save(filepath);
return token.access_token;
}
return "";
}
调用api ,识别图像内容 ,
base64一定要转码 ,切记。
System.Web.HttpUtility.UrlEncode(base64str, System.Text.Encoding.UTF8)
private OcrData GetOcrData(string base64str)
{
string token = getAccessToken(Baidu_OCRApiKey, Baidu_OCRSecret);
string OCR_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" + token;
Dictionary verifyPostParameters = new Dictionary();
List> paraList = new List>();
paraList.Add(new KeyValuePair("image", base64str));
String result = WebUtil.HttpClientPostImg(OCR_URL, paraList);
OcrData ocrResult = JsonConvert.DeserializeObject(result);
return ocrResult;
}
HttpClientPostImg 自己封装的。
///
/// HttPClient操作POST
///
///
///
///
public static string HttpClientPostImg(string url, List> data)
{
using (var client = new HttpClient())
{
string str = string.Empty;
if (data != null)
{
foreach (var item in data)
{
str += item.Key + "=" + item.Value;
}
}
var content = new StringContent(str, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
return responseString;
}
}
3、分词
使用前同样要获取AccessToken , 将上步骤解析到的字符串拼接为一字符串,传入api .
///
///
///
///
///
private BaiduLexer GetBaiduLexer(string par)
{
string token = getAccessToken(Baidu_NLPApiKey, Baidu_NLPSecret);
string OCR_URL = "https://aip.baidubce.com/rpc/2.0/nlp/v1/lexer?access_token=" + token;
Dictionary verifyPostParameters = new Dictionary();
String result = WebUtil.PostMoths(OCR_URL, par);
BaiduLexer baiduLexer = JsonConvert.DeserializeObject(result);
return baiduLexer;
}
解析结果 标识--百度api
3.1 获取人名。
///
/// 获取人员姓名或公司名称
///
///
///
private string GetPER(BaiduLexer baiduLexer)
{
string per = string.Empty;
var items = baiduLexer.items;
var perm = items.LastOrDefault(e => e.ne == "PER");
if (perm != null)
{
per = perm.item;
}
else
{
var nrm = items.LastOrDefault(e => e.pos == "nr");
if (nrm != null)
{
per = nrm.item;
}
}
if (string.IsNullOrEmpty(per))
{
var orgm = items.LastOrDefault(e => e.ne == "ORG");
if (orgm != null)
{
per = orgm.item;
}
else
{
var nt = items.LastOrDefault(e => e.pos == "nt");
if (nt != null)
{
per = nt.item;
}
}
}
return per;
}
3.2 获取电话
///
/// 匹配电话
///
///
///
private string GetMobile(string input)
{
Regex regex = new Regex("0?(13|14|15|17|18|19)[0-9]{9}");
Match match = regex.Match(input);
if (match.Success)
{
return match.Value;
}
else
{
Regex _regex = new Regex("^(0[0-9]{2,3}/-)?([2-9][0-9]{6,7})+(/-[0-9]{1,4})?$");
Match _match = regex.Match(input);
if (_match.Success)
{
return _match.Value;
}
}
return "";
}
3.3 获取地址
///
/// 获取地址
///
///
///
private string GetLOC(BaiduLexer baiduLexer)
{
string address = string.Empty;
var items = baiduLexer.items;
var list = items.Where(e => e.ne == "LOC").ToList();
if (list != null && list.Count > 0)
{
foreach (var item in list)
{
address += item.item;
}
}
return address;
}
4、转换
得到的地址信息是一串字符串,如:上海上海市普陀区桃浦新村X弄XX号。或上海普陀区桃浦新村X路XX号
地址不一定按照 XX省XX市XX区标准格式。。有能力的自己写正则匹配(在下佩服), 像我这样懒的找个api试试。
so .我又找度娘。。 我使用的方法比较笨, 如有好方法,希望留言探讨。
我先用得到的地址信息获取经纬度, 再用经纬度获取省市区。百度api会帮忙校验地址合法性以及补全地址信息。
4.1 获取经纬度
///
/// 根据地址获取经纬度
///
///
///
public Location GetLocation(string address, string Baidu_AK)
{
string Url = "http://api.map.baidu.com/geocoder/v2/?address=" + address + "&output=json&ak=" + Baidu_AK;
String result = WebUtil.HttpClientGet(Url);
BaiduMapApiResult Result = JsonConvert.DeserializeObject(result);
if (Result.status == 0)
{
return Result.result.location;
}
return null;
}
4.2 根据经纬度获取地址信息
public LocationOut GetLocation(decimal lat, decimal lnt, string Baidu_AK)
{
StringBuilder URLbuilder = new StringBuilder("http://api.map.baidu.com/geocoder/v2/");
URLbuilder.AppendFormat("?location={0},{1}", lat, lnt);
URLbuilder.Append("&output=json&pois=0");
URLbuilder.AppendFormat("&ak={0}", Baidu_AK);
string restult = WebUtil.HttpClientGet(URLbuilder.ToString());
LocationOut location = new LocationOut();
var baiduresult = JsonConvert.DeserializeObject(restult);
if (baiduresult.status == 0 && !string.IsNullOrEmpty(baiduresult.result.formatted_address))
{
var addressComponent = baiduresult.result.addressComponent;
location.ProvinceName = addressComponent.province;
location.CityName = addressComponent.city;
location.AreaName = addressComponent.district;
}
return location;
}
5、显示,,,,没啥说的
结尾
此实例对应并发性较高的不太使用。毕竟百度API 限制DPS为5 ,
实际业务中,中小客户,地址使用频率并不是很高, 可以使用,但不是很建议,
网络上有提供识别地址的服务,当然是收费的,而且价格还很高。
实例截图,
实例代码下载 地址 : https://download.csdn.net/download/qq_25042791/10567449