C# Emgu.CV+Tesseract实现识别图像验证码
效果图,简单的还行,复杂的。。。拉跨
懒得写讲解了,全部源码直接上吧
/// <summary>/// 验证码识别/// </summary>public partial class FrmCodeIdentify : FrmBase{private string _filePath;// 原图像Image<Bgr, byte> inputImage;// 灰度图像Image<Gray, byte> inputGray;// 二值化图像Image<Gray, byte> binaryImage;// 去噪音图像Image<Gray, byte> denoisingImage;// 修复图像Image<Gray, byte> repairImage;// 图像增强Image<Bgr, byte> enhanceImage;public FrmCodeIdentify(){InitializeComponent();}/// <summary>/// 选择图像/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button1_Click(object sender, EventArgs e){using OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.Filter = ImageExtension;if (openFileDialog.ShowDialog() == DialogResult.OK){string selectedFile = openFileDialog.FileName;_filePath = selectedFile;this.pictureBox1.Image?.Dispose();this.pictureBox1.Image = new Bitmap(_filePath);inputImage?.Dispose();inputImage = new Image<Bgr, byte>(_filePath);if (checkBox1.Checked){ImageEnhancement();Grayscale();Binarization();Denoising();RepairImage();ShowAllTxt();}else{var bitmap = inputImage.ToBitmap();ShowTxt(bitmap, label3);}}}private void ShowAllTxt(){var bitmap3 = inputImage.ToBitmap();ShowTxt(bitmap3, label3);var bitmap4 = enhanceImage.ToBitmap();ShowTxt(bitmap4, label4);var bitmap5 = inputGray.ToBitmap();ShowTxt(bitmap5, label5);var bitmap1 = binaryImage.ToBitmap();ShowTxt(bitmap1, label1);var bitmap6 = denoisingImage.ToBitmap();ShowTxt(bitmap6, label6);var bitmap7 = repairImage.ToBitmap();ShowTxt(bitmap7, label7);}private void ShowTxt(Bitmap bitmap, Label label){var data = BitmapToByteArray(bitmap);bitmap.Dispose();var txt = ExtractedText(data);label.Text = $"识别结果:{txt}";}private void FrmCodeIdentify_Load(object sender, EventArgs e){}private void FrmCodeIdentify_FormClosing(object sender, FormClosingEventArgs e){repairImage?.Dispose();enhanceImage?.Dispose();denoisingImage?.Dispose();binaryImage?.Dispose();inputImage?.Dispose();inputGray?.Dispose();engine?.Dispose();this.Dispose();}/// <summary>/// 灰度化/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button2_Click(object sender, EventArgs e){Grayscale();var bitmap5 = inputGray.ToBitmap();ShowTxt(bitmap5, label5);}private void Grayscale(){inputGray?.Dispose();if (string.IsNullOrEmpty(_filePath)){MessageBox.Show("请选择图像");return;}//using Matrix<float> kernel = new Matrix<float>(kernelData);// 应用卷积操作//CvInvoke.Filter2D(inputImage, inputImage, kernel, new Point(-1, -1));//ShowPictureBox(pictureBox1, inputImage);//inputImage = PerformTextCorrection(inputImage);inputGray = enhanceImage.Convert<Gray, byte>();// 应用直方图均衡化//inputGray._EqualizeHist();this.pictureBox2.Image?.Dispose();this.pictureBox2.Image = inputGray.ToBitmap();}/// <summary>/// 二值化/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button3_Click(object sender, EventArgs e){Binarization();var bitmap1 = binaryImage.ToBitmap();ShowTxt(bitmap1, label1);}private void Binarization(){if (inputGray == null){MessageBox.Show("需要灰度化图像");return;}binaryImage?.Dispose();using var inputGrayOut = new Image<Gray, byte>(inputGray.Size);// 自适应阈值//binaryImage= new Image<Gray, byte>(inputGray.Size);//CvInvoke.AdaptiveThreshold(inputGray, binaryImage, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, 11, 2);// 计算OTSU阈值var threshold = CvInvoke.Threshold(inputGray, inputGrayOut, 0, 255, ThresholdType.BinaryInv | ThresholdType.Otsu);// 二值化图像binaryImage = inputGrayOut.ThresholdBinary(new Gray(threshold), new Gray(255));pictureBox3.Image?.Dispose();pictureBox3.Image = binaryImage.ToBitmap();}/// <summary>/// 去噪音/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button4_Click(object sender, EventArgs e){Denoising();var bitmap6 = denoisingImage.ToBitmap();ShowTxt(bitmap6, label6);}private void Denoising(){if (binaryImage == null){MessageBox.Show("需要二值化图像");return;}int mksize = (int)numericUpDown6.Value;if ((mksize & 1) == 0){MessageBox.Show("MedianBlur的ksize必须为奇数");return;}denoisingImage?.Dispose();denoisingImage = new Image<Gray, byte>(binaryImage.Size);// 中值滤波//CvInvoke.MedianBlur(binaryImage, binaryImage, mksize);// 创建结构元素using Mat element = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size((int)numericUpDown1.Value, (int)numericUpDown2.Value), new Point(-1, -1));// 进行开运算CvInvoke.MorphologyEx(binaryImage, denoisingImage, MorphOp.Open, element, new Point(-1, -1), (int)numericUpDown5.Value, BorderType.Default, new MCvScalar());//CvInvoke.BitwiseNot(denoisingImage, denoisingImage);// 中值滤波CvInvoke.MedianBlur(denoisingImage, denoisingImage, mksize);ShowPictureBox(pictureBox4, denoisingImage);}/// <summary>/// 修复/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button7_Click(object sender, EventArgs e){RepairImage();var bitmap7 = repairImage.ToBitmap();ShowTxt(bitmap7, label7);}private void RepairImage(){if (denoisingImage == null){MessageBox.Show("请操作去噪音");return;}repairImage?.Dispose();// 创建结构元素using Mat element = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size((int)numericUpDown8.Value, (int)numericUpDown7.Value), new Point(-1, -1));repairImage = new Image<Gray, byte>(denoisingImage.Size);CvInvoke.MorphologyEx(denoisingImage, repairImage, MorphOp.Close, element, new Point(-1, -1), 1, BorderType.Default, new MCvScalar());ShowPictureBox(pictureBox6, repairImage);}// 创建卷积核float[,] kernelData = {{ -1, -1, -1 },{ -1, 9, -1 },{ -1, -1, -1 }
};// 定义锐化滤波器float[,] kernel = new float[,]{{ 0, -1, 0 },{ -1, 5, -1 },{ 0, -1, 0 }};/// <summary>/// 图像增强/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button5_Click(object sender, EventArgs e){ImageEnhancement();var bitmap = enhanceImage.ToBitmap();ShowTxt(bitmap, label4);}private void ImageEnhancement(){if (inputImage == null){MessageBox.Show("需要添加图片");return;}int gksize = (int)numericUpDown4.Value;if ((gksize & 1) == 0){MessageBox.Show("需要为奇数");return;}enhanceImage = new Image<Bgr, byte>(inputImage.Size);// 应用高斯模糊滤波器CvInvoke.GaussianBlur(inputImage, enhanceImage, new Size(gksize, gksize), 0);using Matrix<float> kernels = new Matrix<float>(kernel);// 应用卷积操作CvInvoke.Filter2D(enhanceImage, enhanceImage, kernels, new Point(-1, -1));// 创建锐化滤波器的内核//using Matrix<float> kernelMatrix = new Matrix<float>(kernelData);// 应用锐化滤波器//CvInvoke.Filter2D(enhanceImage, enhanceImage, kernelMatrix, new Point(-1, -1));// 将图像转换为 YCrCb 颜色空间Image<Ycc, byte> yccImage = enhanceImage.Convert<Ycc, byte>();// 将 YCrCb 图像的亮度通道应用自适应直方图均衡化CvInvoke.CLAHE(yccImage[0], 40.0, new Size(8, 8), yccImage[0]);enhanceImage.Dispose();// 将 YCrCb 图像转换回 Bgr 颜色空间enhanceImage = yccImage.Convert<Bgr, byte>();ShowPictureBox(pictureBox5, enhanceImage);}/// <summary>/// 文字识别/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button6_Click(object sender, EventArgs e){//ExtractedText();}TesseractEngine engine = new TesseractEngine("D:\\个人\\tessdata-master", "eng", EngineMode.Default);private string ExtractedText(byte[] data){if (repairImage == null){MessageBox.Show("需要增强图像");return "";}// 加载图像using var image = Tesseract.Pix.LoadFromMemory(data);// 将图像传递给Tesseract引擎进行文字提取using var page = engine.Process(image);// 获取提取的文字string extractedText = page.GetText();//var mc = page.GetMeanConfidence();extractedText = FilterExtractedText(extractedText);return extractedText;}public byte[] BitmapToByteArray(Bitmap bitmap){using (MemoryStream stream = new MemoryStream()){bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);return stream.ToArray();}}public static Image<Bgr, byte> PerformTextCorrection(Image<Bgr, byte> inputImage){// 转换为灰度图像using Image<Gray, byte> grayImage = inputImage.Convert<Gray, byte>();// 进行边缘检测using Image<Gray, byte> edges = grayImage.Canny(50, 150);// 进行直线检测LineSegment2D[] lines = CvInvoke.HoughLinesP(edges, 1, Math.PI / 180, 100, 30, 10);// 计算所有直线的平均角度double averageAngle = lines.Average(line => Math.Atan2(line.P2.Y - line.P1.Y, line.P2.X - line.P1.X) * 180 / Math.PI);// 计算旋转中心PointF center = new PointF(inputImage.Width / 2f, inputImage.Height / 2f);// 创建旋转矩阵using Mat rotationMatrix = new Mat();CvInvoke.GetRotationMatrix2D(center, -averageAngle, 1.0, rotationMatrix);// 进行旋转using Image<Bgr, byte> rotatedImage = inputImage.WarpAffine(rotationMatrix, Inter.Linear, Warp.Default, BorderType.Constant, new Bgr(255, 255, 255));return rotatedImage;}private string FilterExtractedText(string extractedText){string txt = string.Empty;foreach (var item in extractedText){if (char.IsDigit(item))txt += item;else{int temp = (char)item;if (temp >= 65 && temp <= 90 || temp >= 97 && temp <= 122)txt += item;}}return txt;}}
相关文章:

