有没有HarmonyOS鸿蒙Next大佬做过ocr识别微信和支付宝账单

有没有HarmonyOS鸿蒙Next大佬做过ocr识别微信和支付宝账单 我怎么解析都不稳定,乱七八糟的。要么没时间,要么把汇总也识别出来了。

有没有大佬能能用的代码

11 回复

可以做,但不建议直接拿 OCR 的整段 value 去正则匹配账单。微信/支付宝账单截图属于“表格 + 多列 + 汇总文字”的场景,通用 OCR 只负责识别文字和坐标,不会自动告诉你哪一行是交易记录,所以要自己按坐标重建行,再过滤汇总区。

HarmonyOS 里可以先用 Core Vision Kit 的 textRecognition 识别,结果里有 blocks、lines、words 和 cornerPoints。核心思路:

  1. 先裁剪截图,只保留交易列表区域,去掉顶部标题、筛选栏、底部汇总。
  2. 调用 recognizeText,不要只用 result.value,优先遍历 result.blocks[].lines。
  3. 用 line.cornerPoints 算每行的 y 中心点,按 y 排序;y 接近的内容合并成同一行,再按 x 排序。
  4. 用规则过滤“合计、收入、支出、月账单、筛选、转账说明”等汇总/标题词。
  5. 金额和时间单独提取,金额建议匹配 +/-、¥、小数两位,时间建议匹配 HH:mm、MM-dd、yyyy-MM-dd。

示例骨架:

import textRecognition from '@hms.ai.ocr.textRecognition'

type OcrLine = {
 text: string
 x: number
 y: number
}

async function recognizeBill(pixelMap: image.PixelMap): Promise<string[]> {
 await textRecognition.init()
 try {
  const result = await textRecognition.recognizeText({ pixelMap }, {
   isDirectionDetectionSupported: true
  })
  const lines: OcrLine[] = []
  result.blocks.forEach(block => {
   block.lines.forEach(line => {
    const xs = line.cornerPoints.map(p => p.x)
    const ys = line.cornerPoints.map(p => p.y)
    lines.push({
     text: line.value.trim(),
     x: Math.min(...xs),
     y: ys.reduce((a, b) => a + b, 0) / ys.length
    })
   })
  })
  return lines
   .sort((a, b) => a.y === b.y ? a.x - b.x : a.y - b.y)
   .map(item => item.text)
   .filter(text => text.length > 0)
   .filter(text => !/(合计|汇总|月账单|筛选|收入|支出)/.test(text))
   .filter(text => /(d{1,2}:d{2}|d{4}-d{1,2}-d{1,2}|[+-]?¥?d+.d{2})/.test(text))
 } finally {
  await textRecognition.release()
 }
}

如果你现在的问题是“时间丢了、汇总也被识别进来”,重点不是换 OCR,而是做截图预处理和行级解析:先裁剪交易列表,再按坐标聚类成行,最后用关键词和金额/时间规则过滤。这样会比直接解析整段 OCR 文本稳定很多。

更多关于有没有HarmonyOS鸿蒙Next大佬做过ocr识别微信和支付宝账单的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


裁剪了顶部的25%,效果不错

这个我非常理解,之前体验发票抽奖,也是经常会识别错误,感觉是因为OCR识别微信/支付宝账单/发片这些 确实容易遇到格式混乱、汇总信息干扰、识别不全等问题。主要还是因为账单排版复杂,包含表格、数字、中文混排,且不同版本样式有差异。

建议看能不能这样:

  1. 只识别关键区域:通过裁剪图片,只保留账单明细区域。
  2. 后处理过滤:识别后,用正则只提取“交易时间、金额、对方账户”等关键字段,丢弃无关行。

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

开发者您好,OCR(光学字符识别)是通用技术,可通过集成第三方OCR服务或使用鸿蒙相关的AI能力实现。建议:

  1. 参考Core Vision Kit中的文字识别能力:通用文字识别(点击查看),然后分析文字,提取数据;
  2. 考虑使用第三方收费OCR服务。

如果是识别微信、支付宝账单这种场景,其实不建议自己硬调 OCR 规则,鸿蒙这边可以直接考虑用 Core Vision Kit 的文字识别能力。它本身就是针对图片文字提取的能力,支持 OCR 识别,可以从图片中提取文本内容。

不过要注意,OCR 只能解决“看懂图片文字”,不能直接解决“理解账单结构”。

比如微信账单截图:

昨天
星巴克
-35.00

今天
滴滴出行
-28.50

本月支出
xxxx

OCR 可能会全部识别出来,但是它不知道:

  • 哪个是交易时间
  • 哪个是商户
  • 哪个是金额
  • 哪个是汇总信息

所以后面还是需要自己做一层数据解析。

比较推荐流程:

