C# Emgu.CV+Tesseract实现识别图像验证码

news2024/9/30 3:27:47

效果图,简单的还行,复杂的。。。拉跨

懒得写讲解了,全部源码直接上吧

/// <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;
        }
    }

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

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

相关文章

基于Python开发的DIY字符画程序(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)

一、项目简介 本项目是一套基于Python开发的DIY字符画程序&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&…

Kafka3.0.0版本——消费者(消费者组初始化流程图解)

一、消费者组初始化流程图解 每个consumer都发送JoinGroup请求&#xff0c;如下图所示&#xff1a; 选出一个consumer作为leader&#xff0c;如下图所示&#xff1a; 把要消费的topic情况发送给leader 消费者&#xff0c;如下图所示&#xff1a; leader会负责制定消费方案…

MFC:自绘CListBox,GetText返回一个乱码

问题描述 自绘CListBox&#xff0c;GetText返回一个乱码&#xff0c;并且还会伴随以下断言 解决方案 ListBox Control 属性【Has Strings】改为True即可

【线程池处理任务】Runnable任务和Callable任务

线程池处理任务 ExecutorService的常用方法 方法名称说明void execute(Runnable command)执行 Runnable 任务Future< T > submit(Callable< T > task)执行 Callable 任务&#xff0c;返回未来任务对象&#xff0c;用于获取线程返回的结果void shutdown()等全部任…

前端,关于一个骚气的页面阅读定位图(菜单)

之前在网上看到一个特别骚气的页面阅读定位菜单&#xff0c;今天给大家分享一下原理&#xff0c;先看效果图&#xff1a; 这是我之前浏览联想官网上看到的一个效果图&#xff0c;觉得相当骚气。然后我把他的背景图扣下来&#xff0c;也做了一个&#xff0c;看看效果。 他的实现…

接口自动化测试总结

一、什么项目适合做自动化测试&#xff1f; 软件需求变动不频繁 测试脚本的稳定性决定了自动化测试的维护成本。如果软件需求变动过于频繁&#xff0c;测试人员需要根据变动的需求来更新测试用例以及相关的测试脚本&#xff0c;而脚本的维护本身就是一个代码开发的过程&#x…

【SpringCloudAlibaba】Seata分布式事务使用

文章目录 分布式事务问题示例Seata概述、官网一个典型的分布式事务过程处理过程全局GlobalTransactional分布式交易解决方案流程图 Seata安装下载修改conf目录下的application.yml配置文件dashboard demo 分布式事务问题示例 单体应用被拆分成微服务应用&#xff0c;原来的三个…

详解Transformer中的Encoder

一.Transformer架构 左半边是Encoder&#xff0c;右半边是Decoder。 二.Vision Transformer Vision Transformer取了Transformer的左半边。包含 Input EmbeddingPositional Encoding多头注意力机制 Add & Norm(前馈网络)Feed Forward Add & Norm 2.1 Input Embe…

C51智能小车(循迹、跟随、避障、测速、蓝牙、wifie、4g、语音识别)总结

目录 1.电机模块开发 1.1 让小车动起来 1.2 串口控制小车方向 1.3 如何进行小车PWM调速 1.4 PWM方式实现小车转向 2.循迹小车 2.1 循迹模块使用 2.2 循迹小车原理 2.3 循迹小车核心代码 3.跟随/避障小车 3.1 红外壁障模块分析​编辑 3.2 跟随小车的原理 3.3 跟随小…

世界级黑客丨电脑犯罪界的汉尼拔

被美国FBI称为电脑界的汉尼拔的人&#xff0c;有什么样的故事&#xff1f; 这个人就是世界级黑客凯文李波尔森&#xff0c;他在早期是正儿八经的黑客&#xff0c;他在17岁的时候就使用TRS-80电脑攻入美国国防部的高等研究计划署网络&#xff0c;但是当时他进去啥也没干&#x…

lambda nodejs 函数降低冷启动时间的最佳实践

lambda nodejs 函数降低冷启动时间的最佳实践 lambda nodejs 函数降低冷启动时间的最佳实践 前言什么是冷启动时间打包服务端 js什么是 inline进一步封装的打包工具存在的弊端以及解决方案Next Chapter完整示例及文章仓库地址 前言 本文章的思路&#xff0c;继承发展自这两篇…

vite vue项目 运行时 \esbuild\esbuild.exe 缺失 错误码 errno: -4058, code: ‘ENOENT‘,

vite vue项目运行 npm run dev 报错某个模块启动文件丢失信息 D:\PengYe_code\2\vite-vue3-admin>npm run dev> vite-vue3-admin1.0.2 dev > vitenode:events:504throw er; // Unhandled error event^Error: spawn D:\PengYe_code\2\vite-vue3-admin\node_modules\vi…

jupyter 添加中文选项

文章目录 jupyter 添加中文选项1. 下载中文包2. 选择中文重新加载一下&#xff0c;页面就变成中文了 jupyter 添加中文选项 1. 下载中文包 pip install jupyterlab-language-pack-zh-CN2. 选择中文 重新加载一下&#xff0c;页面就变成中文了 这才是设置中文的正解&#xff…

出现Browse information of one xxxx解决方法

不良现象如下&#xff1a; Browse information of one or more files is not available: Doing a project rebuild might fix this. 解决的方法&#xff1a;将C文件里面的内容全部注释掉&#xff0c;再编译正常。 然后再将注释掉的代码打开&#xff0c;再次编译就正常了。

【笔试强训选择题】Day35.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01; 文章目录 前言 一、Da…

什么是互联网打工人都需要知道的API?

我们生活在一个科技主导的世界。在这里&#xff0c;数据无处不在。作为许多不同产品的用户&#xff0c;我们所追寻的不再是某一个能将工作完成的最佳产品&#xff0c;而是一个不仅能有效完成工作&#xff0c;同时也与我们所使用的其他工具完美兼容的产品。因此&#xff0c;了解…

08-JVM垃圾收集器详解

上一篇&#xff1a;07-垃圾收集算法详解 如果说收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。 虽然我们对各个收集器进行比较&#xff0c;但并非为了挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现&#xff0c;更加没…

Web安全研究(四)

No Honor Among Thieves: A Large-Scale Analysis of Malicious Web Shells Stony Brook University Ruhr-University Bochum 数据集地址&#xff1a;https://github.com/HACHp1/CWSOGG_dataset Web shell作为恶意脚本&#xff0c;攻击者将其上传到被攻陷的Web服务器&#xff…

iTunes备份文件在哪?苹果手机怎么恢复iTunes备份?

iTunes是苹果手机的一个常见应用&#xff0c;很多小伙伴都使用它来备份手机上的重要数据。通过iTunes备份数据到电脑后还可以进行随时管理和查看。itunes备份文件在哪&#xff1f;手机数据丢失怎么恢复iTunes备份&#xff1f;接下来&#xff0c;本文将给大家介绍一下&#xff0…

javaweb03-js基础

文本中涉及的一些基础介绍&#xff0c;不是全的。只写一些最常见、最经常使用的&#xff0c;其他的想了解可以自行查找资料。 前言&#xff1a; script引入 内部引用 script 外部引用 script:src 一、js语法 1.编写语法 &#xff08;1&#xff09;区分大小写&#xff0c;建议…