C# Emgu.CV+Tesseract实现识别图像验证码
效果图,简单的还行,复杂的。。。拉跨 懒得写讲解了,全部源码直接上吧 /// <summary>/// 验证码识别/// </summary>public partial class FrmCodeIdentify : FrmBase{private string _filePath;// 原图像Image<Bgr, byte> …...
ORACLE 11.2.0.4 RAC Cluster not starting cssd with Cannot get GPnP profile
最近,处理一次oracle 11.2.0.4 rac cluster由于cssd无法启动,导致集群一个节点的CRS集群无法正常启动的故障。原本,计划变更是从ASM剔除磁盘,解除存储到数据库服务器的映射;磁盘已经成功从ASM剔除,也已经成…...

Converting Phase Noise to Random Jitter(Cycle-to-Cycle)
借用Phase Noise to Random Jitter(Period)的转换过程推导了Cycle to Cycle random Jitter,一般展频时钟调制,用来评估相邻周期的随机抖动。...
HashMap知识总结
HashMap: 1. 扰动函数hash值右移16位与原hash值做异或运算得出的新hash值散列程度高. 2. 负载因子0.75,就是说一个数组初始化new HashMap(17)容量会比17最小2的n次方大,就是32,想要已空间换时间,就是负载因子小于0.75这样的话hash冲突更低,但是扩容频率更高.3 扩容,jdk…...
PLC编码器测速(限幅滤波+中心差分法求导SCL源代码)
M法测速的基本原理,大家可以查看专栏的系列文章,这里不再赘述常用链接如下: PLC通过编码器反馈值计算速度的推荐做法(算法解析+ST代码)_编码器脉冲怎么转换为速度_RXXW_Dor的博客-CSDN博客PLC如何测量采集编码器的位置数据,不清楚的可以参看我的另一篇博文:三菱FX3U PLC…...

