用PHP实现简单验证码识别


在浏览blog的时候淘到的一个不错的应用–简单验证码识别。

原文地址:http://www.rrgod.com/technique/871.html

写了个简单验证码的识别程序,分享下。基本步骤就是二值化、去噪点、取字符、做字模库,最后利用字模库实现验证码识别

部分代码如下:

<?php
header('Content-type:text/html;charset=uft-8');

define('WORD_SPACING',9);//字符间距
define('LEFT',10);
define('TOP',9);
define('HEIGHT',15);
define('WIDTH',10);
define('COLOR', 215);//二值化阀值

$filePath = $_GET['p'].'.png';
list($width,$height) = getimagesize($filePath);
$rs = imagecreatefrompng($filePath);
$sourceData =array();

//取特征值
for ($i=0; $i < $height; $i++) {
	for ($j=0; $j < $width; $j++) {
		$index = imagecolorat($rs, $j, $i);
		$rgb = imagecolorsforindex($rs, $index);
		//print_r($rgb);
		if ($rgb['red']>COLOR && $rgb['blue']>COLOR && $rgb['green']>COLOR) {
			//echo '1';
			$sourceData[$i][$j]=0;
		}else{
			//echo '0';
			$sourceData[$i][$j]=1;
		}
	}
}

//去噪点 阀值5
function clear($sourceData){
	$desData = array();
	$h =count($sourceData,0);
	$w =count($sourceData[0]);

	for ($i=1; $i < $h-1; $i++) {
		for ($j=1; $j < $w-1; $j++) {
			$value = $sourceData[$i-1][$j]+$sourceData[$i+1][$j]+$sourceData[$i][$j-1]+$sourceData[$i][$j+1]
                +$sourceData[$i-1][$j-1]+$sourceData[$i+1][$j+1]+$sourceData[$i-1][$j+1]+$sourceData[$i+1][$j-1];
			if ($value>=5) {
				$desData[$i-1][$j-1] = 1;
			}else{
				$desData[$i-1][$j-1] = 0;
			}
		}
	}
	return $desData;
}

//字符分割
function getCH($data){

	//第一个左上角坐标
	$x = LEFT -1;
	$y = TOP -1;

	$ch=0;
	for ($i=$y; $i < $y + HEIGHT; $i++) {
		for ($j=$x; $j < $x + WIDTH; $j++) {
			$chData[0][$ch] = $data[$i][$j];
			$ch++;
		}
	}

	$ch=0;
	for ($i=$y; $i < $y + HEIGHT; $i++) {
		for ($j=$x + WIDTH + WORD_SPACING; $j < $x + 2 * WIDTH + WORD_SPACING; $j++) {
			$chData[1][$ch] = $data[$i][$j];
			$ch++;
		}
	}

	$ch=0;
	for ($i=$y; $i < $y + HEIGHT; $i++) {
		for ($j=$x + 2*(WIDTH + WORD_SPACING); $j < $x + 3 * WIDTH + 2 * WORD_SPACING; $j++) {
			$chData[2][$ch] = $data[$i][$j];
			$ch++;
		}
	}

	$ch=0;
	for ($i=$y; $i < $y + HEIGHT; $i++) {
		for ($j=$x + 3*(WIDTH + WORD_SPACING); $j < $x + 4 * WIDTH + 3 * WORD_SPACING; $j++) {
			$chData[3][$ch] = $data[$i][$j];
			$ch++;
		}
	}

	return $chData;
}

/*显示
foreach ($desData as $value) {
	foreach ($value as $v) {
		if($v==1){
			echo '■';
		} else{
			echo '□';
		}//echo $v;
	}
	echo "<br />";
}*/

/*学习功能 制作字模库
foreach ($chData as $value) {
	echo "'";
	foreach ($value as $v) {
		echo $v;
	}
	echo "',<br />";
}*/

