谈谈调用腾讯云【OCR-通用印刷体识别】Api踩的坑
一、写在前面
最近做项目需要用到识别图片中文字的功能,本来用的Tesseract这个写的,不过效果不是很理想。
随后上网搜了一下OCR接口,就准备使用腾讯云、百度的OCR接口试一下效果。不过这个腾讯云OCR就折腾了一天!
二、OCR-通用印刷体识别
首先附上文档地址:OCR-通用印刷体识别。
1、通用OCR简介
通用OCR技术提供图片整体文字的检测和识别服务,返回文字框位置与文字内容。支持多场景、任意版面下整图文字的识别,以及中英文、字母、数字的识别。被广泛应用于印刷文档识别、广告图文字识别、街景店招识别、菜单识别、视频标题识别、互联网头像文字识别等。
2、接口url地址
http://recognition.image.myqcloud.com/ocr/general
3、请求包header
接口采用http协议,支持指定图片URL和上传本地图片文件两种方式。
所有请求都要求含有下列的头部信息:
Host、Content-Length、Content-Type、Authorization
三、示例
1、使用 url 的请求包
POST /ocr/general HTTP/1.1
Authorization: FCHXdPTEwMDAwMzc5Jms9QUtJRGVRZDBrRU1yM2J4ZjhRckJi==
Host: recognition.image.myqcloud.com
Content-Length: 187
Content-Type: application/json
{
"appid":"123456",
"bucket":"test",
"url":"http://test-123456.image.myqcloud.com/test.jpg"
}
这个url是万象优图中图片的url地址。

看到这种格式,心里大概有数了,开始敲代码。
2、具体实现
HttpClient client = new HttpClient();
var para = new
{
appid = "123456",
bucket = "test",
url = "http://test-123456.image.myqcloud.com/test.jpg"
};
var jsonPara = JsonConvert.SerializeObject(para);
StringContent content = new StringContent(jsonPara);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentLength = jsonPara.Length;
content.Headers.Add("Host", "recognition.image.myqcloud.com");
content.Headers.Add("Authorization", aut);
var taskHrm = client.PostAsync(postUrl, content);
taskHrm.Wait();
var taskStr = taskHrm.Result.Content.ReadAsStringAsync();
taskStr.Wait();
var result = taskStr.Result;
F5运行,结果报错了:

这个错误的原因为:Host和Authorization不能这样添加到Headers中。于是乎我自作聪明的把它们放到参数中了:
var para = new
{
appid = "123456",
bucket = "test",
url = "http://test-123456.image.myqcloud.com/test.jpg",
Host = "recognition.image.myqcloud.com",
Authorization = aut
};
这样运行代码是没有报错,不过后台返回“has no sign or sign is empty”,没有签名。
再回头看看参数要求,Host和Authorization必须添加在请求包Header中。于是百度一下,如何使用Httpclient设置Authorization。最终解决方案如下:
client.DefaultRequestHeaders.Host = "recognition.image.myqcloud.com";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", aut);
成功运行!
但是项目中使用url的几率毕竟少,基本上都是上传一张本地图片,然后识别出来文字。
下面来看一下识别一张本地图片。
3、使用 image 的请求包
POST /ocr/general HTTP/1.1
Authorization: FCHXdPTEwMDAwMzc5Jms9QUtJRGVRZDBrRU1yM2J4ZjhRckJi==
Host: recognition.image.myqcloud.com
Content-Length: 735
Content-Type: multipart/form-data;boundary=--------------acebdf13572468 ----------------acebdf13572468
Content-Disposition: form-data; name="appid"; 123456
----------------acebdf13572468
Content-Disposition: form-data; name="bucket"; test
----------------acebdf13572468
Content-Disposition: form-data; name="image"; filename="test.jpg"
Content-Type: image/jpeg xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
----------------acebdf13572468--
说实话看到这种格式,一开始真是一脸懵逼,前面几个参数还好,后面这一大串不知道怎么传递过去,后来百度了一下,这种格式符合RFC 2045协议。
具体解释一下:
第5行:声明Content Type类型,并定义边界字符串。边界符可以自定义,不过最好是用破折号等数据中一般不会出现的字符;
第6、9、13以及18行是换行,传递的时候使用‘\r\n';
第7、11以及15行是‘--’加上第5行的boundary即边界字符串。这里要注意是一定要加上前面的连字符‘--’,我开始没注意写的是和boundary一样,结果一直报错。
第8、10、12、14就是传递的Key_Value类型的数据。“appid”和“bucket”就是要传递的key,而“123456”以及“test”就是分别对应的value。
第16、17行代表另外一个数据,key是image,filename是“test.jpg”。
最后两行就是结束了。注意最后一行是boundary加上‘--’。
弄清楚是什么意思了,就可以开始写代码了。这里我们用WebRequest,至于为什么不用HttpClient,研究ing。不知哪位仁兄使用HttpClient写过,请不吝赐教。
4、具体实现
要识别的图片如下:

HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));
Stream memStream = new MemoryStream();
webReq.Method = "POST";
string boundary = "--------------" + DateTime.Now.Ticks.ToString("x");// 边界符
webReq.ContentType = "multipart/form-data; boundary=" + boundary;
接下来是一个换行符,对应第6行:
byte[] enter = Encoding.ASCII.GetBytes("\r\n"); //换行
memStream.Write(enter, 0, enter.Length);
传递key_value的时候格式都是一样,于是我们写在一个循环里面:
Dictionary<string, string> dic = new Dictionary<string, string>()
{
{"appid","1255710379"} ,
{"bucket","test1"}
};
//写入文本字段
string inputPartHeaderFormat = "--" + boundary + "\r\n" + "Content-Disposition:form-data;name=\"{0}\";" + "\r\n\r\n{1}\r\n";
foreach (var kv in dic)
{
string inputPartHeader = string.Format(inputPartHeaderFormat, kv.Key, kv.Value);
var inputPartHeaderBytes = Encoding.ASCII.GetBytes(inputPartHeader);
memStream.Write(inputPartHeaderBytes, 0, inputPartHeaderBytes.Length);
}
接着该写入image了,这里我们在bin/debug里面有一张名为1.jpg的图片(即为上面的图片)。
var fileStream = new FileStream("1.jpg", FileMode.Open, FileAccess.Read);
// 写入文件
string imagePartHeader = "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
"Content-Type: image/jpeg\r\n\r\n";
var header = string.Format(imagePartHeader, "image", "1.jpg");
var headerbytes = Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
var buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
最后就是结束符了:
// 最后的结束符
byte[] endBoundary = Encoding.ASCII.GetBytes("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "\r\n" + boundary + "--\r\n");
memStream.Write(endBoundary, 0, endBoundary.Length);
接下来设置其他Header参数:
webReq.ContentLength = memStream.Length;
webReq.Headers.Add(HttpRequestHeader.Authorization, aut);
webReq.Host = "recognition.image.myqcloud.com";
这里需要注意的一点是设置Host值的时候不能使用
webReq.Headers.Add(HttpRequestHeader.Host, "recognition.image.myqcloud.com");
这个方法,否则会有异常。
var requestStream = webReq.GetRequestStream();
memStream.Position = 0;
memStream.CopyTo(requestStream);
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
var ret = sr.ReadToEnd();
sr.Close();
response.Close();
requestStream.Close();
memStream.Close();
完美运行!识别结果如下:
四、需要注意的点
1、计算Authorization授权签名
签名分为多次有效签名和单次有效签名。它们拼接成的签名串格式为:
a=[appid]&b=[bucket]&k=[SecretID]&e=[expiredTime]&t=[currentTime]&r=[rand]&u=[userid]&f=[fileid]
具体每个字段的含义请参见官方文档:签名和鉴权文档
需要注意的有两点:
1、使用 HMAC-SHA1 算法对请求进行加密;
2、签名串需要使用 Base64 编码(首先对orignal使用HMAC-SHA1算法进行签名,然后将orignal附加到签名结果的末尾,再进行Base64编码,得到最终的sign)。
/// <summary>
/// HMAC-SHA1加密算法
/// </summary>
/// <param name="secret_key">密钥</param>
/// <param name="orignalStr">源文</param>
/// <returns></returns>
public static string HmacSha1Sign(string secret_key, string orignalStr)
{
var hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(secret_key));
var orignalBytes = Encoding.UTF8.GetBytes(orignalStr);
var hashBytes = hmacsha1.ComputeHash(orignalBytes);
List<byte> bytes = new List<byte>();
bytes.AddRange(hashBytes);
bytes.AddRange(orignalBytes);
return Convert.ToBase64String(bytes.ToArray());
}
2、一些其他需要注意的
1、文中使用的appid、bucket、secret_id、secret_key需要注册万象优图后,才能得到。至于如何得到,文档中说的很清楚,有详细的步骤。
2、在设置Header参数时,Content_Length和Host可以不用设置。
五、最后
希望你在调用腾讯云-OCR通用印刷体识别Api的时候可以少走些弯路,少踩一些坑。当然了这些可能算不上坑,可能是个人一些基础知识没掌握。不管怎么样,如果你在使用OCR的时候,本文对你有一点帮助,那它就发挥了应有的作用。
本文的源代码有兴趣的可以下载。
谈谈调用腾讯云【OCR-通用印刷体识别】Api踩的坑的更多相关文章
- 关于python 使用腾讯云OCR 通用印刷体识别
腾讯的python SDK没有通用印刷体识别,所以参考了别人识别网上图片的方式:https://www.cnblogs.com/semishigure/p/7690789.html 但是咱们使用的基本 ...
- 腾讯云OCR图片文字识别
一. OCR OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别 ...
- 腾讯云OCR服务二次开发
本文记录了对腾讯云OCR服务二次开发的代码和开发过程中遇到的问题.
- 云+社区分享——腾讯云OCR文字识别
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云+社区运营团队发布在腾讯云+社区 前言 2018年3月27日腾讯云云+社区联合腾讯云智能图像团队共同在客户群举办了腾讯云OCR文字识 ...
- .NET调用腾讯云API实例
最近项目有用到腾讯云的身份识别接口,话不多说,直接上代码: private void IDCardVerification(HttpContext context) { string imgStr = ...
- C# 调用腾讯云接口获取视频基本信息
做项目需要上传视频,获取时长,上传教程很多,获取信息很少,官方只有一条请求地址. 找了好久,都没有说这个请求地址怎么用.最后发现需要调用腾讯云SDK 官方地址:https://github.com/Q ...
- python调用腾讯云短信接口
目录 python调用腾讯云短信接口 账号注册 python中封装腾讯云短信接口 python调用腾讯云短信接口 账号注册 去腾讯云官网注册一个腾讯云账号,通过实名认证 然后开通短信服务,创建短信应用 ...
- Python调用腾讯云API,实现人脸年龄变化
网上看到了一个教程,调用腾讯云的人脸识别api和修改年龄api来实现模拟人物不同年龄的面貌 但是大多数教程的代码都是想同的,估计是抄袭哪个人的关键是执行不了 刚好周杰伦马上要发新专辑了,小改一下,拿杰 ...
- 每天响应数亿次请求,腾讯云如何提供高可用API服务?
每天响应数亿次请求,腾讯云如何提供高可用API服务? https://mp.weixin.qq.com/s/OPwlHcqkaTT_gcwHfr5Shw 李阳 云加社区 2020-09-16 导语 | ...
随机推荐
- 关于双11过后MATLAB许可过期问题的解决方案
在距离双11还有2个月之前,matlab会提示:Your MATLAB license will expire in 50 days --------------------------------- ...
- JMeter基础教程3:脚本录制篇
对于一些JMeter初学者来说,录制脚本可能是最容易掌握的技能之一.虽然我不建议录制性能脚本(因为录制的脚本比较混乱,必须要通过二次处理才可正常使用),但有时做总比不做要好,是吧?下面我们详细介绍使用 ...
- CSS3属性——“box-flex”
CSS3的新增属性有很多,其中有一个比较神奇的,通常称为盒子模型布局,不需要把div浮动,也能合理分配.看如下例子: HTML: <div id="box"> < ...
- JS--我发现,原来你是这样的JS:面向对象编程OOP[2]--(创建你的那个对象吧)
一.介绍 我们继续面向对象吧,这次是面向对象编程的第二篇,主要是讲创建对象的模式,希望大家能从博客中学到东西. 时间过得很快,还是不断的学习吧,为了自己的目标. 二.创建对象 1.前面的创建对象方式 ...
- alex python of day2
模块 sys模块:sys模块是用c语言写的,所以在lib下是不会有sys.py这个文件存在 1 import sys 2 print(sys.path) #打印环境变量 3 print(sys.a ...
- Python 函数返回值
本章详细介绍 返回值: 0x 00 返回值简介 0x 01 指定返回值与隐含返回值 0x 02 return 语句位置与多条 return 语句 0x 03 返回值类型 0x 04 函数嵌套 0x 0 ...
- 拼写纠错的利器,BK树算法
BK树或者称为Burkhard-Keller树,是一种基于树的数据结构,被设计于快速查找近似字符串匹配,比方说拼写纠错,或模糊查找,当搜索”aeek”时能返回”seek”和”peek”. 本文首先剖析 ...
- [react] 细数 React 的原罪
Props & onChange 的原罪 .「props & onChange 接口规范」它不是一个典型的「程序接口规范」. 当你拿到一个可视组件的 ref,却没有类似 setProp ...
- eclipse中 web项目缺少tomcatl lib的解决办法
1.最近在搭建的项目中,将项目导入eclipse中突然报好多错误,查看后全是丢失tomcat的lib包的错误,莫名其妙的错误. 代码中缺少的也是这样的问题 很明显,我之前的包丢了,莫名其妙的丢了. 解 ...
- (12.05)Java小知识!
今天与大家分享关于抽象类的知识点. 抽象类: 抽象类应用场景:在某种情况下,某个父类只是知道子类应该包含怎样的方法,但无法准确的知道这些子类如何实现这些方法. 从多一个具有相同特征的类中抽象出一个抽 ...