PHP圖像識(shí)別技術(shù)原理與實(shí)現(xiàn)
其實(shí)圖像識(shí)別技術(shù)與我們平時(shí)做的密碼驗(yàn)證之類的沒有什么區(qū)別,都是事先把要校驗(yàn)的數(shù)據(jù)入庫,然后使用時(shí)將錄入(識(shí)別)的數(shù)據(jù)與庫中的數(shù)據(jù)做對(duì)比,只不過圖像識(shí)別技術(shù)有一部分的容錯(cuò)性,而我們平時(shí)的密碼驗(yàn)證是要100%匹配。
前幾天,有朋友談到做游戲點(diǎn)擊抽獎(jiǎng),識(shí)別圖片中的文字,當(dāng)時(shí)立馬想到的就是js控制或者flash做遮罩層,感覺這種辦法是最方便快捷效果好,而且節(jié)省服務(wù)器資源,但是那邊提的要求竟然是通過php識(shí)別圖像中的文字。
趕巧那兩天的新聞?dòng)校?、馬云人臉識(shí)別支付;2、12306使用新的驗(yàn)證碼,說什么現(xiàn)在國內(nèi)的搶票軟件都不能用了,發(fā)布不到一天就被破解。然后又很湊巧的那天早上看了一篇Java的圖像識(shí)別技術(shù)文章。于是就琢磨著看一下PHP的圖像識(shí)別技術(shù)。
其實(shí)所謂的圖像識(shí)別,已經(jīng)不是什么新技術(shù)了,起碼我找到的資料都是很早之前的了。只不過我一直沒涉及到這方面的工作,就一直沒看過。
先說下這次實(shí)驗(yàn)的需求:有一張圖片,里面三個(gè)位置分別有三個(gè)數(shù)字,要求取出相應(yīng)位置的數(shù)字的值。(眼尖的同學(xué)可能會(huì)看出下面的代碼是我拿的別人的,沒錯(cuò),的確是我直接copy別人并刪減的,畢竟我對(duì)這些也是淺嘗輒止,最后會(huì)貼出原作者的初始代碼)

