应用场景

在企业文档管理、数字图书馆、电商商品管理等场景中,经常需要处理大量图片中的文字信息。例如:

  • 电商平台需要将商品图片中的型号、规格等信息提取出来作为文件名
  • 图书馆需要将扫描的图书页面识别为文字并整理归档
  • 企业需要将纸质文档电子化并按内容分类

使用 WPF 和京东 OCR 接口可以开发一个高效的桌面应用程序JD图片文字识别与重命名工具,实现图片文字识别和批量重命名功能。

界面设计

一个功能完善的图片文字识别与重命名工具界面应包含以下元素:

  1. 文件选择区域:支持拖放或点击选择图片文件 / 文件夹
  2. 处理队列显示:展示待处理和已处理的图片列表
  3. OCR 配置区域:设置识别语言、API 参数等
  4. 重命名规则设置:自定义文件名格式和替换规则
  5. 处理进度显示:实时展示处理进度和状态
  6. 日志输出区域:记录处理过程和错误信息

下面是一个基于 WPF 的实现方案:

image-ocr-rename-wpf基于WPF和京东OCR的图片文字识别与重命名工具

<Window x:Class="ImageOcrRenameTool.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="JD图片文字识别与重命名工具" Height="700" Width="900"WindowStartupLocation="CenterScreen"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><!-- 标题区域 --><Border Background="#3498db" Padding="10"><TextBlock Text="JD图片文字识别与重命名工具" FontSize="20" FontWeight="Bold" Foreground="White"/></Border><!-- 文件选择区域 --><GroupBox Header="文件选择" Grid.Row="1" Margin="10" Padding="10"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><TextBox x:Name="txtFilePath" TextWrapping="Wrap" Margin="0,0,5,0" IsReadOnly="True"/><Button x:Name="btnSelectFile" Content="选择文件" Margin="5,0" Padding="10,5" Click="BtnSelectFile_Click"/><Button x:Name="btnSelectFolder" Content="选择文件夹" Margin="5,0" Padding="10,5" Click="BtnSelectFolder_Click" Grid.Column="2"/></Grid></GroupBox><!-- OCR配置区域 --><GroupBox Header="JD_OCR配置" Grid.Row="2" Margin="10" Padding="10"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><TextBlock Text="AppKey:" VerticalAlignment="Center" Margin="0,5"/><TextBox x:Name="txtAppKey" TextWrapping="Wrap" Margin="5,5" Text="{Binding AppKey, Mode=TwoWay}"/><TextBlock Text="AppSecret:" VerticalAlignment="Center" Margin="0,5" Grid.Column="2"/><TextBox x:Name="txtAppSecret" TextWrapping="Wrap" Margin="5,5" Text="{Binding AppSecret, Mode=TwoWay}"Grid.Column="3"/><TextBlock Text="识别语言:" VerticalAlignment="Center" Margin="0,5" Grid.Row="1"/><ComboBox x:Name="cmbLanguage" Margin="5,5" Grid.Row="1" Grid.Column="1"ItemsSource="{Binding AvailableLanguages}" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}"/><TextBlock Text="重命名规则:" VerticalAlignment="Center" Margin="0,5" Grid.Row="2"/><TextBox x:Name="txtRenameRule" TextWrapping="Wrap" Margin="5,5" Grid.Row="2" Grid.Column="1"Text="{Binding RenameRule, Mode=TwoWay}" ToolTip="使用{text}表示识别的文字,{index}表示序号,{original}表示原文件名"/></Grid></GroupBox><!-- 处理区域 --><GroupBox Header="处理队列" Grid.Row="3" Margin="10" Padding="10"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><StackPanel Orientation="Horizontal" Margin="0,0,0,5"><Button x:Name="btnStartProcess" Content="开始处理" Padding="10,5" Click="BtnStartProcess_Click" IsEnabled="{Binding CanStartProcessing}"/><Button x:Name="btnStopProcess" Content="停止处理" Padding="10,5" Margin="5,0,0,0" Click="BtnStopProcess_Click" IsEnabled="{Binding IsProcessing}"/><ProgressBar x:Name="progressBar" Width="200" Height="20" Margin="10,0,0,0" Value="{Binding ProgressValue}" Maximum="{Binding ProgressMax}"/><TextBlock x:Name="txtProgress" Text="{Binding ProgressText}" VerticalAlignment="Center" Margin="5,0,0,0"/></StackPanel><DataGrid x:Name="dataGrid" AutoGenerateColumns="False" ItemsSource="{Binding ImageItems}" CanUserAddRows="False" CanUserDeleteRows="False" SelectionMode="Single"HorizontalGridLinesBrush="LightGray" VerticalGridLinesBrush="LightGray"><DataGrid.Columns><DataGridTextColumn Header="序号" Binding="{Binding Index}" Width="50"/><DataGridTextColumn Header="原文件名" Binding="{Binding OriginalFileName}" Width="*"/><DataGridTextColumn Header="识别文字" Binding="{Binding RecognizedText}" Width="*"/><DataGridTextColumn Header="新文件名" Binding="{Binding NewFileName}" Width="*"/><DataGridTextColumn Header="状态" Binding="{Binding Status}" Width="100"/></DataGrid.Columns></DataGrid></Grid></GroupBox><!-- 日志区域 --><GroupBox Header="处理日志" Grid.Row="4" Margin="10" Padding="10"><TextBox x:Name="txtLog" TextWrapping="Wrap" AcceptsReturn="True" IsReadOnly="True" VerticalScrollBarVisibility="Auto" Height="100"/></GroupBox></Grid>
</Window>    

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;namespace ImageOcrRenameTool
{public class MainViewModel : INotifyPropertyChanged{private readonly JdOcrService _ocrService;private string _appKey;private string _appSecret;private string _selectedLanguage = "CHN_ENG";private string _renameRule = "{text}_{index}";private bool _isProcessing;private double _progressValue;private double _progressMax;private string _progressText = "就绪";public event PropertyChangedEventHandler PropertyChanged;public ObservableCollection<ImageItem> ImageItems { get; } = new ObservableCollection<ImageItem>();public List<string> AvailableLanguages { get; } = new List<string>{"CHN_ENG", "ENG", "JAP", "KOR", "FRE", "SPA", "POR", "GER", "ITA", "RUS"};public string AppKey{get => _appKey;set{_appKey = value;OnPropertyChanged();}}public string AppSecret{get => _appSecret;set{_appSecret = value;OnPropertyChanged();}}public string SelectedLanguage{get => _selectedLanguage;set{_selectedLanguage = value;OnPropertyChanged();}}public string RenameRule{get => _renameRule;set{_renameRule = value;OnPropertyChanged();}}public bool IsProcessing{get => _isProcessing;set{_isProcessing = value;OnPropertyChanged();OnPropertyChanged(nameof(CanStartProcessing));}}public bool CanStartProcessing => !IsProcessing && ImageItems.Any();public double ProgressValue{get => _progressValue;set{_progressValue = value;OnPropertyChanged();}}public double ProgressMax{get => _progressMax;set{_progressMax = value;OnPropertyChanged();}}public string ProgressText{get => _progressText;set{_progressText = value;OnPropertyChanged();}}public MainViewModel(){_ocrService = new JdOcrService();}public void AddImageFiles(string[] filePaths){if (filePaths == null || !filePaths.Any())return;var supportedExtensions = new[] { ".jpg", ".jpeg", ".png", ".bmp", ".gif" };foreach (var filePath in filePaths){if (File.Exists(filePath) && supportedExtensions.Contains(Path.GetExtension(filePath).ToLower())){var index = ImageItems.Count + 1;ImageItems.Add(new ImageItem{Index = index,FilePath = filePath,OriginalFileName = Path.GetFileName(filePath)});}}ProgressMax = ImageItems.Count;OnPropertyChanged(nameof(CanStartProcessing));}public void AddImageFolder(string folderPath){if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))return;var supportedExtensions = new[] { ".jpg", ".jpeg", ".png", ".bmp", ".gif" };var filePaths = Directory.GetFiles(folderPath).Where(f => supportedExtensions.Contains(Path.GetExtension(f).ToLower())).ToList();AddImageFiles(filePaths.ToArray());}public async Task ProcessImagesAsync(CancellationToken cancellationToken){IsProcessing = true;ProgressValue = 0;try{if (string.IsNullOrEmpty(AppKey) || string.IsNullOrEmpty(AppSecret)){throw new InvalidOperationException("请先设置京东OCR的AppKey和AppSecret");}_ocrService.Initialize(AppKey, AppSecret);var processedCount = 0;foreach (var item in ImageItems){if (cancellationToken.IsCancellationRequested)throw new OperationCanceledException();try{item.Status = "处理中";ProgressText = $"正在处理: {item.OriginalFileName}";// 执行OCR识别var ocrResult = await _ocrService.RecognizeImageAsync(item.FilePath, SelectedLanguage, cancellationToken);item.RecognizedText = ocrResult;// 生成新文件名item.NewFileName = GenerateNewFileName(item, processedCount + 1);// 重命名文件RenameFile(item);item.Status = "已完成";processedCount++;}catch (OperationCanceledException){item.Status = "已取消";throw;}catch (Exception ex){item.Status = "失败";item.ErrorMessage = ex.Message;}finally{ProgressValue++;ProgressText = $"已完成: {processedCount}/{ImageItems.Count}";}}ProgressText = $"处理完成! 共处理 {processedCount} 个文件";}finally{IsProcessing = false;}}private string GenerateNewFileName(ImageItem item, int index){if (string.IsNullOrEmpty(RenameRule))return item.OriginalFileName;var originalName = Path.GetFileNameWithoutExtension(item.OriginalFileName);var extension = Path.GetExtension(item.OriginalFileName);// 替换模板变量var newName = RenameRule.Replace("{text}", SanitizeFileName(item.RecognizedText)).Replace("{index}", index.ToString()).Replace("{original}", originalName);// 确保文件名不超过最大长度if (newName.Length > 240) // NTFS文件名最大长度为255字符,留出空间给扩展名newName = newName.Substring(0, 240);return newName + extension;}private void RenameFile(ImageItem item){if (string.IsNullOrEmpty(item.NewFileName) || item.NewFileName == item.OriginalFileName)return;var directory = Path.GetDirectoryName(item.FilePath);if (string.IsNullOrEmpty(directory))return;var newFilePath = Path.Combine(directory, item.NewFileName);try{// 如果新文件名已存在,添加序号if (File.Exists(newFilePath)){var baseName = Path.GetFileNameWithoutExtension(item.NewFileName);var extension = Path.GetExtension(item.NewFileName);var counter = 1;do{newFilePath = Path.Combine(directory, $"{baseName}_{counter}{extension}");counter++;} while (File.Exists(newFilePath));item.NewFileName = Path.GetFileName(newFilePath);}File.Move(item.FilePath, newFilePath);item.FilePath = newFilePath;}catch (Exception ex){throw new Exception($"重命名文件失败: {ex.Message}");}}private string SanitizeFileName(string fileName){if (string.IsNullOrEmpty(fileName))return "未识别文字";// 移除或替换文件路径中的非法字符var invalidChars = Path.GetInvalidFileNameChars();var sanitized = new string(fileName.Select(c => invalidChars.Contains(c) ? '_' : c).ToArray());// 替换连续的空格和下划线sanitized = Regex.Replace(sanitized, @"[_\s]+", "_");// 去除首尾空格和下划线return sanitized.Trim('_', ' ');}protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
}    

详细代码步骤

这个应用程序主要包含以下几个部分:

  1. 界面设计:使用 WPF 创建了一个直观的用户界面,包括文件选择、OCR 配置、处理队列和日志显示等区域。

  2. 数据模型

    • ImageItem类:表示待处理的图片项,包含原始文件名、识别文字、新文件名和处理状态等属性
    • JdOcrResponse系列类:用于解析京东OCR接口的返回数据
  3. 视图模型MainViewModel类实现了主要的业务逻辑:

    • 管理图片文件列表
    • 与京东 OCR 服务交互
    • 生成新文件名并执行重命名操作
    • 管理处理进度和状态
  4. OCR 服务JdOcrService类封装了与京东OCR API的通信:

    • 初始化 API 凭证
    • 将图片转换为 Base64 格式
    • 发送请求并解析响应
  5. 文件名处理:实现了安全的文件名生成和清理逻辑,确保生成的文件名符合文件系统规则。

总结优化

这个应用程序提供了一个功能完整的图片文字识别与重命名解决方案,但还有一些可以优化的地方:

  1. 性能优化

    • 可以实现多线程处理,提高大量图片的处理速度
    • 添加图片缓存机制,避免重复处理相同图片
    • 实现断点续传功能,支持中断后继续处理
  2. 错误处理

    • 增强对网络异常的处理,实现自动重试机制
    • 提供更详细的错误日志和调试信息
    • 添加文件冲突解决策略选项
  3. 扩展功能

    • 支持更多 OCR 服务提供商,实现服务切换功能
    • 添加图片预处理功能,如旋转、裁剪、增强对比度等
    • 支持导出识别结果到文本文件或 Excel 表格

这个应用程序可以根据实际需求进一步定制和扩展,成为一个强大的图片文字处理工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/85067.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/85067.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/85067.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简历模板2——数据挖掘工程师5年经验

姓名 / Your Name 数据挖掘工程师 | 5年经验 | 推荐/风控/图模型 &#x1f4de; 138-XXXX-XXXX | ✉️ your.emailexample.com | &#x1f310; github.com/yourname | &#x1f4cd; 北京 &#x1f3af; 个人简介 / Summary 5年大厂数据挖掘经验&#xff0c;硕士学历。擅长推…

CSS3 渐变效果

1. 引言 CSS3 渐变能够在指定颜色之间创建平滑过渡效果。这种设计元素不仅能为网页增添丰富的视觉层次&#xff0c;更是现代网页设计的重要组成部分。CSS3 提供两种主要的渐变类型&#xff1a;线性渐变(Linear Gradient) - 沿直线方向进行颜色过渡&#xff1b;径向渐变(Radial…

A Survey on 3D Gaussian Splatting——3D高斯领域综述

原文链接&#xff1a;[2401.03890] A Survey on 3D Gaussian Splatting 动态更新的GitHub仓库&#xff08;包含性能对比与最新文献追踪&#xff09;&#xff1a; https://github.com/guikunchen/3DGS-Benchmarks https://github.com/guikunchen/Awesome3DGS 摘要&#xff1…

计算机网络 期末实训 eNSP 校园网

eNSP 综合实训 小型校园网 计算机网络期末实训 01 搭建拓扑 1.设计任务 构建一个小型校园网络,涵盖以下设备与区域: 学生宿舍区:50台计算机办公楼区:30台计算机(细分为财务部门、人事部门及其他科室)图书馆:10台计算机教学楼:30台计算机服务器集群:2台服务器,分别用…

Smart Form Adobe form 强制更改内表:TNAPR

强制更改内表:TNAPR se16-> Smart Form总览 Smart form 变量格式说明: &symbol& (括号中,小写字母为变量) &symbol& 屏蔽从第一位开始的N位 &symbol (n)& 只显示前N位 &symbol (S)& 忽略正负号 &symbol (<)& 符号在…

页面配置文件pages.json和小程序配置

页面配置文件pages.json和小程序配置 pages.jsonpagesstyle-navigationBarBackgroundColorstyle-navigationBarTitleTextstyle-navigationStylestyle-enablePullDownRefresh注意事项不同平台区分配置新建页面 globalStyletabBar代码 manifest.json授权web配置代理 pages.json …

Linux网络配置工具ifconfig与ip命令的全面对比

在Linux网络管理中&#xff0c;ifconfig和 ip命令是最常用的两个工具。随着时间的推移&#xff0c;ip命令逐渐取代了 ifconfig&#xff0c;成为更强大和灵活的网络配置工具。本文将对这两个工具进行全面对比&#xff0c;帮助您理解它们的区别和各自的优势。 一、ifconfig命令 …

STM32 实现解析自定义协议

一、环形队列设计与实现&#xff08;核心缓冲机制&#xff09; 数据结构设计&#xff1a; #define BUFFER_SIZE 512 #define BUFFER_MASK (BUFFER_SIZE - 1) typedef struct {volatile uint8_t buffer[BUFFER_SIZE]; // 环形缓冲区&#xff08;大小可配置&#xff09;volati…

NGINX 四层上游模块`ngx_stream_upstream_module` 实战指南

一、模块定位与引入 模块名称&#xff1a;ngx_stream_upstream_module 首次引入&#xff1a;NGINX 1.9.0&#xff08;2015-08-04&#xff09; 编译选项&#xff1a;启用 --with-stream&#xff08;含此模块&#xff09; 作用&#xff1a; 定义后端服务器组&#xff08;upstr…

WinUI3入门2:DataGrid动态更新 添加删除和修改字段

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

基于Python学习《Head First设计模式》第十三章 现实世界中的模式

定义设计模式 设计模式要素 模式名称、分类意图&#xff1a;描述模式是什么动机&#xff1a;描述什么时候使用这个模式&#xff0c;具体场景适用性&#xff1a;描述什么地方使用这个模式&#xff0c;用在什么场合结构&#xff1a;类图参与者&#xff1a;类和对象的责任和角色…

线性代数(1)线性方程组的多种解法

求解线性方程组是线性代数的核心问题之一&#xff0c;根据方程组的类型&#xff08;如齐次/非齐次、方阵/非方阵、稀疏/稠密等&#xff09;&#xff0c;可以采用不同的解法。以下是常见的线性方程组解法分类及简要说明&#xff1a; 一、直接解法&#xff08;精确解&#xff09…

肝脏/肝脏肿瘤图像分割数据集(猫脸码客第261期)

探秘肝脏/肝脏肿瘤图像分割&#xff1a;医学影像技术的新突破 一、引言 肝脏/肝脏肿瘤图像分割在医学领域占据着愈发重要的地位&#xff0c;为肝脏疾病的精准诊断与有效治疗提供了关键技术支撑。随着医学成像技术的飞速进步&#xff0c;如磁共振成像&#xff08;MRI&#xff…

【LLM05---位置编码】

文章目录 位置编码引出Transformer中位置编码方法:Sinusoidal functions两个重要性质位置编码 最近在学习位置编码,想找一个讲的比较透彻的文章或视频,找了半天,满意的一个也没有,所以自己记录一下。 注意,本篇笔记只作为自己的学习记录用,更好的讲解的内容请看链接:位…

pikachu——ssrf

概念补充&#xff1a; 内网&#xff1a;局部范围内的私有网络&#xff0c;比如局域网就是一个小范围的内网&#xff0c;有私有IP&#xff0c;并且内网受防火墙的保护&#xff0c;外网无法直接访问 外网&#xff1a;全球范围的公共网络&#xff0c;公有ip ip地址&#xff1a;…

java 设计模式_行为型_13备忘录模式

13.备忘录模式 模式定义 备忘录模式&#xff08;Memento Pattern&#xff09;模式的定义&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便以后当需要时能将该对象恢复到原先保存的状态。该模式又…

创建postgres数据库失败

异常&#xff1a; postgres# CREATE DATABASE deepflow_agent2; ERROR: source database "template1" is being accessed by other users DETAIL: There are 2 other sessions using the database 如何断联这两个session 要解决 PostgreSQL 中因 template1 数据库…

卧安机器人闯上市:深耕AI具身技术,“大疆教父”李泽湘再落子

撰稿|行星 来源|贝多财经 又一家机器人企业&#xff0c;现身港股资本市场。贝多财经了解到&#xff0c;卧安机器人&#xff08;深圳&#xff09;股份有限公司&#xff08;下称“卧安机器人”&#xff09;于6月8日向港交所提交了上市申请&#xff0c;国泰君安国际、华泰国际为…

基于GNU Radio Companion搭建的AM信号实验

目录 实验目的和要求 1、AM收发系统仿真和实际接收 调制过程 2、Lab 2.1实验过程AM信号的产生 AM信号的表达式 调制深度的概念 3、Lab2.2 AM信号的解调 4、Lab2.3 实际用RTLSDR接收一个ISM(912MHz)频率的AM信号,信号的AM调制为音频为48KHz的音乐信号 实验目的和要求 …

【go】(仅思路)使用go实现一款简单的关系型数据库gosql

文章目录 背景给navicate回复版本号建立连接数据库list新建数据库删除数据库删除表查询表数据总结roadmapnavicate连接适配 背景 使用go很容易编译出一个二进制文件&#xff0c;已经有人用纯go实现了sqlite3的驱动&#xff08;go get github.com/glebarez/sqlite&#xff09;&…