1、assert(img:ok(),下载验证码失败Crop(4 ,3 , 56 ,18 )save(c:testtest.jpg) -保存到硬盘-折分图片,指定一行四列img2,img3,img4,img5 = img:split(1,4);img2:test0001.jpg)img3:test0002.jpgimg4:test0003.jpgimg5:test0004.jpgimage.del(img);如何确定图片后缀名 在整个验证码识别过程中,格式与后缀名一定不能搞错,否则就会失败。通常:asp的验证码是bmp格式,php的验证码是png格式,其他验证码很多是jpg格式。简单的,在验证码上右
2、键点选“图片另存为”,就可以看到格式(不一定准确)。另外,你可以用UltraEdit等以二进制方式打开看文件头部首先下载:str = web.getURL(string.save( str,test.bin然后用UE打开test.bin看文件头部(第一行)jpg文件头部有 JFIF 字眼png文件头部 有 PNG 字眼gif文件头部有 GIF字眼如果你搞不清楚,这时候就不要指定后缀名/vwww.*.com/test.asp这样就可以下载了二、生成验证码样本数据库复制下面的代码并粘贴到fap程序的脚本区块内,然后点击回放运行,最后再点击读取源代码。你就可以在ApeML源代码最后面的数据区块中看到
3、生成的验证码样本了。将数据区块的内容复制需要使用验证码识别的fap模拟程序中覆盖数据区块即可。local tkey =A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0;-在字典中添加所有数字键for i =0,9,1 do tkey tostring(i) = 0;end;-如果一个字符有多个样本,例如 5A.jpg 5B.jpg 5C.jpgfor k,v in pairs(tkey) do if(#k)=2)then -如果元素键名不
4、是两位字符 tkeyk.A =0;BC tkeyk=nil;-删除单字符的键名 end;-k参数为键,v参数表示值 一个典型的tkeyle迭代器回调函数loadtkey = function(k,v) local img = image.new(); img:load(C:test.k.jpg assert(img:.n不是有效的图片bpp(1);bpp(24); -通过上面两句,轻松去掉验证码上的杂色杂点Crop( 1 , 0 , 9 , 10);-修剪单个字符median(2);-中值滤波进一步去杂点 tkeyk= string.encode( img:getBytes(*.jpg) ,
5、-因为转换到字符串还是二进制,所以用base64进行编码 image.del(img);-遍历表tkey的所有元素,调用loadtkey加载图片文件 for k,v in pairs(tkey) do loadtkey(k,v);-把所有图片保存到数据岛,ape:saveTable(tkey,验证码样本三、验证码识别将下面的代码添加到fap模拟程序最前面的init脚本区块中即可-从数据区块读取base64编码的图片数据codekey = ape:loadTable(local timg = ; -这是一个图像数组,用来储存还原后的验证码样本的图片数据-必须进行一个转换,因为codekey里面只
6、是base64编码的普通字符串,而timg 将是真正的图片对象(二进制数据)-还原到图片对象toImage = function(k,v) local str = string.decode( v ,-首先进行base64解码,将纯文本转换为二进制数据setBytes( str ,-将二进制数据还原为图像 timgk = img;-载入验证码样本tkey = ape: -验证样本 toImage(k,v); -转换为图像-转换图片验证码到字符串的函数function ImgToString(img) function test(imgX) -test是一个被包含在函数中的内部函数 sleep(
7、0); local limit = (60 * 20) + (60 * 20); -最小相似度 local关键字声明为局部变量 local chr = ; -读取的字符 -testimg是一个被包含在函数中的内部函数,作为table.foreach的回调函数,k参数表示键,v参数表示值 testimg = function(k,v) -调用image.testXX()函数得出相似度,类似的函数还有image.testX() image.test() local n = imgX:testXX(timgk); if(nlimit)then -比较最小相似度 limit = n; chr = k.
8、 -遍历timg表,并调用testimg函数 for k,v in pairs(timg) do testimg(k,v); return string.left(chr,1); -返回读取到的字符串首字符(如果每个字符有多个样本) -修剪图片 image.Crop(img, 4 ,3 , 56 ,18 ) -上面的过程必须与下载样本时的代码完全一致。 -使用split函数分割图片 local img2,img3,img4,img5 = img: win.messagePrint(正在检测图片,请稍候. return test(img2).test(img3).test(img4).test(
9、img5);需要识别验证码的地方添加类似下面的代码:img = image.new() -因为刷新了验证码与页面不一致,把验证码画到屏幕上local x,y = mouse.getPos()paint(x,y,60 ,20 )local str = ImgToString(img);-下面我们把验证码的每个字符都转换为大写,并控制键盘顺序按键code1 = string.upper( string.sub(str,1,1) );code2 = string.upper( string.sub(str,2,2) );code3 = string.upper( string.sub(str,3,3
10、) );code4 = string.upper( string.sub(str,4,4) );key.press(100,code1,code2,code3,code4);上面我们用了模拟按键的方法输入验证码。实际上大多时候可以用更简单的方法,如下:ele = wb:getEle(验证码控件名字ele:setAttribute(value,str)为什么我的验证码与页面上不一样因为我们使用img:getURL读取验证码时已经刷新了验证码。所以验证码与页面上显示的并不一样,您只需要识别最新的验证码即可。如何直接获取页面的上图片,而不是重新下载有些验证码是绑定页面的,必须识别页面上的验证码才行。
11、那么可以使用image.capture函数直接抓屏屏幕上的图片即可。请参考:image.capture函数。更好的方法是使用ele:exec(Copy)函数直接拷贝页面上的图片到剪贴板。然后使用 img:getClipBD() 获取图片。请参考:)函数 img:getClipBD()函数四、关于剪切图片看上面的示意图,Crop就是选取绿色方框内的区域去清除绿色方框外面的区域必须保证里面的面积正好可以平均分成四块(假设这里是四个验证码字符)这样以后调用 img:split(1,4) 就正好分成四个字符了分成四份的小图片其宽度应当正好是上面的红色小方块的宽度。高度与绿色方框一样,我这里画的参次不齐
12、是为了让大家看清楚。如果你Crop的参数值不对,那么split就出错了下载验证码图片以后,可以使用图像编辑软件打开高倍放大。五、使用种子填充算法去除验证码上的干扰线模拟精灵识别验证码的能用是强大的,一个函数即可以去除杂色杂点。bpp(1)bpp(24)经过上面两句代码的处理,速度很快,所有背景、干扰点、杂色荡然无存。但是有时候验证码中有大量的干扰线,并且位置随机变动的太历害,这时候我们在处理验证码以前首先去除这些干扰线并准确的去除背景提取字符下面是一个模拟精灵初步处理后的验证码图片已经去除了杂色、杂点但是上面还是有干扰线一个可选的办法是用中值滤波再处理一下。 一个函数调用就可以,但是这样虽然去
13、掉了干扰线,原来的字符也被少量的破坏了。下面是使用种子填充算法去除干扰线的源代码,不但能去除杂点,而且可以去除周围的空白(提取位置随机变化的验证码),稍加修改还能有更多的用途下面是自动处理以后的效果下面是全部的源代码:-用一个table结构x=0; y=0表示图像上的坐标点用一组点构成table结构表示图像上的一条线。所有相连的黑色的点被认为是一条连通线。找出最长的一条连通线,被认为是字符,其他的认为是杂点。算法原理与种子填充算法相似。首先让用img:bpp函数处理为黑白图片,并初步去除杂色。先找到一个黑点,创建一个表示坐标点对象,并添加到连通线中。然后在黑点周围8个点中,再找黑色的点,找到就
14、添加到连通线,这样一直递归下去直到遍历图像所有点,可能有几块。清除杂点使用方法image.scan(img);清除杂点并切去掉周围的空白image.scan(img,true);-function image.scan(img,crop) -用一个table数组记录所有的连通线image.scan 的参数必须是一个有效的图片 local tlines =; -首先计算出图片的高度宽度,避免重复的调用 local w = img:width(); local h = img:height(); -以table形式定义一个数组,对应图象中的每个点。 作用相当一个开关,首先值为false,但黑点首次
15、被遍历到时。把这个值变为true。 下次,再找到这个点时忽略。避免重复加入连通线。 - local tchked =; for i=0,w,1 do tchkedi=; for j=0,h,1 do tchkedij=false; -去噪 -首先计算出各点的颜色值,避免在循环递归中重复的取 local tcl=; for i=0,w,1 tcli=; tclij=img:getPos(i,j); - 算点数函数 参数x,y 坐标 参数tab 所属连通线; - localfunction seed(x,y,tab) -出界了则返回 if(x0or yw or yh)then return; -点
16、的颜色为白色时,返回,不处理。 if(tclxy=16777215) -值为1,则计数加1,返回 if( tchkedxy) return ; else table.insert(tab,x=x,y=y-添加到连通线里 tchkedxy=true;-当值为0时,把值置为1。 seed(x+1,y-1,tab); seed(x,y-1,tab); seed(x-1,y-1,tab); seed(x-1,y,tab); seed(x+1,y,tab); seed(x-1,y+1,tab); seed(x,y+1,tab); return seed(x+1,y+1,tab); -这里可以用一个尾调用
17、(参考教程中的函数部份),加快递归的速度。 - -遍历图像中的所有点 -如果是黑色的点,而且没有被计过数,则调用seed函数。 if(tclij=0and(not tchkedij)then local tab = seed(i,j,tab); table.insert(tlines,tab); -添加一条连通线 -现在tlines 里记录了的有的连通线,我们现在需要根据连通线的长度排序 sproc = function(l,l2) returntable.maxn(l) table.maxn(l2);-长的连通线排到前面 table.sort(tlines,sproc) -把图像全部画成白色
18、的点 for j=0,h,1setPos( i , j, 16777215); -然后把最长的一条连通线画上去 for i,point inipairs(tlines1)setPos( point.x, point.y , 0); -如果需要去掉周围的空白 if(crop)then local n = table.maxn(tlines1) -排序最长连通线中的所有坐标点 function(pt,pt2) return (pt.x pt2.x );-*左的排前面 table.sort(tlines1,sproc); local x,x2 = tlines11.x, tlines1n.x;(pt.y pt2.y );-*上的排前面 local y,y2 = tlines11.y, tlines1n.y;Crop( x,y,x2+1,y2)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1