OCR文字识别标注小助手

news2024/11/24 19:44:37

目录

背景

工具界面

操作

1、选择目录

2、更改为正确的信息

3、保存

4、说明

项目

代码

下载


背景

为什么要写这么一个小工具呢?因为要对文字进行标注。

为什么对文字进行标注呢?因为要重新训练识别。

为什么要重新训练识别呢?因为通用OCR识别识别不了。(通用OCR识别参考 https://lw112190.blog.csdn.net/article/details/133784164)

什么样子的图片通用OCR识别不了呢?它来了,如下图

放大看一个

识别不了的原因主要是特殊字体+横线干扰

打算重新训练之前,做过哪些努力呢?

1、更换精度更高的服务器端模型,效果不好,放弃

2、图片预处理,去掉文字后面的横线(去掉文字后面横线参考:https://lw112190.blog.csdn.net/article/details/134283487),再识别,效果不好,放弃。

所以自己标注,重新训练了。

训练效果如何?暂时还不知道,因为标注工作还没完成。

工具界面

操作

1、选择目录

选择后默认加载第一章图片

文本框里面的字哪里来的呢,是我用通用OCR识别的,虽然效果不好,但是还是能识别一些,标注的时候可以少打几个字。

2、更改为正确的信息

3、保存

点击保存,或者键盘Enter,自动加载下一张图片,效率还不错。

4、说明

默认会在选择的目录下生成两个文件夹,标注不会对原数据进行任何处理。

target存放标注好保存的文件。

cache记录一下标注的文件,方便后续工作(比如今天标不完了,关机下班,明天来了打开工具,可以从昨天标注的图片的下一张图片继续标注)。

项目

代码

代码写的比较糙,因为只是一个临时性的工具,需要的可以根据自己的需要修改、重构。

using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace OpenCvSharp_Demo
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        int index = -1;
        Mat src;
        String name;
        String ImageFolderPath;
        String TargetFolderPath;
        String CacheFolderPath;
        List<String> ImgFile = new List<string>();
        List<String> CacheImgFile = new List<string>();

        //下一张
        private void button2_Click(object sender, EventArgs e)
        {
            index = index + 1;

            if (index > ImgFile.Count - 1)
            {
                index = ImgFile.Count;
                MessageBox.Show("下一张没有了,干完了!");
                return;
            }

            ShowImg(index);
        }

        //上一张
        private void button4_Click(object sender, EventArgs e)
        {
            index = index - 1;

            if (index < 0)
            {
                MessageBox.Show("上一张没有了");
                index = 0;
                return;
            }

            ShowImg(index);
        }

        private void ShowImg(int index)
        {
            name = ImgFile[index];
            txtName.Text = name.Split('.')[0];
            txtInfo.Text = name + " " + index + "/" + ImgFile.Count;

            if (File.Exists(CacheFolderPath + name.Split('.')[0] + ".txt"))
            {
                string info = System.IO.File.ReadAllText(CacheFolderPath + name.Split('.')[0] + ".txt");
                if (info.StartsWith("del_"))
                {
                    //已经标注
                    txtInfo.Text = name + "[标记为删除] " + (index + 1).ToString() + "/" + ImgFile.Count;
                }
                else
                {
                    //已经标注
                    txtInfo.Text = name + "[已经标注] " + (index + 1) + "/" + ImgFile.Count;
                    txtName.Text = info;
                }
            }
            else
            {
                //未标注
                txtInfo.Text = name + " " + (index + 1) + "/" + ImgFile.Count;
            }

            if (src!=null)
            {
                src.Dispose();
            }

            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }

            src = new Mat(ImageFolderPath + name);

            pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src);

        }

        //保存
        private void button1_Click(object sender, EventArgs e)
        {
            //保存图片
            Cv2.ImWrite(TargetFolderPath + txtName.Text + "." + name.Split('.')[1], src);

            //写个缓存
            FileStream fs = new FileStream(CacheFolderPath + name.Split('.')[0] + ".txt", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
            sw.WriteLine(txtName.Text);
            sw.Close();
            fs.Close();

            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }

            if (src != null)
            {
                src.Dispose();
            }

            //下一张
            button2_Click(null, null);
        }

        /// <summary>
        /// 选择目录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();

            if (dialog.ShowDialog(this) != DialogResult.OK)
            {
                return;
            }

            ImageFolderPath = dialog.SelectedPath + "\\";

            TargetFolderPath = ImageFolderPath + "target\\";
            CacheFolderPath = ImageFolderPath + "cache\\";

            if (!Directory.Exists(TargetFolderPath))
            {
                Directory.CreateDirectory(TargetFolderPath);
            }

            DirectoryInfo root = new DirectoryInfo(ImageFolderPath);
            foreach (FileInfo f in root.GetFiles())
            {
                if (f.Extension.Contains(".jpg") || f.Extension.Contains(".jpeg") || f.Extension.Contains(".png"))
                {
                    ImgFile.Add(f.Name);
                }
            }

            if (ImgFile.Count == 0)
            {
                MessageBox.Show("没有图片");
                return;
            }

            txtInfo.Text = "共计[" + ImgFile.Count + "]张图片";

            if (!Directory.Exists(CacheFolderPath))
            {
                Directory.CreateDirectory(CacheFolderPath);
            }
            else
            {
                //定位上一次标注的位置,然后下一张
                root = new DirectoryInfo(CacheFolderPath);
                foreach (FileInfo f in root.GetFiles())
                {
                    if (f.Extension.Contains(".txt"))
                    {
                        CacheImgFile.Add(f.Name);
                    }
                }

                if (CacheImgFile.Count > 0)
                {
                    string lastImg = CacheImgFile.Last();
                    lastImg = lastImg.Split('.')[0];
                    string temp = ImgFile.Find(o => o.StartsWith(lastImg));
                    if (!string.IsNullOrEmpty(temp))
                    {
                        index = ImgFile.IndexOf(temp);
                    }
                }
            }

            //自动下一张
            button2_Click(null, null);

        }

        //删除
        private void button5_Click(object sender, EventArgs e)
        {
            //保存
            Cv2.ImWrite(TargetFolderPath + "del_" + txtName.Text + "." + name.Split('.')[1], src);

            //写个缓存
            FileStream fs = new FileStream(CacheFolderPath + name.Split('.')[0] + ".txt", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
            sw.WriteLine("del_" + txtName.Text);
            sw.Close();
            fs.Close();

            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }

            if (!src.Empty())
            {
                src.Dispose();
            }

            //下一张
            button2_Click(null, null);
        }
    }
}