SW的stp文件转成CAD格式文件学习笔记
SW的stp文件转成CAD格式文件 文章目录 SW的stp文件转成CAD格式文件另存为part文件(零件图)另存为CAD文件 另存为part文件(零件图) 如图一个STP文件,右上角标注是什么文件呢 另存为零件图,即另存为part …...

【数据结构】栈---C语言版(详解!!!)
文章目录 🐸一、栈的概念及结构🍄1、栈的概念定义🍄2、动图演示🌲入栈🌲出栈🌲整体过程 🐸二、栈的实现🐸三、数组结构栈详解🍎创建栈的结构⭕接口1:定义结构…...
sqlserver 联表查询、子查询、窗口函数、聚合函数等概念与例子
with cte as的用法 查询的一个有用工具,允许创建临时命名结果集,可在查询中多次引用相同的子查询结果,可以提高查询的可读性和维护性 WITH cte_name (column1, column2, ...) AS (-- 这里是子查询SELECT column1, column2, ...FROM your_ta…...
GO学习之 消息队列(Kafka)
GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、GO学习之 网络通信(Net/Htt…...

搭建自己的OCR服务,第三步:PPOCRLabel标注工具安装
一、安装说明 安装好了PaddleOCR后,还需要安装PPOCRLabel这个标注工具,想要自己训练模型的话,有个标注工具会起很大作用。 尤其是PPOCRLabel就是跟PaddleOCR配套的标注工具,同样是开源的。 在下载 PaddleOCR 整个源码中&#x…...
Java学习笔记37——网络编程01
网络编程入门 网络编程入门网络编程概述网路编程的三要素ip地址InetAddress类的使用端口 网络编程入门 网络编程概述 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理…...
powershell 搜索文本并返回行号
目录 powershell 搜索文本并返回行号 python调用powershell搜索文本并返回行号; powershell 搜索文本并返回行号 $keyword PS dir "d:\" -Filter "*.txt" -Recurse | foreach {$line 0 $fileName $_.FullNameGet-Content $fileName | f…...

网络原理
网络原理 传输层 UDP 特点 特点:无连接,不可靠,面向数据报,全双工 格式 怎么进行校验呢? 把UDP数据报中的源端口,目的端口,UDP报文长度的每个字节,都依次进行累加 把累加结果&a…...
力扣(LeetCode)算法_C++——同构字符串
给定两个字符串 s 和 t ,判断它们是否是同构的。 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。 每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相…...

网管实战⑼:配置华为S5720交换机
配置好汇聚交换机后,需要根据单位情况配置具体的接入交换机。 自从2019年12月底配置好交换机后,基本上都没有怎么操作交换机了。那时候使用的是H3C交换机,主要是H3C S7706、H3C S5120、H3C S5130、H3C S5500、H3C S3600等型号的交换机&#x…...

文件上传漏洞第十六关十七关
第十六关 第十七关 第十六关 直接上传php文件判断限制方式: 同第十五关白名单限制 第十六关源码: 代码逻辑判断了后缀名、content-type,以及利用imagecreatefromgif判断是否为gif图片,最后再做了一次二次渲染 二次渲染图片马&…...
Try llama2 in NUC (by quqi99)
作者:张华 发表于:2023-09-06 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) 据说现在在PC机上可以运行llama2大模型了, Way 1 于是照…...

强大易用的开源 建站工具Halo
特点 可插拔架构 Halo 采用可插拔架构,功能模块之间耦合度低、灵活性提高。支持用户按需安装、卸载插件,操作便捷。同时提供插件开发接口以确保较高扩展性和可维护性。 ☑ 支持在运行时安装和卸载插件 ☑ 更加方便地集成三方平台 ☑ 统一的可配置设置表…...
如何使用vuex
1.安装vuex 2.在store文件夹内写index.js 此处tab是自定义的文件 import Vue from "vue" import Vuex from "vuex" import tab from "./tab"Vue.use(Vuex)export default new Vuex.Store({modules:{tab} }) 3.在store文件夹内写tab.js(自定义…...

动手深度学习——Windows下的环境安装流程(一步一步安装,图文并配)
目录 环境安装官网步骤图文版安装Miniconda下载包含本书全部代码的压缩包使用conda创建虚拟(运行)环境使用conda创建虚拟环境并安装本书需要的软件激活之前创建的环境打开Jupyter记事本 环境安装 文章参考来源:http://t.csdn.cn/tu8V8 官网…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...