//识别验证码
function vertifyCode($chData){

	//字模
$typehead = require './zimo.php';

	$ch = array();
	$w = count($chData[0]);
	/*单个字符识别
	for ($i=0; $i < 10; $i++) {
		$mount=0;
		for ($j=0; $j < $w; $j++) {
			if ($chData[0][$j]==$typehead[$i][$j]) {
				$mount++;
			}
		}
		if ($w-$mount<15) {
			$ch[0]=$i;
			break;
		}
	}*/

	for ($i=0; $i < 4; $i++) {
		$result = array();
		for ($k=0; $k < 10; $k++) {
			$mount = 0;
		if (!is_array($typehead[$k])) {
			for ($j=0; $j < $w; $j++) {
				/*
				if (is_array($typehead[$k])) {
					$subMount = 0;
					foreach ($typehead[$k] as $v) {
						for ($m=0; $m < $w; $w++) {
							if ($chData[$i][$m] == $v[$m]) {
								$subMount++;
							}
						}
						$sub[]=$subMount;
					}
					$mount = max($sub);

				} else {*/
					if ($chData[$i][$j]==$typehead[$k][$j]) {
						$mount++;
					}
				//}
			}
		}else{
			foreach ($typehead[$k] as $v) {
				$subMount = 0;
				$sub = array();
				for ($m=0; $m < $w; $m++) {
					if ($chData[$i][$m] == $v[$m]) {
						$subMount++;
					}
				}
				$sub[]=$subMount;
			}
			$mount = max($sub);
		}


			if ($w-$mount<3) {
				$ch[$i]=$k;
				break;
			}else{
				$result[$k]=$w-$mount;
			}
		}
		//未匹配成功则取最优结果
		if (!isset($ch[$i])) {
			$ch[$i]=current(array_keys($result,min($result)));
		}
	}

	return $ch;
}

$desData = clear($sourceData);
$chData = getCH($desData);
$digtal = vertifyCode($chData);

$resul = '';
foreach ($digtal as $v) {
	$resul .= $v;
}

//输出识别结果
echo '识别结果:',$resul;

/*test
foreach ($desData as $value) {
	foreach ($value as $v) {
		echo $v;
	}
	echo "<br />";
}
*/

/*test
$im = imagecreate($width-OFFSET_X-RIGHT, $height - OFFSET_Y - BOTTOM);
$black = imagecolorallocate($im, 0, 0, 0);
$white = imagecolorallocate($im, 255, 255, 255);
$h = count($desData,0);
$w = count($desData[0]);

for ($i=0; $i < $h; $i++) {
	for ($j=0; $j < $w; $j++) {
		if ($desData[$i][$j]==1) {
			imagesetpixel($im, $j, $i, $white);
		}
	}
}
header("Content-type: image/jpeg");
imagejpeg($im);
*/


?>

完整程序下载:yzm

测试URL:http://127.0.0.1/yzm/index.php?p=文件名
测试例子:http://127.0.0.1/yzm/index.php?p=1

结合之前学习的EMlog博客验证码生成的PHP代码,貌似要被这次的识别程序给完爆啊……

, ,

