验证码识别基础方法及源码
- 格式:doc
- 大小:297.00 KB
- 文档页数:10
验证码识别原理及实现方法验证码的作用:有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。
其实现代的验证码一般是防止机器批量注册的,防止机器批量发帖回复。
目前,不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了验证码技术。
所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息,输入表单提交网站验证,验证成功后才能使用某项功能。
我们最常见的验证码1,四位数字,随机的一数字字符串,最原始的验证码,验证作用几乎为零。
2,随机数字图片验证码。
图片上的字符比较中规中矩,有的可能加入一些随机干扰素,还有一些是随机字符颜色,验证作用比上一个好。
没有基本图形图像学知识的人,不可破!3,各种图片格式的随机数字+随机大写英文字母+随机干扰像素+随机位置。
4,汉字是注册目前最新的验证码,随机生成,打起来更难了,影响用户体验,所以,一般应用的比较少。
简单起见,我们这次说明的主要对象是第2种类型的,我们先看几种网上比较常见的这种验证码的图片.这四种样式,基本上能代表2中所提到的验证码类型,初步看起来第一个图片最容易破解,第二个次之,第三个更难,第四个最难。
真实情况那?其实这三种图片破解难度相同。
第一个图片,最容易,图片背景和数字都使用相同的颜色,字符规整,字符位置统一。
第二个图片,看似不容易,其实仔细研究会发现其规则,背景色和干扰素无论怎么变化,验证字符字符规整,颜色相同,所以排除干扰素非常容易,只要是非字符色素全部排除即可。
第三个图片,看似更复杂,处理上面提到背景色和干扰素一直变化外,验证字符的颜色也在变化,并且各个字符的颜色也各不相同。
看似无法突破这个验证码,本篇文章,就一这种类型验证码为例说明,第四个图片,同学们自己搞。
第四个图片,除了第三个图片上提到的特征外,又在文字上加了两条直线干扰率,看似困难其实,很容易去掉。
识别验证码通常是一个复杂的过程,因为验证码通常被设计成能够区分计算机程序和人类用户。
然而,有一些验证码可能相对容易通过机器学习或深度学习模型来识别。
下面是一个基本的例子,它使用Python的opencv库来识别验证码。
这个例子仅仅是一个简单的演示,并不能处理所有类型的验证码。
```pythonimport cv2import numpy as np# 读取图片img = cv2.imread('captcha.png', 0)# 二值化处理_, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 查找轮廓contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 遍历轮廓,尝试匹配每个字符for contour in contours:# 计算轮廓的边界框x, y, w, h = cv2.boundingRect(contour)# 提取字符图像char_img = img[y:y+h, x:x+w]# 尝试识别字符# 这里我们只是简单地将其转换为灰度图像并查找边界框gray = cv2.cvtColor(char_img, cv2.COLOR_BGR2GRAY)_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)if len(contours) > 0:# 如果找到轮廓,假设字符是字母或数字char = ''for cnt in contours:if cv2.contourArea(cnt) > 50:char = 'a' + str(len(char))else:char = '0' + str(len(char))print(char)```这个代码假设每个字符都是一个简单的形状,并且可以通过查找轮廓来识别。
python识别验证码——⼀般的数字加字母验证码识别1、验证码的识别是有针对性的,不同的系统、应⽤的验证码区别有⼤有⼩,只要处理好图⽚,利⽤好pytesseract,⼀般的验证码都可以识别2、我在识别验证码的路上⾛了很多弯路,重点应该放在怎么把图⽚处理成这个样⼦,⽅便pytesseract的识别,以提⾼成功率3、原图为:思想过程:①不要盲⽬的去直接⽤代码识别,识别不出来就怀疑代码有问题或者pytesseract不好⽤:先将验证码⽤图⽚处理⼯具处理,⼀步步得到理想图⽚,记住处理过程,将处理后的图⽚直接⽤pytesseract识别,代码如下:# -*- coding: UTF-8 -*-、import Imageimport pytesseractim = Image.open('31.png')aa = pytesseract.image_to_string(out)print aa②确定图⽚可以识别后,开始⽤代码复现你的图⽚处理过程# -*- coding: UTF-8 -*_from PIL import Imagefrom pytesseract import *import PIL.ImageOpsdef initTable(threshold=140):table = []for i in range(256):if i < threshold:table.append(0)else:table.append(1)return tableim = Image.open('31.png')#图⽚的处理过程im = im.convert('L')binaryImage = im.point(initTable(), '1')im1 = binaryImage.convert('L')im2 = PIL.ImageOps.invert(im1)im3 = im2.convert('1')im4 = im3.convert('L')#将图⽚中字符裁剪保留box = (30,10,90,28)region = im4.crop(box)#将图⽚字符放⼤out = region.resize((120,38))asd = pytesseract.image_to_string(out)print asdprint (out.show())先将图⽚转换为L模式然后去噪反转颜⾊将重要部分裁剪放⼤输出结果:。
验证码识别常用算法
验证码识别是一类复杂的计算机视觉任务,它通常用于识别用户输入的人类可读的文本或数字字符串,以确认用户的身份或进行其他保护性操作。
验证码识别的主要挑战之一是要求系统在较高的正确率下准确识别验证码,而同时又能抵御常见的攻击方法。
因此,有必要对验证码识别的常用算法进行介绍,以便设计出更加有效的验证码识别系统。
首先,需要介绍的是基于规则的验证码识别技术。
它的工作原理是,用户输入的验证码会根据其结构模式被识别出特定的规则。
比如,一个简单的验证码可能是由四个数字构成,系统会使用统一的规则将该验证码识别成四个数字形式的字符。
基于规则的验证码识别技术的主要缺点是,其能够识别出的验证码的类型太少,而且并不能有效地抵御攻击,如果验证码由攻击者知晓,然后可以通过算法将其破解,因此,基于规则的验证码识别不能有效地防止攻击。
其次,还有基于机器学习的验证码识别技术。
它的工作原理是使用机器学习算法学习历史数据,对输入的验证码进行分类和识别。
易语言验证码识别源码以下是一个使用易语言开发的简单验证码识别源码:```basic//图片预处理procedure preProcess(var img: TImage)varcolor1, color2, color3: int64;i, j: integer;begin//缩小图片img.SetRect(img.Width / 2, img.Height / 2, img.Width, img.Height);img.Save("temp.jpg");img.Clear;img.Load("temp.jpg");//灰度化处理for i := 0 to img.Width - 1 dobeginfor j := 0 to img.Height - 1 dobegincolor1 := img.GetPixel(i, j) and $FF;color2 := (img.GetPixel(i, j) shr 8) and $FF;color3 := (img.GetPixel(i, j) shr 16) and $FF;img.SetPixel(i, j, (color1 + color2 + color3) div 3); end;end;//二值化处理for i := 0 to img.Width - 1 dobeginfor j := 0 to img.Height - 1 dobeginif img.GetPixel(i, j) < 128 thenimg.SetPixel(i, j, 0)elseimg.SetPixel(i, j, 255);end;end;end;//切割验证码图片procedure splitImage(var img: TImage; var imgList: array of TImage)varlineWidth, i, j, k, start, endPos: integer;colStart: boolean;beginlineWidth := 1;colStart := false;start := -1;for i := 0 to img.Width - 1 dobeginfor j := 0 to img.Height - 1 dobeginif img.GetPixel(i, j) = 0 thenbeginlineWidth := 0;colStart := true;break;end;if colStart thenbreak;end;k:=0;for i := lineWidth to img.Width - 1 do beginlineWidth := 0;for j := 0 to img.Height - 1 dobeginif img.GetPixel(i, j) = 255 thenbeginlineWidth := 1;colStart := true;break;end;end;if (lineWidth > 0) thenif (start = -1) thenstart := i - 1;endelse if (colStart and (lineWidth = 0) and (start <> -1)) thenbeginendPos := i + 1;imgList[k].Create(endPos - start, img.Height, pic_gray);for j := 0 to img.Height - 1 dobeginimgList[k].CopyRect(img2, 0, 0, img, start, j, endPos, j + 1);end;inc(k);start := -1;end;end;end;//提取特征码function getFeatureCode(var img: TImage): string varcode: string;count, i, j: integer;begincode := '';count := 0;while count < 4 dobeginfor i := 0 to img.Width - 1 dobeginfor j := 0 to img.Height - 1 dobeginif img.GetPixel(i, j) = 0 thenbeginif i < img.Width - 1 thenimg.SetPixel(i, j, 255);if j < img.Height - 1 thenimg.SetPixel(i, j + 1, 255);code := code + '1';inc(count);break;end;end;if count > 0 thenbreak;end;end;result := code;end;//主程序varimgOriginal, imgPreprocessed: TImage;imgList: array [0..3] of TImage;featureCode: string;beginimgOriginal.Load("captcha.jpg"); // 加载验证码图片//预处理imgPreprocessed.Create(imgOriginal.Width, imgOriginal.Height, pic_gray);imgPreprocessed.CopyRect(imgOriginal, 0, 0, imgOriginal, 0, 0, imgOriginal.Width, imgOriginal.Height);preProcess(imgPreprocessed);//切割验证码splitImage(imgPreprocessed, imgList);//提取特征码featureCode := '';for i := 0 to 3 dobeginfeatureCode := featureCode + getFeatureCode(imgList[i]);end;MessageBox("", "验证码识别结果:" + featureCode);end.```这个源码实现了一个简单的验证码识别程序。
java识别验证码的方法
Java识别验证码的方法主要有以下几种:
1. 使用开源的OCR(Optical Character Recognition,光学字符识别)库,例如Tesseract。
Tesseract是一个强大的OCR引擎,可以识别多种语言的文本。
使用Tesseract识别验证码需要先对验证码进行预处理,例如二值化、去噪等,然后将处理后的图像输入到Tesseract中进行识别。
2. 使用机器学习算法,例如卷积神经网络(Convolutional Neural Network,CNN)或循环神经网络(Recurrent Neural Network,RNN)。
这些算法可以通过训练大量的验证码图片来学习识别验证码的规律,从而实现自动识别验证码。
3. 使用第三方服务,例如Google Cloud Vision API、Amazon Rekognition等。
这些服务提供了图像识别功能,可以识别出图像中的文字、物体等。
使用这些服务需要先上传验证码图片,然后调用相应的API进行识别。
无论使用哪种方法,都需要对验证码进行适当的预处理,以提高识别的准确率。
常见的预处理方法包括二值化、去噪、缩放等。
同时,需要注意保护用户隐私和数据安全,避免将用户数据泄露给第三方或用于其他用途。
常见的数字验证码识别方法
数字验证码识别是指识别数字验证码的过程,通常用于防止恶意注册、登录等行为。
以下是几种常见的数字验证码识别方法:
1.OCR识别:OCR识别是指使用光学字符识别技术对验证码中的字符进行识别。
OCR识别通常使用计算机视觉技术,通过分析图像中的像素点和线条来识别字符。
OCR识别速度快、精度高,但对于扭曲、变形、模糊等情况的识别效果较差。
2.人工神经网络识别:人工神经网络识别是指使用人工神经网络对验证码中的字符进行识别。
人工神经网络识别通常使用卷积神经网络(CNN)或循环神经网络(RNN)等深度学习模型,通过训练数据集来学习字符的特征,并进行识别。
人工神经网络识别准确度高,但需要大量的训练数据和计算资源。
3.基于规则的识别:基于规则的识别是指使用预定义的规则对验证码中的字符进行识别。
基于规则的识别通常使用模式匹配、字符串匹配等方法,通过匹配字符与预定义的规则来进行识别。
基于规则的识别速度快、易于实现,但对于复杂的验证码效果较差。
以上是几种常见的数字验证码识别方法,每种方法都有其适用范围和优缺点,需要根据具体的场景和需求选择合适的方法。
数字验证码的识别(一)无忧 | 2008-10-9 4:18:44数字验证码是最常见的验证码之一,抛却直接写在页面上的验证码,我们用JAVA程序实现一下数字验证码的识别数字验证码是最常见的验证码之一,抛却直接写在页面上的验证码,我们用JAVA程序实现一下数字验证码的识别数字验证码很多地方都会用到,我前段时间也写过一篇有关于生成验证码的文章,那是随机生成大小不一,颜色不一,形状不一的数字图识别,何谓规范?规范就是数字的大小几乎一致,颜色对比度挺高,没什么干扰线.识别的依据就是最最最基础的办法,比对,先取样,保存取最接近的那个结果.不过在比较之前必须得到图片里面的数据提取出来并适当地去除一些干扰.下面就是识别部份的代码:/** ImageCode.java* To change this template, choose Tools | Template Manager* and open the template in the editor. */package net.bccn.hadeslee.programfan;import java.awt.image.BufferedImage;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.StreamTokenizer;import .URL;import javax.imageio.ImageIO;/*** 验证码识别程序* @author hadeslee */public class ImageCode {private BufferedImage bi;private static int[][][] model=new int[5][10][208];//静态初始化块static{initNumModel();}/*** Creates a new instance of ImageCode public ImageCode() {initNumModel();}public String getNumber(InputStream is){try{bi= ImageIO.read( is );final StringBuffer sb=new StringBuffer();for(int i=0;i<4;i++){int[] data=this.getData(i);sb.append(this.doCheck(data));}return sb.toString();} catch(Exception exe){exe.printStackTrace();return "";}}/*** 重载的方法,根据传进来的参数得到返回的字符串 * @param bi* @return结果*/public String getNumber(BufferedImage bi){try{this.bi= bi;StringBuffer sb=new StringBuffer();for(int i=0;i<4;i++){int[] data=this.getData(i);sb.append(this.doCheck(data));}//System.out.println(sb.toString());return sb.toString();} catch(Exception exe){exe.printStackTrace();return "";}}/*** 静态初始化方法,* 用于初始化字模*/private static void initNumModel(){try{//System.out.println("初始化model");for(int i=0;i<10;i++){StreamTokenizer st=new StreamTokenizer(new InputStreamReader(ImageCode.class.getResourceAsStream("/net/bc st.whitespaceChars('#','#');st.whitespaceChars(',',',');st.eolIsSignificant(false);out:while(true){int token=st.nextToken();if(token==StreamTokenizer.TT_WORD){int who=0;int index=0;if(st.sval.equals("center")){who=0;}else if(st.sval.equals("left")){who=1;}else if(st.sval.equals("right")){who=2;}else if(st.sval.equals("up")){who=3;}else if(st.sval.equals("down")){who=4;}while(st.nextToken()==StreamTokenizer.TT_NUMBER){model[who][i][index++]=(int)st.nval;}st.pushBack();}else if(token==StreamTokenizer.TT_EOF){break out;}}}} catch(Exception exe){exe.printStackTrace();}//System.out.println("初始化结束model");}//通过传进来的字符串得到BufferedImage对象private BufferedImage getBI(String url){try {return ImageIO.read(new URL(url));} catch (IOException ex) {ex.printStackTrace();return null;}}/**根据索引得到*某一块的图像转为数组*的文件*/private int[] getData(int index){BufferedImage sub=bi.getSubimage(index*16,0,16,13);int iw=sub.getWidth();int ih=sub.getHeight();int[] demo=new int[iw*ih];for(int i=0;i<ih;i++){for(int j=0;j<iw;j++){demo[i*iw+j]=(sub.getRGB(j,i)==-1?0:1);}}return demo;}//根据传进来的数组,得到五个位置当中和差别最小的那个private int getMin(int who,int[] demo){int temp=208;for(int i=0;i<5;i++){int x=0;for(int j=0;j<demo.length;j++){x+=(model[i][who][j]==demo[j]?0:1);}if(x<temp){temp=x;}}//System.out.println("比对"+who+"最小值是"+temp);return temp;}//分析689或者0的方法,以免这几个数字混淆private int get689(int[] demo,int origin){boolean isLeft=false,isRight=false;int temp=-1;if((demo[75]==1&&demo[90]==1)||(demo[76]==1&&demo[91]==1)||(demo[58]==1&&demo[74]==1&&demo[90]==1)||(demo[59]==1&&demo[75]==1&&demo[91]==1)||(demo[60]==1&&demo[76]==1&&demo[92]==1)||(demo[28]==1&&demo[44]==1&&demo[60]==1)||(demo[27]==1&&demo[43]==1&&demo[59]==1)){isRight=true;}if((demo[131]==1&&demo[147]==1)||(demo[132]==1&&demo[148]==1)||(demo[133]==1&&demo[149]==1)){ isLeft=true;}if(isLeft&&isRight){temp=8;}else if(isLeft){temp=6;}else if(isRight){temp=9;}else{temp=origin;}if(temp==8&&(!((demo[103]==1&&demo[104]==1&&demo[105]==1&&demo[106]==1)||(demo[87]==1&&demo[88]==1&&demo[89]==1&&demo[90]==1)||(demo[103]+demo[104]+demo[105]+demo[106]+demo[87]+demo[88]+demo[89]+demo[90]>3)))){return temp=0;}return temp;}//比较传入的数据,返回最接近的值private int doCheck(int[] demo){int number=-1;int temp=208;for(int i=0;i<10;i++){int x=this.getMin(i,demo);if(x<temp){temp=x;number=i;}}//System.out.println("===========================================");if(number==6||number==8||number==9){number=this.get689(demo,number);}return number;}}数字验证码的识别(二)下面是一些字模的内容,把它保存成相应的文件,并能让程序找到就可以了.比如这是0的字模,它在不同位字模,以此类推.这些字模都是先取到样本,然后再分类的#center0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,#left0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0, 0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0, 0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0, 0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0, 0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0, #right0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,, 0,0, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0, #up0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, #down0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,在此算法的实现中主要是针对比较规范的验证码,然后还要针对外形比较相似的6890进行分辨,实现识别的方式有很多种,大家仁者见仁,智者见智吧.不过, 说句题外话,MOTO的识别就很牛,它对手写字体的支持都能达到很高的识别率,更不要说是正体了,这就是另外一个领域了.不是一两句代码就能搞得定的:)。
先说说写这个的背景
最近有朋友在搞一个东西,已经做的挺不错了,最后想再完美一点,于是乎就提议把这种验证码给K.O.了,于是乎就K.O.了这个验证码。
达到单个图片识别时间小于200ms,500个样本人工统计正确率为95%。
由于本人没有相关经验,是摸着石头过河。
本着经验分享的精神,分享一下整个分析的思路。
在各位大神面前献丑了。
再看看部分识别结果
是不是看着很眼熟?
处理第一步,去背景噪音和二值化
对于这一块,考虑了几种方法。
方法一,统计图片颜色分布,颜色占有率低的判定为背景噪音。
由于背景噪音和前景色区分并不明显,尝试了很多种取景方法都不能很好去除背景噪音,最终放弃了这种方法。
方法二,事后在网上稍微查了下,最近比较流行计算灰度后设定一个阈值进行二值化。
其实所谓的灰度图片原理是根据人眼对色彩敏感度取了权值,这个权值对计算机来说没有什么意义。
稍微想一下就可以发现,这两个过程完全可以合并。
于是乎我一步完成了去背景噪音和二值化。
阈值设置为RGB三分量之和到500。
结果非常令人满意。
处理第二步,制作字符样本
样本对于计算机来说是非常重要的,因为计算机很难有逻辑思维,就算有逻辑思维也要经过长期训练才能让你满意。
所以要用事先制作好的样本进行比较。
如果你仔细观察过这些验证码会发现一个bug,几乎大部分的验证码都是使用同样的字体,于是乎就人工制作了一套字体的样本。
由于上一步已经有去除背景噪音的结果,可以直接利用。
制作样本这一步有点简单枯燥,还需要细心。
可能因为你的一个不细心会导致某个符号的识别率偏低。
在这500个样本中,只发现了31个字符。
幸亏是某部门的某人员还考虑到了易错的字符,例如,1和I,0和O等。
要不然这个某部门要背负更多的骂名。
处理第三步,匹配
单个匹配用了最简单最原始的二值比较,不过匹配的是匹配率而不是匹配数。
我定义了相关的计分原则。
大原则是“该有的有了加分,该有的没了减分,不该有的有了适度减分,可达区域外的不算分”。
由于一些符号的部分区域匹配结果跟另一些符号的完整匹配结果相似,需要把单个匹配在一个扩大的区域内择优。
在一定的范围内,找到一个最佳匹配,这个最佳匹配就是当前位置对应的符号。
完成了一次最佳匹配,可以把匹配位置向右推进一大步,若找不到合适的最佳匹配就向右推进一小步。
处理第四步,优化和调整
任何一个算法都是需要优化和调整的。
现在要找到最佳参数配置和最佳代码组织。
这一步往往是需要花费最多时间和精力的。
处理第五步,验证结果
这一步呢,纯人力验证结果,统计出正确率。
思考
结果是出来了,代码也不多,效果也很理想。
搞这一行的,很多时候都想要通用的。
能否通用,很大程度上在于抽象层次。
本方法只是单纯的匹配,自然不能通用,但是方法和思想却是通用的。
具体案例具体分析。
至于扭曲文字、空心文字等,处理要复杂的多。
网上也有一些使用第三方图像库的方法,也许那些方法会比较通用。
等有空了有兴趣了继续搞一下这个主题。
源码
至于这个源码要不要发布,纠结了一段时间。
网上已经有类似的商业活动了,而且这个识别本身没有太大难度,再加上某系统天生的bug,此验证码本身就相当于没有设置,因此发布此代码,仅作于学习交流。
用法。