class gjPhone
{
protected $imgPath; // 圖片路徑
protected $imgSize; // 圖片大小
protected $hecData; // 分離后數(shù)組
protected $horData; // 橫向整理的數(shù)據(jù)
protected $verData; // 縱向整理的數(shù)據(jù)
function __construct ($path)
{
$this->imgPath = $path;
}
public function getHec ()
{
$size = getimagesize($this->imgPath);
$res = imagecreatefrompng($this->imgPath);
for ($i = 0; $i < $size[1]; ++ $i) {
for ($j = 0; $j < $size[0]; ++ $j) {
$rgb = imagecolorat($res, $j, $i);
$rgbarray = imagecolorsforindex($res, $rgb);
if ($rgbarray['red'] < 125 || $rgbarray['green'] < 125 ||
$rgbarray['blue'] < 125) {
$data[$i][$j] = 1;
} else {
$data[$i][$j] = 0;
}
}
}
$this->imgSize = $size;
$this->hecData = $data;
}
public function magHorData ()
{
$data = $this->hecData;
$size = $this->imgSize;
$z = 0;
for ($i = 0; $i < $size[1]; ++ $i) {
if (in_array('1', $data[$i])) {
$z ++;
for ($j = 0; $j < $size[0]; ++ $j) {
if ($data[$i][$j] == '1') {
$newdata[$z][$j] = 1;
} else {
$newdata[$z][$j] = 0;
}
}
}
}
return $this->horData = $newdata;
}
public function showPhone ($ndatas)
{
error_reporting(0);
$phone = null;
$d = 0;
foreach ($ndatas as $key => $val) {
if (in_array(1, $val)) {
foreach ($val as $k => $v) {
$ndArr[$d] .= $v;
}
}
if (! in_array(1, $val)) {
$d ++;
}
}
foreach ($ndArr as $key01 => $val01) {
$phone .= $this->initData($val01);
}
return $phone;
}
/**
* 初始數(shù)據(jù)
*/
public function initData ($numStr)
{
$result = null;
$data = array(
'1' => '00000000111000000000000001110000000001001000100000000010100011000000000011000110000000000110000100000000010110011000000',
'5' => '00000000001000000000000000010000000000100100100000000000101001110000000000100000110000000011000000100000001101000010000',
'10' => '00000011100011100000000011001100100100100010010001000110000100100010001100001001000100011000010010001001001001100010100'
);
foreach ($data as $key => $val) {
similar_text($numStr, $val, $pre);
if ($pre > 95) { // 相似度95%以上
$result = $key;
break;
}
}
return $result;
}
}
$imgurl = 'jd.png';
list ($width, $heght, $type, $attr) = getimagesize($imgurl);
$new_w = 17;
$new_h = 11;
$thisimage = imagecreatetruecolor($new_w, $new_h); // $new_w, $new_h 為裁剪后的圖片寬高
$background = imagecolorallocate($thisimage, 255, 255, 255);
imagefilledrectangle($thisimage, 0, 0, $new_w, $new_h, $background);
$oldimg = imagecreatefrompng($imgurl); // 載入原始圖片
// 首先定位要取圖的位置(這里可以通過前端js或者其他手段定位,由于我這是測試,所以就ps定位并寫死了)
$weizhi = array(
'1' => 165,
'5' => 308,
'10' => 456
);
foreach ($weizhi as $wwzz) {
$src_y = 108;
imagecopy($thisimage, $oldimg, 0, 0, $wwzz, $src_y, $new_w, $new_h); // $src_y,$new_w為原圖中裁剪區(qū)域的左上角坐標(biāo)拷貝圖像的一部分將src_im圖像中坐標(biāo)從src_x,src_y開始,寬度為src_w,高度為src_h的一部分拷貝到dst_im圖像中坐標(biāo)為dst_x和dst_y的位置上。
$tem_png = 'tem_1.png';
imagepng($thisimage, __DIR__ . '/' . $tem_png); // 通過定位從原圖中copy出想要識(shí)別的位置并生成新的緩存圖,用以后面的圖像識(shí)別類使用。
$gjPhone = new gjPhone($tem_png); // 實(shí)例化類
$gjPhone->getHec(); // 進(jìn)行圖像像素分離
$horData = $gjPhone->magHorData(); // 將分離出是數(shù)據(jù)轉(zhuǎn)成01表示的圖像、這里可以根據(jù)自己喜好定
$phone = $gjPhone->showPhone($horData); // 將轉(zhuǎn)換好的01表示的數(shù)據(jù)與庫中的數(shù)據(jù)進(jìn)行匹配,匹配度95以上就算成功,庫這里由于是做測試就直接寫了數(shù)組
echo '| ' . $phone . ' | ';
}
如此看來,其實(shí)12306驗(yàn)證碼被破解也算是有情可原了,也沒必要那么的口誅筆伐了罷。只要不斷的抓驗(yàn)證碼圖片并轉(zhuǎn)成自己程序可讀的數(shù)據(jù)存入庫里,然后驗(yàn)證的時(shí)候進(jìn)行匹配就可以了。那么阿里的人臉識(shí)別支付原理也算是理解了,只不過他們做的可能會(huì)很精細(xì)。
前端時(shí)間有看到阿里云的一個(gè)驗(yàn)證碼形式,剛開始感覺可能會(huì)好點(diǎn),現(xiàn)在看來,只要有心,其實(shí)也是可以破解的啊。

