本文从实际项目出发,讲清 OCR 文字识别的核心原理、常见方案,以及如何通过 API 在 10 分钟内完成系统接入。
在很多业务系统中,OCR(光学字符识别)已经是一个高频能力,比如:
- 📄 文档数字化
- 🧾 发票识别
- 🪪 身份证识别
- 📷 图片转文字
- 🤖 RPA 自动录入
但很多团队在真正落地时会发现:OCR 看起来简单,工程化很复杂。
这篇文章带你一次讲透。
一、OCR 是怎么工作的?(通俗但工程视角)
一个完整的 OCR 流程通常包含 4 个阶段:
图像输入 → 文本检测 → 文本识别 → 结果结构化
我们逐个拆开看。
1️⃣ 图像预处理
目标:让文字“更容易被机器看清”。
常见操作包括:
- 灰度化
- 二值化
- 去噪
- 倾斜校正
- 对比度增强
👉 这一步直接影响最终识别率。
2️⃣ 文本检测(Text Detection)
这一阶段解决的问题是:
哪里有文字?
算法会在图片中定位出文本区域(bounding box)。
常见难点:
- 多行文本
- 弯曲文本
- 小字体
- 复杂背景
3️⃣ 文本识别(Text Recognition)
这一阶段才是:
文字具体是什么?
通常基于深度学习序列模型完成。
难点包括:
- 多语言
- 手写体
- 模糊图片
- 低分辨率
4️⃣ 结果结构化(工程中非常重要)
真实业务往往不仅要“识别文字”,还要:
- 按行返回
- 按字段返回
- 转成 JSON
- 做字段映射
👉 这是很多 demo 和生产系统的分水岭。
二、自己做 OCR vs 直接接 API?
很多团队一开始都会纠结这个问题,我给一个非常现实的对比。
🧠 自研 OCR 的成本
如果完全自研,你通常需要:
- 模型训练
- 数据集
- 推理服务
- GPU 资源
- 持续优化
保守周期:2–6 个月起
而且还不包含:
- 版面适配
- 多语言
- 稳定性
- 并发能力
🚀 API 方案的优势
大多数业务场景,更推荐直接接入成熟 OCR API,因为可以:
- 快速上线
- 降低算法成本
- 支持多语言
- 易于扩展
👉 这也是现在绝大多数 SaaS / 工具站的选择。
三、OCR API 标准接入流程(实战)
下面给出一个通用接入流程,基本所有 OCR 平台都适用。
Step 1:准备图片输入
常见两种方式:
方式 A:上传文件
<input type="file" />
方式 B:传图片 URL
适合服务端批处理场景。
Step 2:调用 OCR API
如果你正在做系统集成,建议优先看完整接口文档(通常包含多语言示例),可以少踩很多坑。
👉 接口文档: market.shiliuai.com/doc/advance…
下面是调用示例
Python 示例
# -*- coding: utf-8 -*-
import requests
import base64
import json
# 请求接口
URL = "https://ocr-api.shiliuai.com/api/advanced_general_ocr/v1"
# 图片/pdf文件转base64
def get_base64(file_path):
with open(file_path, "rb") as f:
data = f.read()
return base64.b64encode(data).decode("utf8")
def demo(appcode, file_path):
# 请求头
headers = {
"Authorization": "APPCODE %s" % appcode,
"Content-Type": "application/json"
}
# 请求体
b64 = get_base64(file_path)
data = {"file_base64": b64}
# 请求
response = requests.post(url=URL, headers=headers, json=data)
content = json.loads(response.content)
print(content)
if __name__ == "__main__":
appcode = "你的APPCODE"
file_path = "本地文件路径"
demo(appcode, file_path)
java 示例
//main.java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Base64;
public class Main {
public static String get_base64(String path) {
String b64 = "";
try {
// 使用Commons IO简化文件读取
byte[] content = FileUtils.readFileToByteArray(new File(path));
// 使用JDK自带的Base64
b64 = Base64.getEncoder().encodeToString(content);
} catch (IOException e) {
e.printStackTrace();
}
return b64;
}
public static void main(String[] args) {
String url = "https://ocr-api.shiliuai.com/api/advanced_general_ocr/v1";// 请求接口
String appcode = "你的APPCODE";
String imgFile = "本地文件路径";
Map headers = new HashMap<>();
headers.put("Authorization", "APPCODE " + appcode);
headers.put("Content-Type", "application/json");
// 请求体
JSONObject requestObj = new JSONObject();
requestObj.put("file_base64", get_base64(imgFile));
String bodys = requestObj.toString();
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 创建POST请求
HttpPost httpPost = new HttpPost(url);
// 设置请求头
for (Map.Entry entry : headers.entrySet()) {
httpPost.addHeader(entry.getKey(), entry.getValue());
}
// 设置请求体
StringEntity entity = new StringEntity(bodys, "UTF-8");
httpPost.setEntity(entity);
// 执行请求
HttpResponse response = httpClient.execute(httpPost);
int stat = response.getStatusLine().getStatusCode();
if (stat != 200) {
System.out.println("Http code: " + stat);
return;
}
String res = EntityUtils.toString(response.getEntity());
JSONObject res_obj = JSON.parseObject(res);
System.out.println(res_obj.toJSONString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
php 示例
// 图片/pdf转base64
function get_base64($path){
if($fp = fopen($path, "rb", 0)) {
$binary = fread($fp, filesize($path));// 文件读取
fclose($fp);
$b64 = base64_encode($binary);// 转base64
}else{
$b64="";
printf("%s 文件不存在", $path);
}
return $b64;
}
$url = "https://ocr-api.shiliuai.com/api/advanced_general_ocr/v1";
$appcode = "你的appcode";
$img_path = "图片路径";
$method = "POST";
//请求头
$headers = array();
array_push($headers, "Authorization:APPCODE " . $appcode);
array_push($headers, "Content-Type:application/json");
//请求体
$b64 = get_base64($img_path);
$data = array(
"file_base64" => $b64
);
$post_data = json_encode($data);
// 请求
$curl = curl_init();
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_FAILONERROR, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
$result = curl_exec($curl);
var_dump($result);
c# 示例
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MyCSharpApp
{
public class Program
{
public static string GetBase64(string path)
{
string b64 = "";
try
{
// 读取文件内容
byte[] content = File.ReadAllBytes(path);
// 转换为Base64
b64 = Convert.ToBase64String(content);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return b64;
}
public static async Task Main(string[] args)
{
string url = "https://ocr-api.shiliuai.com/api/advanced_general_ocr/v1";// 请求接口
string appcode = "你的APPCODE";
string imgFile = "本地文件路径";
// 设置请求头
Dictionary headers = new Dictionary
{
{ "Authorization", "APPCODE " + appcode }
// Content-Type 将在创建 StringContent 时设置
};
// 请求体
JObject requestObj = new JObject();
requestObj["file_base64"] = GetBase64(imgFile);
string body = requestObj.ToString();
try
{
using (HttpClient client = new HttpClient())
{
// 设置请求头
foreach (var header in headers)
{
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
// 创建请求内容
StringContent content = new StringContent(body, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"Http code: {(int)response.StatusCode}");
return;
}
// 读取响应内容
string responseContent = await response.Content.ReadAsStringAsync();
JObject resObj = JObject.Parse(responseContent);
Console.WriteLine(resObj.ToString(Formatting.Indented));
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
更多示例
如易语言API接入示例、天诺API接入示例、懒人精灵API接入示例、按键精灵API接入示例等等可以查看代码接入API说明:market.shiliuai.com/doc/advance…
四、返回结果该怎么处理?
一个典型 OCR 返回通常包含:
- 原始文本
- 行级结果
- 坐标信息
- 置信度
前端常见展示方式:
// 渲染识别文本
result.lines.forEach(line => {
console.log(line.text)
})
⭐ 实战建议
如果你的业务是结构化场景(如发票 / 身份证),建议:
- 优先用结构化 OCR
- 不要自己再做正则解析
- 能省大量维护成本
五、真实项目中最常见的坑
这些是我见过团队踩得最多的。
❗ 坑 1:直接拿手机原图就识别
问题:
- 图片过大
- 倾斜
- 光照不均
建议至少做:
- 尺寸压缩
- 基础预处理
识别率会明显提升。
❗ 坑 2:忽略并发与限流
OCR 属于计算密集型服务。
上线前一定要考虑:
- QPS 限制
- 重试机制
- 超时处理
否则高峰期很容易失败。
❗ 坑 3:只测清晰样本
很多 demo 成功率很高,但线上翻车,因为真实用户会上传:
- 模糊图
- 截图
- 压缩图
- 夜拍
👉 一定要用“脏数据”压测。
六、什么时候用在线 OCR,什么时候用 API?
一个简单判断:
✅ 适合在线工具
- 临时识别
- 人工使用
- 少量图片
- 快速验证效果
如果你只是想快速测试一张图片,可以先在线跑一遍看看识别效果。
👉 在线体验: market.shiliuai.com/general-ocr
✅ 适合 API 接入
- 系统自动化
- 批量处理
- 嵌入业务流程
- RPA / SaaS
七、写在最后
OCR 的技术门槛其实不低,但业务接入门槛已经被 API 极大降低了。
真正影响项目成败的,往往不是模型本身,而是:
- 是否稳定
- 是否易接入
- 是否支持结构化
- 是否能扛并发
如果你正在做:
- 文档处理系统
- 自动录入平台
- AI 工具站
- RPA 项目
OCR 基本是一个值得尽早接入的基础能力。