下载

源码下载

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python socket编程2 - socket创建发送方所需参数的获得

使用socket进行进程间通信或者跨网络的计算机间通讯&#xff0c;有点类似日常生活中的发送快递。 根据发送方的需要&#xff0c;选择不同的物流公司&#xff1a; 在选择适合的公司和运输方式后&#xff0c;需要在app上做出选择&#xff0c;并根据要求填写一些信息。app会根据…

根据视频编码时间批量重命名视频文件

整理收藏的小视频的时候发现很多视频命名很随意&#xff0c;自己命名又太麻烦&#xff0c;看着乱糟糟的文件又心烦&#xff0c;所有写了这个程序&#xff0c;代码如下&#xff1a; import osfrom filetype import filetype from pymediainfo import MediaInfovideo_extension …

【文件读取/包含】任意文件读取漏洞 afr_3

1.1漏洞描述 漏洞名称任意文件读取漏洞 afr_3漏洞类型文件读取/包含漏洞等级⭐⭐⭐⭐⭐漏洞环境docker攻击方式 1.2漏洞等级 高危 1.3影响版本 暂无 1.4漏洞复现 1.4.1.基础环境 靶场docker工具BurpSuite 1.4.2.环境搭建 1.创建docker-compose.yml文件 version: 3.2 servi…

从CentOS向KeyarchOS操作系统的wordpress应用迁移实战

文章目录 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战一、使用浪潮信息X2Keyarch迁移工具完成操作系统的迁移1.1 迁移前的验证1.2 执行迁移评估1.3 开始迁移1.4 验证迁移结果1.5 迁移后的验证 二、总结 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战 CentOS是一…

mysql操作 sql语句中的完整性约束有哪些,主键约束、外键约束、引用完整性约束,主键外键、唯一性

什么是约束&#xff1a;约束&#xff1a;就是约定哪些东西能填、怎么填&#xff1f;哪些东西不能填&#xff1f; 文章目录 前言&#xff1a;建表正文一、实体完整性约束1. 主键约束2. 唯一性约束3. 自增长约束4. 联合主键约束 二、域完整性约束三、引用完整性约束1. 外键约束 讲…

【Git企业开发】第七节.多人协作开发

文章目录 前言 一、多人协作开发 1.1 多人协作一 1.2 多人协作二 1.3 远程分支删除后&#xff0c;本地 git branch -a 依然能看到的解决办法 总结 前言 一、多人协作开发 1.1 多人协作一 目前&#xff0c;我们所完成的工作如下: 基本完成Git的所有本地库的相关操作&#xff0…

未来10年,NAND 与DRAM依然是存储主角

根据Yole Group调查机构的数据显示&#xff0c;在2022年独立记忆体&#xff08;Stand-alone Memory&#xff09;整体市场达到了1440亿美元。其中DRAM占比55.4%&#xff0c;NAND占比40.8%。剩下的NOR、(NV)SRAM/FRAM、EEPROM、新型非易失存储(PCM, ReRAM and STT-MRAM)等占比3.8…

蓝桥杯 string

string简介 string是C标准库的重要组成部分&#xff0c;主要用于字符串处理。 使用string库需要在头文件中包括该库 #include< string> string与char[]不同&#xff0c;string实现了高度的封装&#xff0c;可以很方便地完 成各种字符串的操作&#xff0c;比如拼接、截取…