好了,下面是原作代碼。
/**
* 電話號(hào)碼識(shí)別.
* @author by zsc for 2010.03.24
*/
class gjPhone
{
protected $imgPath; // 圖片路徑
protected $imgSize; // 圖片大小
protected $hecData; // 分離后數(shù)組
protected $horData; // 橫向整理的數(shù)據(jù)
protected $verData; // 縱向整理的數(shù)據(jù)
function __construct ($path)
{
$this->imgPath = $path;
}
/**
* 顏色分離轉(zhuǎn)換...
*
* @param unknown_type $path
* @return unknown
*/
public function getHec ()
{
$size = getimagesize($this->imgPath);
$res = imagecreatefrompng($this->imgPath);
for ($i = 0; $i < $size[1]; ++ $i) {
for ($j = 0; $j < $size[0]; ++ $j) {
$rgb = imagecolorat($res, $j, $i);
$rgbarray = imagecolorsforindex($res, $rgb);
if ($rgbarray['red'] < 125 || $rgbarray['green'] < 125 ||
$rgbarray['blue'] < 125) {
$data[$i][$j] = 1;
} else {
$data[$i][$j] = 0;
}
}
}
$this->imgSize = $size;
$this->hecData = $data;
}
/**
* 顏色分離后的數(shù)據(jù)橫向整理...
*
* @return unknown
*/
public function magHorData ()
{
$data = $this->hecData;
$size = $this->imgSize;
$z = 0;
for ($i = 0; $i < $size[1]; ++ $i) {
if (in_array('1', $data[$i])) {
$z ++;
for ($j = 0; $j < $size[0]; ++ $j) {
if ($data[$i][$j] == '1') {
$newdata[$z][$j] = 1;
} else {
$newdata[$z][$j] = 0;
}
}
}
}
return $this->horData = $newdata;
}
/**
* 整理縱向數(shù)據(jù)...
*
* @return unknown
*/
public function magVerData ($newdata)
{
for ($i = 0; $i < 132; ++ $i) {
for ($j = 1; $j < 13; ++ $j) {
$ndata[$i][$j] = $newdata[$j][$i];
}
}
$sum = count($ndata);
$c = 0;
for ($a = 0; $a < $sum; $a ++) {
$value = $ndata[$a];
if (in_array(1, $value)) {
$ndatas[$c] = $value;
$c ++;
} elseif (is_array($ndatas)) {
$b = $c - 1;
if (in_array(1, $ndatas[$b])) {
$ndatas[$c] = $value;
$c ++;
}
}
}
return $this->verData = $ndatas;
}
/**
* 顯示電話號(hào)碼...
*
* @return unknown
*/
public function showPhone ($ndatas)
{
$phone = null;
$d = 0;
foreach ($ndatas as $key => $val) {
if (in_array(1, $val)) {
foreach ($val as $k => $v) {
$ndArr[$d] .= $v;
}
}
if (! in_array(1, $val)) {
$d ++;
}
}
foreach ($ndArr as $key01 => $val01) {
$phone .= $this->initData($val01);
}
return $phone;
}
/**
* 分離顯示...
*
* @param unknown_type $dataArr
*/
function drawWH ($dataArr)
{
if (is_array($dataArr)) {
foreach ($dataArr as $key => $val) {
foreach ($val as $k => $v) {
if ($v == 0) {
$c .= "<font color='#FFFFFF'>" . $v . "</font>";
} else {
$c .= $v;
}
}
$c .= "<br/>";
}
}
echo $c;
}
/**
* 初始數(shù)據(jù)...
*
* @param unknown_type $numStr
* @return unknown
*/
public function initData ($numStr)
{
$result = null;
$data = array(
0 => '000011111000001111111110011000000011110000000001110000000001110000000001110000000001011000000011011100000111000111111100000001110000',
1 => '011000000000011000000000111111111111111111111111',
2 => '001000000011011000000111110000001101110000011001110000011001110000110001111001100001011111100001000110000001',
3 => '001000000010011000000011110000000001110000000001110000110001110000110001011001110011011111011111000110001100',
4 => '000000001100000000111100000001111100000011101100000111001100001100001100011000001100111111111111111111111111000000001100000000000100',
5 => '111111000001111111000001110001000001110001000001110001100001110001100001110000110011110000111111000000001100',
6 => '000011111000001111111110011000110011110001100001110001100001110001100001110001100001010001110011010000111111000000001100',
7 => '110000000000110000000111110000111111110001110000110111000000111100000000111000000000111000000000',
8 => '000100011110011111111111110011100001110001100001110001100001110001100001110011100001011111111111000100011110',
9 => '001111000000011111100001110000110001110000110001110000110001110000110001011000100001011111100111000111111110000001110000'
);
foreach ($data as $key => $val) {
similar_text($numStr, $val, $pre);
if ($pre > 95) { // 相似度95%以上
$result = $key;
break;
}
}
return $result;
}
}
$imgPath = "http://bj.ganji.com/tel/5463013757650d6c5e31093e563c51315b6c5c6c5237.png";
$gjPhone = new gjPhone($imgPath);
// 進(jìn)行顏色分離
$gjPhone->getHec();
// 畫出橫向數(shù)據(jù)
$horData = $gjPhone->magHorData();
echo "===============橫向數(shù)據(jù)==============<br/><br/><br/>";
$gjPhone->drawWH($horData);
// 畫出縱向數(shù)據(jù)
$verData = $gjPhone->magVerData($horData);
echo "<br/><br/><br/>===============縱向數(shù)據(jù)==============< br/><br/><br/>";
$gjPhone->drawWH($verData);
// 輸出電話
$phone = $gjPhone->showPhone($verData);
echo "<br/><br/><br/>===============電話==============<br /><br/><br/>" . $phone;
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 使用PHP生成二維碼的兩種方法(帶logo圖像)
- php圖像處理函數(shù)大全(推薦收藏)
- PHP輸出圖像imagegif、imagejpeg與imagepng函數(shù)用法分析
- PHP圖片裁剪函數(shù)(保持圖像不變形)
- PHP圖像處理之imagecreate、imagedestroy函數(shù)介紹
- PHP實(shí)現(xiàn)提取一個(gè)圖像文件并在瀏覽器上顯示的代碼
- 基于OpenCV的PHP圖像人臉識(shí)別技術(shù)
- PHP中繪制圖像的一些函數(shù)總結(jié)
- PHP GD庫生成圖像的幾個(gè)函數(shù)總結(jié)
- 解析php常用image圖像函數(shù)集
- PHP基于GD庫的圖像處理方法小結(jié)
- php實(shí)現(xiàn)的證件照換底色功能示例【人像摳圖/換背景圖】
相關(guān)文章
php5 apache 2.2 webservice 創(chuàng)建與配置(java)
要運(yùn)行wsCaller.jar 要選安裝jdk 如果沒有安裝jdk 則wsCaller.jar 會(huì)以壓縮包的形式顯示2011-01-01
php中PDO方式實(shí)現(xiàn)數(shù)據(jù)庫的增刪改查
PDO是mysql數(shù)據(jù)庫操作的一個(gè)公用類了,我們不需要進(jìn)行自定類就可以直接使用pdo來操作數(shù)據(jù)庫了,但是在php默認(rèn)配置中pdo是未開啟所以我們必須先在php.ini中開啟它才可以使用。2015-05-05
php_screw安裝使用教程(另一個(gè)PHP代碼加密實(shí)現(xiàn))
這篇文章主要介紹了php_screw安裝使用教程,php_screw是另一個(gè)PHP代碼加密實(shí)現(xiàn),和Zend的encoder類似,需要的朋友可以參考下2014-05-05
PHP中file_get_contents函數(shù)抓取https地址出錯(cuò)的解決方法(兩種方法)
本文通過兩種方法解決PHP中file_get_contents函數(shù)抓取https地址出錯(cuò),需要的朋友可以參考下2015-09-09
使用Yii2實(shí)現(xiàn)主從數(shù)據(jù)庫設(shè)置
大家應(yīng)該都知道,當(dāng)項(xiàng)目做大了,數(shù)據(jù)庫主從還是不可少的。使用Yii框架開發(fā),如何設(shè)置數(shù)據(jù)庫的主從呢?其實(shí)很簡單。下面這篇文章就給大家詳細(xì)介紹了使用Yii2實(shí)現(xiàn)主從數(shù)據(jù)庫設(shè)置的方法,文中介紹的很詳細(xì),相信對(duì)大家的理解和學(xué)習(xí)很有幫助,下面來一起學(xué)習(xí)學(xué)習(xí)吧。2016-11-11
PHP--用萬網(wǎng)的接口實(shí)現(xiàn)域名查詢功能
PHP用萬網(wǎng)的接口實(shí)現(xiàn)域名查詢功能,需要的朋友可以了解下2012-12-12
Thinkphp5.0自動(dòng)生成模塊及目錄的方法詳解
這篇文章主要介紹了Thinkphp5.0自動(dòng)生成模塊及目錄的方法,簡單分析了Thinkphp5.0的結(jié)構(gòu)、目錄、創(chuàng)建與運(yùn)行方法,需要的朋友可以參考下2017-04-04
PHP+Ajax異步通訊實(shí)現(xiàn)用戶名郵箱驗(yàn)證是否已注冊( 2種方法實(shí)現(xiàn))
在網(wǎng)站注冊用戶時(shí)使用,主要為了無刷新異步驗(yàn)證用戶輸入的用戶名或者Email是否已注冊。2011-12-12

