HarmonyOS 7 端侧 AI 视觉能力实战 05:给截图建立自动分类能力

前面几篇把 OCR、超分、文搜图、人脸检测都单独讲了一遍。这篇开始把它们串起来,做一个实际的功能:截图自动分类。
我们的智能截图整理工具的核心需求就是:用户截了一堆图,App 自动帮你分类——哪些是聊天记录、哪些是文档、哪些是截图、哪些是人脸照片。分好类之后用户找起来方便,也不用自己手动整理。
这个功能的难点不在于调单个 API,而在于怎么把多个视觉能力组合起来,做一套分类规则,并且分类结果要稳定、准确。
一、真实开发中遇到的问题
最开始想的是:一张截图进来,OCR 提取文字,然后根据文字内容分类。简单粗暴。
实际试了一下发现不行:
第一,纯文字分类不够准。一张微信聊天截图和一张文档截图,文字都是中文,怎么区分?光靠文字内容分不出来。
第二,有些截图文字很少。比如一张纯风景截图,OCR 提取不出几个字,怎么分类?
第三,分类标准不清晰。什么叫"聊天记录"?什么叫"文档"?边界在哪里?
第四,用户量一大,处理速度跟不上。用户一次导入 50 张截图,每张都要 OCR + 人脸检测 + 关键词分析,串行处理要等好久。
二、这个能力怎么接入
我们最后用了多特征组合的分类思路,一张截图同时跑三个检测:
1. OCR 文字提取:提取截图里的所有文字。
2. 人脸检测:判断截图里有没有人脸。
3. 图像分类:用多模态模型判断这张图是什么类型(照片/截图/文档)。
然后根据三个结果组合出最终分类:
有文字 + 没人脸 + 文字密度高 → 文档类
有文字 + 有聊天界面特征(时间戳、头像、气泡)→ 聊天记录类
有人脸 → 人像类
没文字 + 色彩丰富 → 图片类
这样比单靠 OCR 分类准多了。

三、关键代码怎么写
下面是封装的截图分类器,文件位置在 entry/src/main/ets/utils/ScreenshotClassifier.ets:
import { image } from '@kit.CoreImageKit';
import { OcrUtil } from './OcrUtil';
import { FaceDetectUtil } from './FaceDetectUtil';
export class ScreenshotClassifier {
// 分类主入口
static async classify(
pixelMap: image.PixelMap
): Promise<ScreenshotCategory> {
// 1. OCR 提取文字
const ocrResult = await OcrUtil.extractTextFromImage(pixelMap);
const text = ocrResult.text;
// 2. 人脸检测
const hasFace = await FaceDetectUtil.hasFace(pixelMap);
// 3. 关键词分析
const keywords = this.extractKeywords(text);
// 4. 综合判断分类
return this.decideCategory(text, hasFace, keywords);
}
// 提取关键词
private static extractKeywords(text: string): string[] {
if (!text) return [];
// 简单的关键词匹配
const keywordMap: Record<string, string> = {
'聊天记录': ['聊天', '微信', '消息', '发送'],
'文档': ['合同', '协议', '报告', '文档', 'PDF'],
'票据': ['发票', '报销', '金额', '元'],
'截图': ['截图', '屏幕', '系统', '设置']
};
const found: string[] = [];
for (const [category, words] of Object.entries(keywordMap)) {
for (const word of words) {
if (text.includes(word)) {
found.push(category);
break;
}
}
}
return found;
}
// 综合决策分类
private static decideCategory(
text: string,
hasFace: boolean,
keywords: string[]
): ScreenshotCategory {
// 优先按关键词分类
if (keywords.includes('票据')) return {
type: 'invoice',
label: '票据',
confidence: 0.85
};
if (keywords.includes('聊天记录')) return {
type: 'chat',
label: '聊天记录',
confidence: 0.8
};
// 有人脸 → 人像类
if (hasFace) return {
type: 'portrait',
label: '人像',
confidence: 0.75
};
// 文字多 → 文档类
if (text.length > 100) return {
type: 'document',
label: '文档',
confidence: 0.7
};
// 兜底:图片类
return {
type: 'image',
label: '图片',
confidence: 0.5
};
}
}
// 分类结果类型
interface ScreenshotCategory {
type: string;
label: string;
confidence: number;
}
这段代码的核心:classify 方法同时跑 OCR 和人脸检测,然后 extractKeywords 做关键词匹配,decideCategory 综合所有特征做最终分类。
批量处理的时候怎么提高速度?文件位置 pages/ScreenshotListPage.ets:
@Entry
@Component
struct ScreenshotListPage {
@State screenshots: ScreenshotItem[] = [];
@State isProcessing: boolean = false;
@State progress: number = 0;
// 批量导入截图并分类
async onImportScreenshots(images: image.PixelMap[]) {
this.isProcessing = true;
this.progress = 0;
const total = images.length;
const results: ScreenshotItem[] = [];
// 串行处理,避免内存压力
for (let i = 0; i < images.length; i++) {
const pixelMap = images[i];
// 执行分类
const category = await ScreenshotClassifier.classify(pixelMap);
results.push({
image: pixelMap,
category: category
});
this.progress = Math.round(((i + 1) / total) * 100);
// 释放内存
pixelMap.release();
}
this.screenshots = results;
this.isProcessing = false;
}
build() {
Column() {
if (this.isProcessing) {
// 进度条
Column() {
Text('正在分类... ' + this.progress + '%')
Progress({ value: this.progress, total: 100 })
}
} else {
// 按分类分组展示
List() {
ForEach(this.groupByCategory(), (group: CategoryGroup) => {
ListItem() {
Column() {
Text(group.label + ' (' + group.items.length + ')')
// 该分类下的截图列表
Grid() {
ForEach(group.items, (item: ScreenshotItem) => {
GridItem() {
Image(item.image)
.width(100).height(100)
}
})
}
.columnsTemplate('1fr 1fr 1fr')
}
}
})
}
}
}
}
}

四、运行过程中怎么处理异常
截图分类的异常场景:
1. OCR 失败:某张图识别失败了,text 为空。没关系,继续做人脸检测和图像分类,多特征组合就是为了兜底。
2. 分类置信度低:如果所有特征都不明显,confidence 低于 0.5,就归到"其他"类,不要硬分到某个类别里。
3. 批量处理中断:处理到一半用户退出去了,要保存已经处理的结果,下次进来继续,不要从头再来。
4. 内存压力:批量处理的时候,每张图的 PixelMap 用完就释放,不要一直持着。
五、实际开发中容易忽略的问题
1. 分类规则要可配置:关键词和分类规则不要写死在代码里,做成可配置的,后面调整规则不用改代码。
2. 分类结果要展示置信度:用户看到"文档类 70%",比只看到"文档类"更可信。置信度低的分类,UI 上可以标注一下。
3. 批量处理要限流:一次不要同时跑太多张,串行处理最稳。如果想并行,最多 2-3 个,再多就 OOM 了。
4. 分类结果要缓存:同一张截图不要每次都重新分类。分类结果存到本地数据库,下次直接读。
5. 用户可以手动修正:AI 分类总有不准的时候。UI 上要允许用户手动调整分类,并且把修正结果记下来,后面分类可以越来越准。
截图自动分类是前几篇能力的第一个综合应用。OCR、人脸检测、关键词分析,每个单独拿出来都不难,但组合起来做成一个稳定好用的功能,就要在工程细节上下功夫。下一篇会把整个处理链串起来,做一个完整的流水线。
更多推荐



所有评论(0)