截图 → Core Vision文字识别 → 获取文字块坐标 → 按位置排序 → 正则提取金额/日期 → 过滤汇总区域 → 生成账单数据

Core Vision 的文字识别结果会带文本信息,结合位置关系处理会比直接拿字符串靠谱。

例如:

金额:

¥xx.xx

时间:

2026-xx-xx

交易类型:

支付
退款
收入

这些自己做规则匹配。

另外有个经验:

不要识别微信/支付宝首页账单统计页,因为里面大量都是:

  • 本月消费
  • 总收入
  • 支出排名

这些一定会混进去。

最好进入:

交易明细列表 → 截图 → OCR

效果会好很多。

如果追求稳定:

微信/支付宝账单导出文件 > OCR > 截图识别

OCR 更适合做辅助录入,不适合作为唯一账单解析方案。

Core Vision 可以作为鸿蒙侧 OCR 基础能力,但业务上的“账单结构化”还是需要自己处理。

希望能帮到你~~~

这个方法也行,至少基本能识别

https://gitcode.com/HarmonyOS_Samples/core-vision-kit-sample-code-ark-ts-ocr-demo

官方demo看满不满足你的需要:

实现通用文字识别

介绍

本示例展示了使用基础视觉服务提供的通用文字识别能力。

本示例模拟了在应用里,选择一张图片,识别其文字信息并展示出来(可复制)。

需要使用通用文字识别接口@hms.ai.ocr.textRecognition.d.ts。

使用说明:

  1. 在手机的主屏幕,点击”ocrDemo“,启动应用。
  2. 点击“Select image”按钮,在图库中选择图片,或者通过相机拍照。
  3. 点击“Start recognition”按钮,识别图本信息,文本展示并可复制。

工程目录

├─entry/src/main/ets
│  ├─entryability
│  │  └─EntryAbility.ets            // 程序入口
│  └─pages
│     └─Index.ets                   // 应用主界面
└─entry/src/main/resources          // 资源文件目录

具体实现

本示例展示的控件在@hms.ai.ocr.textRecognition.d.ts定义了文字识别API:

* recognizeText(visionInfo: VisionInfo, callback: AsyncCallback<TextRecognitionResult>): void

业务使用时,需要先进行import导入textRecognition。 调用通用文字识别接口,并传入想要识别的图片,接收处理返回的结果(文字信息)。参考entry/src/main/ets/pages/Index.ets.

cke_1054.png

通用文字识别,是通过拍照、扫描等光学输入方式,将各种票据、卡证、表格、报刊、书籍等印刷品文字转化为图像信息,再利用文字识别技术将图像信息转化为计算机等设备可以使用的字符信息的技术。

  • 可以对文档翻拍、街景翻拍等图片进行文字检测和识别,也可以集成于其他应用中,提供文字检测、识别的功能,并根据识别结果提供翻译、搜索等相关服务。
  • 可以处理来自相机、图库等多种来源的图像数据,提供一个自动检测文本、识别图像中文本位置以及文本内容功能的开放能力。
  • 支持特定角度范围内的文本倾斜、拍摄角度倾斜、复杂光照条件以及复杂文本背景等场景的文字识别。

效果如下图所示:

cke_230.png

代码:

