RNOH x HarmonyOS OCR:商品包装 / 物流面单识别接入方案
本文是《React Native x HarmonyOS NEXT 创新能力接入方案:从 RNOH 到原生能力桥接》系列第 4 篇。上一篇我们完成了 TTS 语音合成,本篇继续把 HarmonyOS 的视觉识别能力接入 React Native 项目,实现“选择图片 → OCR 识别 → 结果回显到 RN 页面”的完整链路。
源码: https://atomgit.com/huqi/RNHarmonySkuAssistant
1. 本篇要实现什么?
本篇我们要做一个 React Native 调用 HarmonyOS OCR 文字识别能力 的接入方案 Demo。
业务场景不照搬 BabyOne 的“疫苗本 / 体检报告”,而是换成更适合工具类 App 和跨境电商场景的:
- 商品包装文字识别;
- 物流面单文字识别;
- 商品标签识别;
- 说明书文字提取;
- 发票 / 表单辅助录入。
最终效果:
React Native 页面
↓
选择本地图片
↓
调用 RNOH TurboModule
↓
ArkTS 原生模块调用 HarmonyOS OCR 能力
↓
识别结果返回 React Native
↓
页面展示识别文本
最终页面建议设计成:
RN Harmony SKU Assistant
OCR 商品包装识别
[选择图片]
图片预览区域
[开始识别]
识别结果:
Product Name: Stainless Steel Storage Rack
Material: 304 Stainless Steel
Size: 30 x 12 x 8 cm
Made in China
真机效果如下:




