C#实现简单验证码识别的思路与代码

认真发呆
认真发呆
发布时间:2026-10-14 | 2人浏览过
原创

利用 C# 的图形处理功能进行验证码识别,核心思路在于将图片转换为数据表后进行模式匹配。通过设定颜色阈值去除背景干扰,建立标准字符样本库,并在滑动窗口中进行区域对比评分,可实现高效的字符提取。

背景

在实际应用中,面对某些使用固定字体且无复杂扭曲变形的简易验证码,传统的 OCR 方案可能过于庞大。通过自定义的二值化算法配合特征匹配,可以在极短的时间内(通常低于 200ms)完成识别,且在特定样本下准确率可达 95% 左右。

准备条件

  • C# 运行环境,引用 System.Drawing 命名空间。
  • 目标验证码图片:建议使用背景噪点较少、字体统一的静态图片作为实验对象。

真实操作顺序

第1步:去背景噪音并进行二值化

目的:消除图片中的背景杂色,将像素点转化为“黑/白”布尔值,减少后续计算量并聚焦前景文字。

动作:遍历图像的每个像素,获取其 R、G、B 分量,判断三色之和是否小于设定的阈值(本例中设为 500),从而生成一个二维布尔数组 bool[,] table。

结果展示:

 

Code (C#):

private bool[,] ToTable(Bitmap bmp)
{
    var table = new bool[bmp.Width, bmp.Height];
    for (int i = 0; i < bmp.Width; i++)
        for (int j = 0; j < bmp.Height; j++)
        {
            var color = bmp.GetPixel(i, j);
            // 核心逻辑:RGB三元组之和低于500视为前景(通常为黑色文字)
            table[i, j] = (color.R + color.G + color.B < 500);
        }
    return table;
}

第2步:制作与加载字符样本

目的:由于计算机不具备认知能力,必须提供已知字符的“笔迹”数据来进行比对。针对某类系统天生 bug(如字体单一),可以预先提取所有可能出现的字符图样。

动作:将提取好的字符样本打包进程序中。为加快加载速度,可将包含坐标映射和字模信息的字节数组使用 GZipStream 压缩后硬编码进代码内部。

结果展示:

第3步:逐位滑动匹配

目的:从左向右依次确定当前横坐标对应的字符内容。

动作:

  1. 定位起点:找到当前位置之后第一个属于前景的列坐标。
  2. 搜索最佳匹配:在当前位置附近的一个扩展区域内(如上下偏移几个像素,左右微调),对每一个预置字符进行评分比较。
  3. 计分原则:预期有的地方有了加满分;缺了减分;不该有的却出现了适度扣分(本例扣 0.55);超出边界的不计入总得分。
  4. 推进指针:如果找到的匹配率高于设定阈值(例如 0.6),则将匹配到的字符加入结果串,并将扫描指针向右大幅跳跃(跳过已识别区域);否则仅前进一小格重试。

验证结果与优化

此算法基于简单的几何覆盖原理,不涉及深度学习训练或复杂的第三方库调用,因此执行速度极快且资源占用低。主要局限性在于无法处理严重扭曲、变形或非标准化的字体。对于此类特殊情况,需要引入更高级的骨架算法或卷积神经网络。以下为完整的测试示例源码:

实例源码

该代码演示了如何构建基础的验证码破解引擎:

using System.Collections.Generic;
using System.Drawing;
using System.IO; 
using System.IO.Compression;
namespace Crack12306Captcha
{
public class Cracker
{
List<CharInfo> words_ = new List<CharInfo>(); 
public Cracker() 
{
    // 省略大量压缩字节码...此处应放置实际生成的GZip流
    using (var stream = new MemoryStream(bytes)) 
    using (var gzip = new GZipStream(stream, CompressionMode.Decompress)) 
    using (var reader = new BinaryReader(gzip)) 
    { 
        while (true) 
        { 
            char ch = reader.ReadChar(); 
            if (ch == '\0') break;
            int width = reader.ReadByte(); 
            int height = reader.ReadByte(); 
            bool[,] map = new bool[width, height]; 
            for (int i = 0; i < width; i++)
                for (int j = 0; j < height; j++)
                    map[i, j] = reader.ReadBoolean(); 
            words_.Add(new CharInfo(ch, map)); 
        } 
    } 
}

// 读取验证码主入口
public string Read(Bitmap bmp) 
{
    var result = string.Empty;
    var width = bmp.Width; 
    var height = bmp.Height;
    var table = ToTable(bmp); // 转换为二维表
    var next = SearchNext(table, -1); 

    while (next < width - 7) 
    { 
        var matched = Match(table, next);
        // 若匹配度超过阈值则确认字符并跳转,否则微调位置
        if (matched.Rate > 0.6) 
        { 
            result += matched.Char; 
            next = matched.X + 10; // 向右推进大步伐
        } 
        else
        { 
            next += 1; 
        } 
    } 
    return result; 
} 

// 其他辅助函数ToTable, SearchNext, FixedMatch等...在此略
}
}
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表