《 “用PHP实现简单验证码识别” 》 有 15 条评论

  1. https://github.com/topics/ocr

    超轻量级中文ocr,支持竖排文字识别, 支持ncnn、mnn、tnn推理 ( dbnet(1.8M) + crnn(2.5M) + anglenet(378KB)) 总模型仅4.7M
    https://github.com/DayBreak-u/chineseocr_lite

    开源易用的中文离线OCR,识别率媲美大厂,并且提供了易用的web页面及web的接口,方便人类日常工作使用或者其他程序来调用~
    https://github.com/alisen39/TrWebOCR

    Ready-to-use OCR with 80+ supported languages and all popular writing scripts including Latin, Chinese, Arabic, Devanagari, Cyrillic and etc.
    https://github.com/JaidedAI/EasyOCR

    Pure Javascript OCR for more than 100 Languages
    https://github.com/naptha/tesseract.js

  2. 滑动验证码协议通用解决方案
    https://vipread.com/library/topic/3749
    https://bbs.pediy.com/thread-272562.htm
    `
    验证码在大数据风控中中是比较常见的区分人机的方案,如何绕过验证码成了许多爬虫工程师比较头疼的问题。

    本次主题将从浏览器的”上帝视角”出发,介绍如何用整体思想来逆向分析解决验证码中的轨迹加密,监控浏览器中的api调用来模拟执行代码中的关键函数,从而实现”黑盒”调用的目的,启发风控工程师研发更为强大的滑动验证码引擎,提升网站的安全水平,保护企业数据。

    验证码协议初步分析
    利用开发者工具回溯堆栈
    回溯时碰到混淆代码可以利用控制台解密初步判断代码作用
    找到目标对象和轨迹数组
    hook构造函数定位对象创建位置
    整体调用思想
    监控Node中的环境调用
    监控浏览器中的环境调用
    浏览器中事件机制模拟
    验证码流程总结
    `

  3. windows 平台 ocr 软件有什么好的选择
    https://www.v2ex.com/t/936159
    `
    我现在用的是天若 ocr 调用百度的接口,速度还可以就是准确率差点。微信电脑版点开图片自带 ocr 准确率挺高的,v 友有什么好建议?
    ==

    免费,不要钱,安装方便且没广告,识别率还高的。只有 qq 微信
    =
    白描,这个收费几块钱吧,但识别准确度很好;
    然后 gitee 上还有一个天若 OCR 离线版,我之前用的比较多,应该也是够用的;
    现在我主要用的 quicker ,里面有个 OCR 动作,但是这个软件功能太多了,单纯 OCR 的话可能不太推荐专门去下这个
    =
    PowerToys 里的 OCR 一言难尽,好像是调的 windows 系统级的 OCR 。目前看来是最拉跨的。被苹果和微信的 OCR 吊打
    =
    上次找了一个 汉王 PDF OCR ,似乎挺牛逼的,转换出来的是真正的 word 文档,不是图片。不知道跟原始的格式是否有关系。
    =
    微信电脑版的 ocr 识别目前用起来很顺手
    =
    QQ 截图是云识别,这个识别率高!
    =
    一哥是毛子的 abbyy
    =
    翻了翻书签,找到了下面几个 OCR 相关的,你可以挨个试试(记得移除地址中的空格)。

    这四个都是离线的 OCR 软件(最后一个是 天若 OCR 离线版):
    https://github.com/xushengfeng/eSearch
    https://github.com/hiroi-sora/Umi-OCR
    https://github.com/xksoft/OcrHelper
    https://gitee.com/wanglifree/tianruoocr-cl

    这个我记得是论坛里人做的,虽然是个在线网站,但都是在浏览器端本地实现的 OCR:
    https://ocr. zjyl1994. com

    这个支持 OCR 但没说是离线还是在线的:
    https://gitee. com/smartoldfish/ocr-assistant
    ==

    tesseract 怎么样?没怎么用过,有没有用过的大哥讲一下?
    =
    tesseract 本身挺好,但是用起来并不方便。这玩意性能不弱,架构不落后,功能接口丰富,背后也一直有大厂在推着它走。但是,喂给它的图像必须够清晰,换句话说,预处理这块,它不负责。排版、格式、方向的识别,也是,它不负责,虽然它也提供这方面的功能接口,但用户得自己构建前置处理的环节。总之,这东西,不是傻瓜化的开箱即用的解决方案。字符清晰、明暗统一、排列整齐的文本图片,它能给出让人满意的结果,否则的话,消化不良。
    ==

    要么各种大厂的云端接口,免费或者付费,但说实话其实良莠不齐,各有短板。
    你还可以试试 EasyOCR ,我玩过还行,不过跟 paddleocr 一样,基于机器学习,所以设备算力不能太弱。
    或者就拿 tesseract 自己折腾。
    abbyy 是绝对的独一档,不过不知道它有没有编程调用接口。

    然后,提供个邪门,你知道漫画汉化这块吗,对 OCR 的需求很大。过去技术欠发展那也没人多寻思,都是汉化组手工修图、人肉翻译校对润色。但现在有了一整套自动化、半自动化方案,从图片预处理、去噪锐化拉伸、画面增强、角度扶正,到文字区识别、语言自动监测、多方 API 并行调用、格式排版自动识别,最后按照原图上的文本位置和排版自动将译文嵌入图中,用户只要手动选择、编辑、润色一下,讲真搞这玩意的那帮人虽然离第一梯队还有距离,但是完成度相当牛逼。社区驱动能做到这种程度,背后的需求肯定很大,搞不好成人色情漫画的汉化需求也是个大头。不过不是完全开源的,还收费,但如果能跟背后的团队联系上的话不妨去取取经。

    ==
    之前也想找个离线的 ocr ,找着找着发现微信跟飞书的截图都支持 ocr 了。。遂放弃
    `

  4. 巴西那边讲葡萄牙语的比较多,因此用Tesseract对于巴西那边的聊天图片解析需要用参数指定一下语言
    tesseract -l por+eng

    Codes for the Representation of Names of Languages (Codes arranged alphabetically by alpha-3/ISO 639-2 Code)
    https://www.loc.gov/standards/iso639-2/php/code_list.php
    `
    ISO 639-2 Code | ISO 639-1 Code | English name of Language | French name of Language | German name of Language
    por | pt | Portuguese | portugais | Portugiesisch
    `

    ISO 639-2 Language Code List
    https://localizely.com/iso-639-2-list/

  5. 通用端到端OCR模型开源,拒绝多模态大模型降维打击
    https://www.qbitai.com/2024/09/189611.html
    `
    在AI-2.0时代,OCR模型的研究难道到头了吗!?(OCR:一种将图像中的文字转换为可编辑和可搜索文本的技术)

    Vary作者团队开源了第一个迈向OCR-2.0的通用端到端模型GOT。

    用实验结果向人们证明:No~No~No~
    ==

    研究团队称,尽管GOT模型表现不错,但也存在一些局限,如更多的语言支持,更复杂的几何图,chart上的OCR性能。

    他们说OCR-2.0的研究还远的很,GOT也还有不小提升空间(该项目在数据和算力资源上都是非常受限的)。

    正是因为深知GOT以及OCR-2.0的潜力,我们希望通过开源GOT吸引更多的人,放弃VQA,再次投向强感知。都说纯OCR容易背锅,但也正好说明做的不够work,不是吗?
    ==

    GOT: Towards OCR-2.0
    通用OCR模型须要够通用,体现在输入输出都要通用上。

    GOT的通用具体表现为:在输入方面,模型支持Scene Text OCR、Document OCR、Fine-grained OCR、More General OCR等任务。

    关于为什么在大模型相互梭哈的时代继续研究OCR?

    研究团队有他们自己的理由:

    OCR一直是离落地最近的研究方向之一,是AI-1.0时代的技术结晶。

    到了以LLM(LVLM)为核心的AI-2.0时代,OCR成了多模大模型的一项基本能力,各家模型甚至有梭哈之势。

    多模态大模型作为通用模型,总有种降维打击OCR模型的感觉。

    那么纯OCR的研究真的到头了吗?我们想说:当然没有!没准才刚刚开始。

    首先盘一下AI-1.0 OCR系统和LVLM OCR的缺点:

    首先是AI-1.0流水线式的OCR系统,缺点不用多说,各个模块比较独立,局部最优,维护成本也大。

    最重要的是不通用,不同OCR任务需路由不同模型,不太方便。

    那么多模态大模型在pure OCR任务上有什么缺陷呢?我们认为有以下两点:

    1、为Reasoning让路必然导致image token数量过多,进而导致在纯OCR任务上存在bottle-neck。

    Reasoning(VQA-like)能力来自LLM(decoder),要想获得更好的VQA能力(至少在刷点上),就要充分利用起LLM来,那么image token就得越像text token(至少高维上,这样就会让LLM更舒服)。

    试想一下,100个text token在LLM词表上能编码多少文字?那么一页PDF的文字,又需要多少token呢?不难发现,保VQA就会导致在做OCR任务上,尤其是dense OCR任务上,模型搞得比较丑陋。

    例如,一页PDF图片只有A4纸大小,很多LVLM要都需要切图做OCR,切出几千个image token。单张都要切图,拿出多页PDF拼接图,阁下又当如何应对?

    我们认为对于OCR模型这么多token大可不必。

    2、非常直观的一点就是模型太大,迭代困难。

    要想引入新OCR feature如支持一项新语言,不是SFT一下就能训进模型的,得打开vision encoder做pre-training或者post-training,这都是相当耗资源的。

    对于OCR需求来说太浪费了。

    有人会说,小模型能同时做好这么多OCR任务吗?

    我们的答案是肯定的,而且甚至还能更好
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注