Since Maven 3.8.1 http repositories are blocked

原因 高版本的maven不支持http的存储库。 解决方案 其实方法有好几种&#xff0c;比如降级maven版本至3.6.3(之前一直用的都是这个版本)&#xff0c;我选择了一种比较快(但不一定安全)的方式&#xff0c;因为3.6.3版本被我卸载了&#xff0c;这里直接修改idea的setting配置&…

【Java 进阶篇】JQuery 案例:下拉列表选中条目左右移动,打破选择的边界

在前端的舞台上&#xff0c;下拉列表是常见的用户交互元素&#xff0c;但有时候我们想要更多的交互体验。通过巧妙运用 JQuery&#xff0c;我们可以实现下拉列表中选中条目的左右移动功能&#xff0c;为用户提供更加灵活的选择方式。本篇博客将深入研究 JQuery 中实现这一功能的…

技巧篇:在Pycharm中配置集成Git

一、在Pycharm中配置集成Git 我们使用git需要先安装git工具&#xff0c;这里给出下载地址&#xff0c;下载后一路直接安装即可&#xff1a; https://git-for-windows.github.io/ 0. git中的一些常用词释义 Repository name&#xff1a; 仓库名称 Description(可选)&#xff1a;…

【数据结构】别跟我讲你不会冒泡排序

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;数据结构 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有帮助…

旅拍摄影技巧澳大利亚、韩国旅行攻略

欢迎关注「苏南下」 在这里分享我的旅行和影像创作心得 刚刚在腾讯内部做了一场摄影分享课&#xff1a; 《旅拍摄影技巧&澳大利亚、韩国旅行攻略》 分享了早前去两个国家的一些旅行见闻和摄影心得。我发现&#xff1a;把自己学会的东西整理出来&#xff0c;再告诉给别人这件…

67基于matlab图像处理,包括颜色和亮度调整、翻转功能、空间滤波和去噪、频域滤波和去噪、噪声添加,形态学操作、边缘检测及示波器集成的GUI图像处理。

基于matlab图像处理&#xff0c;包括颜色和亮度调整、翻转功能、空间滤波和去噪、频域滤波和去噪、噪声添加&#xff0c;形态学操作、边缘检测及示波器集成的GUI图像处理。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 67 matlab图像处理图像降噪 (xiaohon…

cubemx工程更换同系列stm32芯片型号

cubemx工程更换stm32芯片型号 实验平台 软件&#xff1a;cubemx v6.10、vscode、MDK v5.27 旧型号芯片&#xff1a;stm32f103c8t6 新型号芯片&#xff1a;stm32f103ret6 步骤 1、复制stm32工程&#xff08;包含.ioc文件&#xff09;到另一个路径&#xff0c;新路径与原路径…

STM32F103C8T6第4天:串口实验(非中断和中断)、hc01蓝牙、esp8266WIFI、4g

1. 串口基本介绍&#xff08;332.36&#xff09; 常用函数介绍 串口发送/接收函数&#xff1a; HAL_UART_Transmit(); 串口发送数据&#xff0c;使用超时管理机制HAL_UART_Receive(); 串口接收数据&#xff0c;使用超时管理机制HAL_UART_Transmit_IT(); 串口中断模式发送HAL…

栈的三道oj【C++】

栈和队列的相关oj 最小栈思路解决代码 栈的压入弹出序列思路解决代码 逆波兰表达式思路&#xff1a;解决代码 这里就挑了三道题用来熟悉栈 最小栈 力扣链接 咱们已经是高贵的C使用者了&#xff0c;不用像C语言一样从头开始造轮子了 这里我们调用了stack后&#xff0c;就会发…

SMART PLC滑动平均值滤波(指针+FOR循环应用浮点数滤波)

SMART PLC滑动平均值滤波应用于单整型数据请查看下面文章链接: 【精选】S7-200 SMART PLC信号处理系列之滑动平均值滤波FB_smart200 滤波函数_RXXW_Dor的博客-CSDN博客文章浏览阅读1.5k次。PLC相关滤波算法,专栏有很多详细讲解这里不再赘述。滑动平均值滤波和算术平均值滤波…

halcon识别验证码,先训练后识别

识别验证码图片&#xff0c;使用halcon 21.05 下面代码识别准确率100% 目录 训练&#xff0c;图片打标签使用代码创建分类器&#xff1b;识别验证码&#xff0c;检验识别效果使用“助手”加载训练文件&#xff0c;加载训练分类器&#xff0c;察看收集的字符&#xff0c;训练识别…

创建数据透视表:根据表中一列作为分类的依据统计每个类别下不同子项数量cross_tab()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 创建数据透视表&#xff1a; 根据表中一列作为分类的依据 统计每个类别下不同子项数量 cross_tab() [太阳]选择题 关于以下代码的说法中正确的是? import pandas as pd data{A:[a1,a2,a1,a2,a…