这次真机识别的图片是一张设备屏幕照片。Core Vision Kit 最终识别出 9 个文本块,并将结果回显到 RN 页面,日志显示耗时约 628ms。
2. 为什么 OCR 适合作为第一个视觉能力?
在 React Native 适配 HarmonyOS 的过程中,OCR 是非常适合做教程的能力,原因有三个:
第一,OCR 结果直观。用户选择一张图片后,页面能直接看到文字结果,截图很有说服力。
第二,OCR 业务场景广。无论是母婴、教育、办公、电商、物流,都会遇到“图片文字转结构化文本”的需求。
第三,OCR 可以很好地体现跨端框架接入原生能力的价值。React Native 负责业务界面和交互,HarmonyOS 原生侧负责调用系统 OCR 能力,二者通过 RNOH TurboModule 打通。
HarmonyOS / 华为 HMS 生态中,OCR 通常属于视觉识别能力范畴。公开文档中,华为文字识别能力支持将图像中的文字转换为可编辑文本,并提供 SDK 集成方式;这类能力非常适合封装成跨端可调用模块。
3. 本篇技术架构
本篇的完整调用链路如下:
OCRPage.tsx
↓
NativeOCRModule.recognizeText(imageUri)
↓
RNOH TurboModule
↓
OCRModule.ets
↓
HarmonyOS OCR / Vision Kit 能力
↓
Promise<OCRResult>
↓
React Native 页面渲染识别结果
可以拆成三层:
React Native 业务层
├── 图片选择
├── 图片预览
├── 识别按钮
├── Loading / Error / Empty 状态
└── 识别结果展示
RNOH 桥接层
├── NativeOCRModule.ts
├── TurboModuleRegistry
├── Codegen
└── Promise 结果回调
HarmonyOS 原生层
├── OCRModule.ets
├── 图片 URI 处理
├── OCR 能力调用
├── 权限处理
└── 结果格式化
4. 项目目录建议
本篇建议在上一节项目基础上继续扩展目录:
RNHarmonySkuAssistant
├── App.tsx
├── src
│ ├── pages
│ │ └── OCRPage.tsx
│ ├── native
│ │ └── NativeOCRModule.ts
│ └── types
│ └── ocr.ts
│
└── harmony
└── entry
└── src
└── main
└── ets
├── modules
│ └── OCRModule.ets
└── RNPackagesFactory.ets
说明:
OCRPage.tsx:React Native 侧页面;NativeOCRModule.ts:JS / TS 侧原生模块声明;ocr.ts:OCR 结果类型定义;OCRModule.ets:ArkTS 原生能力封装;RNPackagesFactory.ets:RNOH 原生模块注册。
5. 定义 OCR 返回数据结构
先在 RN 侧定义 OCR 结果类型。
新建:
src/types/ocr.ts
示例代码:
export interface OCRTextBlock {
text: string;
confidence?: number;
left?: number;
top?: number;
width?: number;
height?: number;
}
export interface OCRResult {
fullText: string;
blocks: OCRTextBlock[];
imageUri: string;
costTime?: number;
}
这里不要只返回一个字符串,建议保留 blocks。
原因是后面可以继续扩展:
- 按行展示识别结果;
- 高亮图片中的识别区域;
- 过滤低置信度文本;
- 对商品名称、规格、产地、条码做结构化提取。
6. React Native 侧声明 NativeOCRModule
新建:
src/native/NativeOCRModule.ts
示例代码:
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface OCRTextBlock {
text: string;
confidence?: number;
left?: number;
top?: number;
width?: number;
height?: number;
}
export interface OCRResult {
fullText: string;
blocks: OCRTextBlock[];
imageUri: string;
costTime?: number;
}
export interface Spec extends TurboModule {
recognizeText(imageUri: string): Promise<OCRResult>;
}
export default TurboModuleRegistry.get<Spec>('OCRModule') as Spec | null;
注意:
TurboModuleRegistry.get<Spec>('OCRModule')
这里的 'OCRModule' 要和 ArkTS 原生模块注册名称保持一致。
如果名称不一致,RN 页面调用时会出现模块为 null 或找不到方法的问题。
7. React Native 页面实现
新建:
src/pages/OCRPage.tsx
示例代码如下:
import React, { useState } from 'react';
import {
ActivityIndicator,
Alert,
Image,
Pressable,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
} from 'react-native';
import NativeOCRModule from '../native/NativeOCRModule';
import type { OCRResult } from '../types/ocr';
export default function OCRPage() {
const [imageUri, setImageUri] = useState<string>('');
const [loading, setLoading] = useState(false);
const [result, setResult] = useState<OCRResult | null>(null);
const handleChooseImage = async () => {
// 这里先用 mock 图片路径占位。
// 实际项目中建议在 HarmonyOS 原生侧封装图片选择能力,
// 或使用已经适配 OpenHarmony 的图片选择库。
const mockUri = 'file://demo/product_package.jpg';
setImageUri(mockUri);
setResult(null);
};
const handleRecognize = async () => {
if (!imageUri) {
Alert.alert('提示', '请先选择一张图片');
return;
}
if (!NativeOCRModule) {
Alert.alert('错误', 'OCRModule 未注册,请检查 RNOH 原生模块配置');
return;
}
try {
setLoading(true);
const data = await NativeOCRModule.recognizeText(imageUri);
setResult(data);
} catch (error) {
console.error('[OCR] recognize failed:', error);
Alert.alert('识别失败', String(error));
} finally {
setLoading(false);
}
};
return (
<SafeAreaView style={styles.safeArea}>
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.title}>OCR 商品包装识别</Text>
<Text style={styles.subtitle}>
React Native 调用 HarmonyOS OCR 能力,识别商品包装、标签、物流面单中的文字。
</Text>
<View style={styles.card}>
<Text style={styles.cardTitle}>图片</Text>
{imageUri ? (
<View style={styles.imageBox}>
<Text style={styles.imagePlaceholder}>已选择图片:{imageUri}</Text>
{/* 真机项目中可以用 Image 展示真实 URI */}
{/* <Image source={{ uri: imageUri }} style={styles.image} /> */}
</View>
) : (
<View style={styles.emptyImageBox}>
<Text style={styles.emptyText}>暂未选择图片</Text>
</View>
)}
<Pressable style={styles.secondaryButton} onPress={handleChooseImage}>
<Text style={styles.secondaryButtonText}>选择图片</Text>
</Pressable>
<Pressable style={styles.primaryButton} onPress={handleRecognize}>
<Text style={styles.primaryButtonText}>开始 OCR 识别</Text>
</Pressable>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>识别结果</Text>
{loading && (
<View style={styles.loadingBox}>
<ActivityIndicator />
<Text style={styles.loadingText}>正在识别中...</Text>
</View>
)}
{!loading && !result && (
<Text style={styles.emptyText}>识别结果会显示在这里</Text>
)}
{!loading && result && (
<View>
<Text style={styles.fullText}>{result.fullText}</Text>
<Text style={styles.metaText}>
共识别 {result.blocks.length} 个文本块
{result.costTime ? `,耗时 ${result.costTime}ms` : ''}
</Text>
{result.blocks.map((block, index) => (
<View key={`${block.text}-${index}`} style={styles.blockItem}>
<Text style={styles.blockIndex}>#{index + 1}</Text>
<Text style={styles.blockText}>{block.text}</Text>
{typeof block.confidence === 'number' && (
<Text style={styles.confidenceText}>
置信度:{Math.round(block.confidence * 100)}%
</Text>
)}
</View>
))}
</View>
)}
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#F7F8FA',
},
container: {
padding: 20,
},
title: {
fontSize: 24,
fontWeight: '700',
color: '#111827',
},
subtitle: {
marginTop: 8,
fontSize: 14,
color: '#6B7280',
lineHeight: 22,
},
card: {
marginTop: 20,
backgroundColor: '#FFFFFF',
borderRadius: 18,
padding: 18,
},
cardTitle: {
fontSize: 17,
fontWeight: '600',
color: '#111827',
marginBottom: 14,
},
imageBox: {
minHeight: 160,
borderRadius: 14,
backgroundColor: '#F3F4F6',
alignItems: 'center',
justifyContent: 'center',
padding: 16,
},
emptyImageBox: {
height: 160,
borderRadius: 14,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#D1D5DB',
alignItems: 'center',
justifyContent: 'center',
},
image: {
width: '100%',
height: 160,
borderRadius: 14,
},
imagePlaceholder: {
fontSize: 13,
color: '#4B5563',
textAlign: 'center',
},
emptyText: {
fontSize: 14,
color: '#9CA3AF',
},
secondaryButton: {
marginTop: 16,
borderRadius: 14,
paddingVertical: 13,
alignItems: 'center',
backgroundColor: '#EEF2FF',
},
secondaryButtonText: {
fontSize: 15,
color: '#1D4ED8',
fontWeight: '600',
},
primaryButton: {
marginTop: 12,
borderRadius: 14,
paddingVertical: 13,
alignItems: 'center',
backgroundColor: '#0A59F7',
},
primaryButtonText: {
fontSize: 15,
color: '#FFFFFF',
fontWeight: '600',
},
loadingBox: {
paddingVertical: 20,
alignItems: 'center',
},
loadingText: {
marginTop: 10,
color: '#6B7280',
},
fullText: {
fontSize: 15,
lineHeight: 24,
color: '#111827',
},
metaText: {
marginTop: 12,
color: '#6B7280',
fontSize: 13,
},
blockItem: {
marginTop: 12,
padding: 12,
borderRadius: 12,
backgroundColor: '#F9FAFB',
},
blockIndex: {
fontSize: 12,
color: '#6B7280',
},
blockText: {
marginTop: 4,
fontSize: 14,
color: '#111827',
lineHeight: 21,
},
confidenceText: {
marginTop: 4,
fontSize: 12,
color: '#6B7280',
},
});
8. 先用 Mock 原生模块跑通页面
真实接入 OCR 前,建议先用 Mock 数据跑通 RN 页面和 TurboModule 调用链路。
这样做的好处是:
- 先确认 RN 页面逻辑没问题;
- 先确认 TurboModule 注册没问题;
- 后面再替换成真实 OCR API,排查范围更小。
ArkTS 原生模块可以先返回模拟数据。
示例:
// OCRModule.ets
// 注意:以下为教学示例,具体基类、导入路径、注册方式请以当前 RNOH 工程模板为准。
export interface OCRTextBlock {
text: string
confidence?: number
left?: number
top?: number
width?: number
height?: number
}
export interface OCRResult {
fullText: string
blocks: OCRTextBlock[]
imageUri: string
costTime?: number
}
export class OCRModule {
async recognizeText(imageUri: string): Promise<OCRResult> {
const start = Date.now()
// 第一步先返回 Mock 数据,验证 RN ↔ ArkTS 调用链路
const blocks: OCRTextBlock[] = [
{
text: 'Stainless Steel Storage Rack',
confidence: 0.98,
},
{
text: 'Material: 304 Stainless Steel',
confidence: 0.96,
},
{
text: 'Size: 30 x 12 x 8 cm',
confidence: 0.95,
},
{
text: 'Made in China',
confidence: 0.93,
},
]
return {
fullText: blocks.map((item) => item.text).join('\n'),
blocks,
imageUri,
costTime: Date.now() - start,
}
}
}
运行后如果 RN 页面能展示 Mock 识别结果,说明最小链路已经打通。
9. 接入真实 HarmonyOS OCR 能力
Mock 跑通之后,再把 recognizeText 替换成真实 OCR 调用。本文实测版本使用 @kit.CoreVisionKit 中的 textRecognition.recognizeText。
真实调用链路如下:
1. 校验 imageUri 是否为空
2. 使用 fileIo.open(imageUri) 打开系统图片选择器返回的 file://media URI
3. 使用 image.createImageSource(file.fd) 创建 ImageSource
4. 使用 imageSource.createPixelMap() 解码图片
5. 调用 textRecognition.init() 初始化 OCR 服务
6. 调用 textRecognition.recognizeText({ pixelMap }, config)
7. 将 TextRecognitionResult.blocks / lines 转换成 OCRResult.blocks
8. 释放 OCR 服务、PixelMap、ImageSource 和文件句柄
核心代码如下:
import { fileIo, picker } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
import { textRecognition } from '@kit.CoreVisionKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { UITurboModule, UITurboModuleContext } from '@rnoh/react-native-openharmony';
interface OCRTextBlock {
text: string;
confidence?: number;
left?: number;
top?: number;
width?: number;
height?: number;
}
interface OCRResult {
fullText: string;
blocks: OCRTextBlock[];
imageUri: string;
costTime?: number;
}
export class OCRModule extends UITurboModule {
static readonly NAME = 'OCRModule';
constructor(ctx: UITurboModuleContext) {
super(ctx);
}
async pickImage(): Promise<string> {
const photoSelectOptions = new picker.PhotoSelectOptions();
photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
photoSelectOptions.maxSelectNumber = 1;
const photoViewPicker = new picker.PhotoViewPicker();
const photoSelectResult = await photoViewPicker.select(photoSelectOptions);
if (photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {
return photoSelectResult.photoUris[0];
}
return Promise.reject('CANCEL');
}
async recognizeText(imageUri: string): Promise<OCRResult> {
if (!imageUri) {
return Promise.reject('IMAGE_URI_EMPTY');
}
const start = Date.now();
let source: image.ImageSource | null = null;
let pixelMap: image.PixelMap | null = null;
let file: fileIo.File | null = null;
let serviceInitialized = false;
try {
file = await fileIo.open(imageUri, fileIo.OpenMode.READ_ONLY);
source = image.createImageSource(file.fd);
pixelMap = await source.createPixelMap();
serviceInitialized = await textRecognition.init();
if (!serviceInitialized) {
return Promise.reject('OCR_SERVICE_INIT_FAILED');
}
const nativeResult = await textRecognition.recognizeText(
{ pixelMap },
{ isDirectionDetectionSupported: true },
);
const blocks: OCRTextBlock[] = nativeResult.blocks.flatMap((block) =>
block.lines.map((line) => ({
text: line.value,
})),
);
return {
fullText: nativeResult.value || blocks.map((item) => item.text).join('\n'),
blocks,
imageUri,
costTime: Date.now() - start,
};
} catch (err) {
const error = err as BusinessError;
return Promise.reject(`OCR 识别失败: ${error.message || String(err)}`);
} finally {
if (serviceInitialized) {
await textRecognition.release().catch(() => {});
}
if (pixelMap) {
await pixelMap.release().catch(() => {});
}
if (source) {
await source.release().catch(() => {});
}
if (file) {
await fileIo.close(file).catch(() => {});
}
}
}
}
当前项目还把 line.cornerPoints 转换成了 left / top / width / height,方便后续做图片区域高亮。由于 Core Vision Kit 当前返回结构里没有置信度字段,RN 类型中的 confidence 保持为可选字段。
真机调用日志如下:
[OCRModule] pickImage success: file://media/Photo/1619/IMG_1781788459_1608/IMG_20260618_211239.jpg
[OCRModule] recognizeText success, blocks: 9, cost: 628ms
构建和安装命令如下:
npm run harmony
cd harmony
env -u OHOS_SDK -u OHOS_SDK_PATH \
DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk/default \
PATH="/Applications/DevEco-Studio.app/Contents/tools/node/bin:/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin:/Applications/DevEco-Studio.app/Contents/tools/ohpm/bin:/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains:$PATH" \
/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw assembleHap --mode module -p module=entry --no-daemon
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b host.huqi.sku_assistant
需要注意:如果命令行环境里同时存在旧版 OHOS_SDK / OHOS_SDK_PATH,可能会出现 SDK component missing。本文实测时通过显式指定 DevEco Studio 自带 SDK 和构建工具路径解决。
完整实现时还需要关注:
1. 权限与隐私提示
2. 大图解码内存占用
3. OCR 服务初始化失败
4. 将原生识别结果转换成 OCRResult
5. PixelMap / ImageSource / fd 资源释放
6. 设备不支持 OCR 能力时的降级提示
10. 图片选择能力怎么处理?
OCR 要处理图片,所以图片选择也是一个必须解决的问题。
有两种方案:
方案一:RN 侧使用已适配 OpenHarmony 的图片选择库
优点:
- RN 页面写法更接近 Android / iOS;
- 图片选择逻辑保持跨端统一;
- 后续维护成本较低。
缺点:
- 依赖第三方库是否已经适配 RNOH;
- 如果库未适配,需要额外处理 OpenHarmony 端实现。
方案二:自己封装 HarmonyOS 原生图片选择模块
优点:
- 可控性强;
- 适配 HarmonyOS 权限和 URI 处理更直接;
- 可以和 OCR 模块合并成一个“选择并识别”能力。
缺点:
- 需要额外写 ArkTS 原生代码;
- 需要处理权限、文件 URI、图片解码等细节。
本系列建议先用方案二,因为它更符合“RNOH 调 HarmonyOS 原生能力”的教程定位。
可以把接口设计成两个方法:
export interface Spec extends TurboModule {
pickImage(): Promise<string>;
recognizeText(imageUri: string): Promise<OCRResult>;
}
页面调用逻辑改成:
const handleChooseImage = async () => {
if (!NativeOCRModule) {
Alert.alert('错误', 'OCRModule 未注册');
return;
}
const uri = await NativeOCRModule.pickImage();
setImageUri(uri);
setResult(null);
};
这样体验会更完整。
11. 权限配置建议
OCR 场景可能涉及:
- 读取相册图片;
- 访问文件;
- 调用相机拍照;
- 使用系统视觉识别能力。
建议在 HarmonyOS 工程中明确检查:
1. module.json5 中是否声明所需权限
2. 是否需要运行时申请权限
3. 用户拒绝权限时是否有兜底提示
4. 图片 URI 是否有访问权限
5. OCR Kit 是否需要在 AGC / 控制台开通相关服务
RN 页面不要直接假设一定有权限,而是要处理错误状态:
try {
const data = await NativeOCRModule.recognizeText(imageUri);
setResult(data);
} catch (error) {
if (String(error).includes('PERMISSION')) {
Alert.alert('权限不足', '请允许应用访问图片后再试');
} else {
Alert.alert('识别失败', String(error));
}
}
12. 错误码设计
建议不要直接把原生异常丢给 RN 页面,而是设计统一错误码。
IMAGE_URI_EMPTY 图片路径为空
IMAGE_READ_FAILED 图片读取失败
IMAGE_FORMAT_UNSUPPORTED 图片格式不支持
OCR_SERVICE_UNAVAILABLE OCR 能力不可用
OCR_RECOGNIZE_FAILED OCR 识别失败
PERMISSION_DENIED 权限被拒绝
MODULE_NOT_REGISTERED 原生模块未注册
ArkTS 返回错误时可以带上:
{
code: 'OCR_RECOGNIZE_FAILED',
message: '文字识别失败,请更换清晰图片后重试'
}
RN 页面根据错误码做友好提示。
13. OCR 结果展示优化
最简单的展示方式是直接展示 fullText。
但如果想让文章更像真实项目,可以继续做三类优化。
1)按文本块展示
适合调试 OCR 结果:
#1 Product Name: Stainless Steel Storage Rack
#2 Material: 304 Stainless Steel
#3 Size: 30 x 12 x 8 cm
#4 Made in China
2)按字段提取
适合跨境电商场景:
商品名称:Stainless Steel Storage Rack
材质:304 Stainless Steel
尺寸:30 x 12 x 8 cm
产地:Made in China
3)低置信度提醒
如果置信度低于 80%,可以提示用户重新拍摄:
const lowConfidenceBlocks = result.blocks.filter(
(item) => typeof item.confidence === 'number' && item.confidence < 0.8,
);
页面提示:
部分文字识别置信度较低,建议重新拍摄更清晰图片。
14. 常见问题
问题 1:NativeOCRModule 为 null
检查:
1. TurboModule 名称是否一致
2. ArkTS 模块是否注册
3. Codegen 是否重新执行
4. HarmonyOS 工程是否重新编译
5. RN 侧是否引入了正确的 NativeOCRModule 文件
尤其注意:
TurboModuleRegistry.get<Spec>('OCRModule')
必须和原生侧注册名保持一致。
问题 2:图片路径传到原生侧后无法读取
常见原因:
1. URI 不是原生侧可访问路径
2. 没有图片读取权限
3. 图片选择库返回的是临时 URI
4. 原生侧没有做 URI 到文件 / PixelMap 的转换
5. 图片格式不支持
建议先在 ArkTS 侧打印 imageUri,确认传入路径是否符合预期。
问题 3:OCR 识别结果为空
可能原因:
1. 图片太模糊
2. 文字太小
3. 光线不足
4. 图片旋转方向异常
5. OCR 能力没有正确初始化
6. 当前语言不在识别支持范围内
建议准备 3 类测试图片:
1. 清晰英文商品包装图
2. 清晰中文标签图
3. 物流面单 / 表单类图片
不要一开始就用复杂背景图片。
问题 4:iOS / Android 可以用的 OCR 库,在 HarmonyOS 上不可用
这是 RNOH 适配中非常常见的问题。
原因是很多 RN 三方库只实现了 Android / iOS 原生端,没有 OpenHarmony 实现。
解决方案:
1. 查看该库是否已有 OpenHarmony 适配版本
2. 如果没有,自己写 ArkTS 原生模块
3. 用 TurboModule 对外暴露统一 JS API
4. RN 页面保持不变,只替换平台实现
这也是本系列要强调的核心思路:
不是等所有三方库都适配 HarmonyOS,而是把关键原生能力封装成可控的 RNOH 模块。
15. 本篇小结
本篇完成了 React Native 调用 HarmonyOS OCR 能力的完整设计:
RN 页面
↓
NativeOCRModule
↓
RNOH TurboModule
↓
ArkTS OCRModule
↓
HarmonyOS OCR 能力
↓
识别结果回显到 RN 页面
这一篇的重点不是单纯“识别文字”,而是建立一个可复用的视觉能力接入范式:
图片输入
↓
原生视觉能力处理
↓
结构化结果返回
↓
React Native 业务页面消费
后续很多能力都可以沿用这个模式:
- 端侧 AI 主体分割;
- 商品图抠图;
- 图片质量检测;
- 条码识别;
- 表单识别;
- 商品信息结构化。
下一篇我们继续写更有视觉冲击力的一篇:
React Native x HarmonyOS 端侧 AI:商品图主体分割与背景替换
下一篇会实现:
上传商品图
↓
端侧 AI 主体分割
↓
生成主体 Mask
↓
选择背景色
↓
生成白底图 / 彩色背景图
更多推荐



所有评论(0)