本文目录导读:

- 方案一:使用第三方OCR API(推荐)
- 方案二:使用Tesseract OCR(开源免费)
- 方案三:基于OpenCV的图像预处理+自定义模板
- 方案四:基于规则的简易提取(适合特定格式)
- 推荐方案选择
- 完整项目示例:基于百度OCR的发票识别系统
在PHP项目中实现票据识别(OCR)并提取关键字段,通常有几种方案,以下是几种主流实现方式及代码示例:
使用第三方OCR API(推荐)
百度AI OCR(国内常用)
<?php
// 使用百度AI OCR接口识别发票
require_once 'vendor/autoload.php';
use Baidu\Aip\Ocr;
// 配置API Key
$client = new AipOcr('APP_ID', 'API_KEY', 'SECRET_KEY');
// 读取图片文件
$image = file_get_contents('invoice.jpg');
// 调用增值税发票识别接口
$result = $client->vatInvoice($image);
// 提取关键字段
if (isset($result['words_result'])) {
$data = [
'invoice_code' => $result['words_result']['InvoiceCode'] ?? '',
'invoice_number' => $result['words_result']['InvoiceNumber'] ?? '',
'invoice_date' => $result['words_result']['InvoiceDate'] ?? '',
'total_amount' => $result['words_result']['TotalAmount'] ?? '',
'seller_name' => $result['words_result']['SellerName'] ?? '',
'buyer_name' => $result['words_result']['BuyerName'] ?? '',
];
print_r($data);
}
阿里云OCR
<?php
// 阿里云OCR识别
require_once 'vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
// 配置阿里云凭证
AlibabaCloud::accessKeyClient('ACCESS_KEY_ID', 'ACCESS_KEY_SECRET')
->regionId('cn-hangzhou')
->asDefaultClient();
try {
$result = AlibabaCloud::rpc()
->product('ocr')
->version('2019-12-30')
->action('RecognizeVATInvoice')
->method('POST')
->options([
'query' => [
'ImageURL' => 'https://example.com/invoice.jpg',
],
])
->request();
$data = $result->toArray();
if (isset($data['Data'])) {
$invoice = [
'invoice_code' => $data['Data']['InvoiceCode'] ?? '',
'invoice_number' => $data['Data']['InvoiceNumber'] ?? '',
'invoice_date' => $data['Data']['InvoiceDate'] ?? '',
'total_amount' => $data['Data']['TotalAmount'] ?? '',
'seller' => $data['Data']['SellerName'] ?? '',
];
print_r($invoice);
}
} catch (ClientException $e) {
echo $e->getErrorMessage();
}
使用Tesseract OCR(开源免费)
安装准备
# 安装Tesseract sudo apt-get install tesseract-ocr tesseract-ocr-chi-sim # 使用Composer安装PHP-Tesseract composer require thiagoalessio/tesseract_ocr
代码实现
<?php
use thiagoalessio\TesseractOCR\TesseractOCR;
class InvoiceOCR {
public function extractFields($imagePath) {
// 执行OCR识别
$text = (new TesseractOCR($imagePath))
->lang('chi_sim+eng') // 中文+英文
->psm(6) // 页面分割模式
->run();
// 解析提取关键字段
return $this->parseInvoiceText($text);
}
private function parseInvoiceText($text) {
$data = [];
// 发票号码模式匹配
if (preg_match('/发票号码[::]\s*(\d{8})/', $text, $matches)) {
$data['invoice_number'] = $matches[1];
}
// 发票代码
if (preg_match('/发票代码[::]\s*(\d{12})/', $text, $matches)) {
$data['invoice_code'] = $matches[1];
}
// 金额
if (preg_match('/价税合计[((][大写][))][::]\s*([\d\.]+)/', $text, $matches)) {
$data['total_amount'] = $matches[1];
}
// 购买方名称
if (preg_match('/购买方[名称]?[::]\s*(.+?)\n/', $text, $matches)) {
$data['buyer_name'] = trim($matches[1]);
}
// 销售方名称
if (preg_match('/销售方[名称]?[::]\s*(.+?)\n/', $text, $matches)) {
$data['seller_name'] = trim($matches[1]);
}
// 日期
if (preg_match('/(\d{4})年(\d{2})月(\d{2})日/', $text, $matches)) {
$data['invoice_date'] = "{$matches[1]}-{$matches[2]}-{$matches[3]}";
}
return $data;
}
}
// 使用示例
$ocr = new InvoiceOCR();
$result = $ocr->extractFields('invoice.jpg');
print_r($result);
基于OpenCV的图像预处理+自定义模板
安装OpenCV for PHP
composer require php-opencv/php-opencv
自定义模板匹配实现
<?php
class CustomInvoiceOCR {
private $templateData;
public function __construct() {
// 定义发票模板位置数据
$this->templateData = [
'invoice_code' => ['x' => 100, 'y' => 50, 'w' => 200, 'h' => 30],
'invoice_number' => ['x' => 350, 'y' => 50, 'w' => 200, 'h' => 30],
'total_amount' => ['x' => 400, 'y' => 600, 'w' => 150, 'h' => 30],
'seller_name' => ['x' => 150, 'y' => 400, 'w' => 300, 'h' => 30],
];
}
public function extractByTemplate($imagePath) {
// 图像预处理
$image = $this->preprocessImage($imagePath);
$result = [];
foreach ($this->templateData as $field => $region) {
// 裁剪特定区域
$cropped = $this->cropRegion($image, $region);
// OCR识别该区域
$text = $this->ocrRegion($cropped);
$result[$field] = $this->cleanText($text);
}
return $result;
}
private function preprocessImage($path) {
// 图像处理:灰度化、二值化、去噪等
// 使用GD库或Imagick
$image = imagecreatefromjpeg($path);
// 转为灰度
imagefilter($image, IMG_FILTER_GRAYSCALE);
// 增强对比度
imagefilter($image, IMG_FILTER_CONTRAST, -50);
return $image;
}
private function cropRegion($image, $region) {
// 裁剪指定区域
$cropped = imagecreatetruecolor($region['w'], $region['h']);
imagecopy($cropped, $image, 0, 0,
$region['x'], $region['y'],
$region['w'], $region['h']);
// 保存临时文件
$tempFile = tempnam(sys_get_temp_dir(), 'ocr_');
imagepng($cropped, $tempFile);
return $tempFile;
}
private function ocrRegion($imagePath) {
// 使用Tesseract识别
$text = (new TesseractOCR($imagePath))
->lang('chi_sim+eng')
->run();
unlink($imagePath); // 清理临时文件
return $text;
}
private function cleanText($text) {
return trim(preg_replace('/\s+/', '', $text));
}
}
基于规则的简易提取(适合特定格式)
<?php
class SimpleInvoiceParser {
public function parseFromText($text) {
$data = [
'invoice_code' => '',
'invoice_number' => '',
'total_amount' => '',
'date' => '',
'seller' => '',
'buyer' => ''
];
// 提取发票代码 (12位数字)
if (preg_match('/\b(\d{12})\b/', $text, $matches)) {
$data['invoice_code'] = $matches[1];
}
// 提取发票号码 (8位数字,通常在代码后面)
if (preg_match('/\d{12}\s*(\d{8})\b/', $text, $matches)) {
$data['invoice_number'] = $matches[1];
}
// 提取金额(价税合计)
preg_match_all('/价税合计[::]\s*¥?([\d,]+\.?\d*)/', $text, $matches);
if (!empty($matches[1])) {
$data['total_amount'] = $matches[1][0];
}
// 提取日期
preg_match('/(\d{4}[-年]\d{1,2}[-月]\d{1,2})/', $text, $matches);
if (!empty($matches[1])) {
$data['date'] = str_replace(['年', '月'], '-', $matches[1]);
}
return $data;
}
/**
* 批量处理多个发票
*/
public function batchProcess($texts) {
$results = [];
foreach ($texts as $text) {
$results[] = $this->parseFromText($text);
}
return $results;
}
}
推荐方案选择
| 方案 | 准确率 | 成本 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| 百度/Ali API | 95%+ | 按量付费 | 低 | 生产环境,高精度要求 |
| Tesseract | 70-85% | 免费 | 中 | 测试/低预算项目 |
| 自定义模板 | 90%+(固定模板) | 低 | 高 | 特定格式发票 |
| 规则提取 | 60-80% | 免费 | 低 | 纯文本处理 |
建议: 如果项目预算允许,推荐使用百度AI OCR API,准确率高且接口简单,如果处理量较小,可以先用免费方案测试效果。
完整项目示例:基于百度OCR的发票识别系统
<?php
class InvoiceRecognitionSystem {
private $ocrClient;
private $db;
public function __construct() {
$this->ocrClient = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
$this->db = new PDO('mysql:host=localhost;dbname=invoices', 'user', 'pass');
}
/**
* 自动识别并保存发票信息
*/
public function processInvoice($imagePath) {
try {
// 1. 图片预处理
$optimizedPath = $this->optimizeImage($imagePath);
// 2. OCR识别
$result = $this->recognize($optimizedPath);
// 3. 提取字段
$invoiceData = $this->extractFields($result);
// 4. 验证数据
if ($this->validateData($invoiceData)) {
// 5. 保存到数据库
$invoiceId = $this->saveToDatabase($invoiceData);
// 6. 生成报告
return $this->generateReport($invoiceId, $invoiceData);
}
return ['error' => '数据验证失败'];
} catch (Exception $e) {
return ['error' => $e->getMessage()];
}
}
private function optimizeImage($path) {
// 图像优化:调整大小、增强对比度等
return $path;
}
private function recognize($imagePath) {
$image = file_get_contents($imagePath);
return $this->ocrClient->vatInvoice($image);
}
private function extractFields($ocrResult) {
$fields = $ocrResult['words_result'] ?? [];
return [
'invoice_code' => $fields['InvoiceCode'] ?? '',
'invoice_number' => $fields['InvoiceNumber'] ?? '',
'invoice_date' => $fields['InvoiceDate'] ?? '',
'total_amount' => $fields['TotalAmount'] ?? '',
'tax_amount' => $fields['TaxAmount'] ?? '',
'seller_name' => $fields['SellerName'] ?? '',
'seller_tax_id' => $fields['SellerTaxID'] ?? '',
'buyer_name' => $fields['BuyerName'] ?? '',
'buyer_tax_id' => $fields['BuyerTaxID'] ?? '',
];
}
private function validateData($data) {
// 验证关键字段
return !empty($data['invoice_number']) &&
!empty($data['total_amount']) &&
!empty($data['invoice_date']);
}
private function saveToDatabase($data) {
$sql = "INSERT INTO invoices (invoice_code, invoice_number, invoice_date,
total_amount, tax_amount, seller_name, seller_tax_id,
buyer_name, buyer_tax_id, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())";
$stmt = $this->db->prepare($sql);
$stmt->execute([
$data['invoice_code'],
$data['invoice_number'],
$data['invoice_date'],
$data['total_amount'],
$data['tax_amount'],
$data['seller_name'],
$data['seller_tax_id'],
$data['buyer_name'],
$data['buyer_tax_id']
]);
return $this->db->lastInsertId();
}
private function generateReport($id, $data) {
return [
'id' => $id,
'status' => 'success',
'data' => $data,
'time' => date('Y-m-d H:i:s')
];
}
}
根据你的具体需求(预算、准确率要求、处理量等),选择合适的方案实现,如果需求复杂,建议结合多种方案使用。