import { textRecognition } from '@kit.CoreVisionKit';
import { image } from '@kit.ImageKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
@Entry
@Component
struct Index {
  private imageSource: image.ImageSource | undefined = undefined;
  @State chooseImage: PixelMap | undefined = undefined;
  @State dataValues: string = '';
  async aboutToAppear(): Promise<void> {
    const initResult = await textRecognition.init();
    hilog.info(0x0000, 'OCRDemo', `OCR service initialization result:${initResult}`);
  }
  async aboutToDisappear(): Promise<void> {
    await textRecognition.release();
    hilog.info(0x0000, 'OCRDemo', 'OCR service released successfully');
  }
  build() {
    Column() {
      Image(this.chooseImage)
        .objectFit(ImageFit.Fill)
        .height('60%')
      Text(this.dataValues)
        .copyOption(CopyOptions.LocalDevice)
        .height('15%')
        .margin(10)
        .width('60%')
      Button('选择图片')
        .type(ButtonType.Capsule)
        .fontColor(Color.White)
        .alignSelf(ItemAlign.Center)
        .width('80%')
        .margin(10)
        .onClick(() => {
          // 拉起图库,获取图片资源
          void this.selectImage();
        })
      Button('开始识别')
        .type(ButtonType.Capsule)
        .fontColor(Color.White)
        .alignSelf(ItemAlign.Center)
        .width('80%')
        .margin(10)
        .onClick(() => {
          this.textRecognitionTest();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
  private textRecognitionTest() {
    if (!this.chooseImage) {
      return;
    }
    // 调用文本识别接口
    let visionInfo: textRecognition.VisionInfo = {
      pixelMap: this.chooseImage
    };
    let textConfiguration: textRecognition.TextRecognitionConfiguration = {
      isDirectionDetectionSupported: false
    };
    textRecognition.recognizeText(visionInfo, textConfiguration)
      .then((data: textRecognition.TextRecognitionResult) => {
        // 识别成功,获取对应的结果
        let recognitionString = JSON.stringify(data);
        hilog.info(0x0000, 'OCRDemo', `Succeeded in recognizing text: ${recognitionString}`);
        // 将结果更新到Text中显示
        this.dataValues = data.value;
      })
      .catch((error: BusinessError) => {
        hilog.error(0x0000, 'OCRDemo', `Failed to recognize text. Code: ${error.code}, message: ${error.message}`);
        this.dataValues = `Error: ${error.message}`;
      });
  }
  private async selectImage() {
    let uri = await this.openPhoto();
    if (uri === undefined) {
      hilog.error(0x0000, 'OCRDemo', 'Failed to get uri.');
      return;
    }
    this.loadImage(uri);
  }
  private async openPhoto(): Promise<string> {
    return new Promise<string>((resolve) => {
      let photoPicker: photoAccessHelper.PhotoViewPicker = new photoAccessHelper.PhotoViewPicker();
      photoPicker.select({
        MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
        maxSelectNumber: 1
      }).then((res: photoAccessHelper.PhotoSelectResult) => {
        resolve(res.photoUris[0]);
      }).catch((err: BusinessError) => {
        hilog.error(0x0000, 'OCRDemo', `Failed to get photo image uri. code: ${err.code}, message: ${err.message}`);
        resolve('');
      });
    });
  }
  private loadImage(name: string) {
    setTimeout(async () => {
      let fileSource = await fileIo.open(name, fileIo.OpenMode.READ_ONLY);
      this.imageSource = image.createImageSource(fileSource.fd);
      this.chooseImage = await this.imageSource.createPixelMap();
      await fileIo.close(fileSource);
    }, 100);
  }
}

鸿蒙Next可使用ML Kit文本识别或集成第三方OCR SDK(如百度、腾讯)识别账单截图,再通过正则或布局解析提取微信/支付宝账单字段。注意权限申请和文本预处理,账单背景干扰需做图像增强。

微信/支付宝账单OCR解析不稳定的核心在于结构化过滤,而非识别本身。给你一个可用的后处理思路:

// 假设text是OCR识别的原始文本(按行存储)
function extractTransactions(text: string[]): Transaction[] {
  const result: Transaction[] = [];
  let current: Partial<Transaction> = {};

  const dateRegex = /^\d{4}[-/.]\d{1,2}[-/.]\d{1,2}/;
  const amountRegex = /[+-]?\d+(\.\d{2})?/;
  const ignoreKeywords = ['汇总', '合计', '收入', '支出', '余额', '交易总数'];

  for (const line of text) {
    const trimmed = line.trim();
    if (!trimmed) continue;

    // 跳过汇总行
    if (ignoreKeywords.some(k => trimmed.includes(k))) {
      if (current.date && current.amount) {
        result.push(current as Transaction);
        current = {};
      }
      continue;
    }

    // 识别时间戳作为新交易开始
    if (dateRegex.test(trimmed)) {
      // 保存上一条未完成的记录
      if (current.date && current.amount) {
        result.push(current as Transaction);
      }
      current = { date: trimmed.match(dateRegex)![0] };
      continue;
    }

    // 金额行
    if (amountRegex.test(trimmed) && trimmed.replace(/[^\d.-]/g, '').length >= 3) {
      const amount = parseFloat(trimmed.match(amountRegex)![0]);
      if (current.date && current.amount === undefined) {
        current.amount = amount;
      } else if (current.date) {
        // 替换更精确的金额(有些账单金额与时间同行)
        current.amount = amount;
      }
    }

    // 标题/商户名(非数字、非日期、非汇总)
    if (!dateRegex.test(trimmed) && !amountRegex.test(trimmed) && trimmed.length > 2) {
      if (current.date && !current.title) {
        current.title = trimmed;
      }
    }
  }

  // 处理最后一条
  if (current.date && current.amount) {
    result.push(current as Transaction);
  }

  return result;
}

关键点

  • 日期作为交易记录的分隔标志
  • 汇总/合计等关键词作为强制截断点
  • 金额识别后验证小数位,避免把时间中的数字当金额
  • 如果账单是PDF截图,建议按区域裁剪(微信账单顶部标题区、底部汇总区可直接裁剪掉)后再进行OCR,能大幅提升稳定性

配合@hms.collaborative.mlkitTextRecognition接口即可。

回到顶部