PHP项目票据识别如何提取关键字段

wen PHP项目 26

本文目录导读:

PHP项目票据识别如何提取关键字段

  1. 方案一:使用第三方OCR API(推荐)
  2. 方案二:使用Tesseract OCR(开源免费)
  3. 方案三:基于OpenCV的图像预处理+自定义模板
  4. 方案四:基于规则的简易提取(适合特定格式)
  5. 推荐方案选择
  6. 完整项目示例:基于百度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')
        ];
    }
}

根据你的具体需求(预算、准确率要求、处理量等),选择合适的方案实现,如果需求复杂,建议结合多种方案使用。

抱歉,评论功能暂时关闭!