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 官网…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
