class verifiCodeEyes{ private $imgFilePath; private $tempDir; private $textOfImg; private $allowedImgExt = array('jpeg', 'png', 'jpg', 'bmp'); private $imgExt; private $validRect; private $fazhi;//阀值 private $imgData; private $charsArray; private $charsStringify; private $keysTable; private $text; const KEY_DB_PATH = 'key_db.bat'; public function __construct($imgFilePath){ if(!file_exists($imgFilePath)) $this->printError('图片文件不存在!'); $ext = $this->getFileExt($imgFilePath); if(!$this->isAllowedImgExt($ext)) $this->printError('图片类型不合法!'); if(!is_readable($imgFilePath)) $this->printError('图片文件没有读取权限!'); $this->imgExt = $ext; $this->imgFilePath = $imgFilePath; $this->tempDir = sys_get_temp_dir(); $this->imgData = array(); $this->fazhi = array();//r,g,b值 $this->charsArray = array(); $this->charsStringify = array(); $this->keysTable = array(); $this->text = ''; $this->loadKeyDb(); } public function parseImgData(){ //检查有没有设置阀值 if(!isset($this->fazhi)) die('请设置阈值!'); if(empty($this->validRect)){ $imgSize = getimagesize($this->imgFilePath); $s_x=0; $s_y=0; $e_x=$imgSize[0]; $e_y=$imgSize[1]; }else{ $s_x=$this->validReclc_0; $s_y=$this->validReclc_1; $e_x=$this->validReclc_2; $e_y=$this->validReclc_3; } //对图像进行二值化处理 $imgRes = $this->getImageRes(); if($imgRes===false) die('图片资源加载失败'); $fz_red = $this->fazhi[0]; $fz_green = $this->fazhi[1]; $fz_blue = $this->fazhi[2]; $row=0; $column=0; for($i=$s_y; $i<$e_y; $i++,$row++){ for($j=$s_x,$column=0; $j<$e_x; $j++,$column++){ //获得当前像素点颜色索引值 $colorIndex = imagecolorat($imgRes, $j, $i); //通过颜色索引值获得颜色的RGB数组表示形式 $colorRgb = imagecolorsforindex($imgRes, $colorIndex); if($colorRgb['red']>$fz_red && $colorRgb['green']>$fz_green && $colorRgb['blue']>$fz_blue){ $this->imgData[$row][$column] = 0;//背景区域设置为0 }else{ $this->imgData[$row][$column] = 1;//前景设置为1 } } } //print_r($this->imgData); //去除上边、下边的背景 $tmpData = array(); foreach($this->imgData as $rowData){ if(array_sum($rowData)>0){ $tmpData[] = $rowData; } } //分隔出单个字符 //首先进行行列转置 $revArray = array(); foreach($tmpData as $r => $row){ foreach($row as $c => $column){ $revArray[$c][$r] = $column; } } //对转置后的数组进行字符分隔 $charsHeap = array(); foreach($revArray as $row){ if(array_sum($row)==0){ if(isset($t) && is_array($t) && !empty($t)){ $charsHeap[] = $t; unset($t); } $t = array(); continue; } $t[] = $row; } if(!empty($t)) $charsHeap[] = $t; unset($t); //对charsHeap中的每个字符数据进行行列转置,还原成正常序列 $i=0; foreach($charsHeap as $charData){ $temp = array(); foreach($charData as $r=>$row){ foreach($row as $c=>$column){ $temp[$c][$r] = $column; } } foreach($temp as $r => $row){ $temp[$r] = implode('', $row); } $this->charsArray[$i] = $temp; $this->charsStringify[$i] = implode(',', $temp); unset($temp); $i ++; } } public function getText(){ $this->parseImgData();//将图片上的数据结构化 $this->text = ''; foreach($this->charsStringify as $charData){ $similar = 0.0; $char = '#'; foreach($this->keysTable as $key => $strValue){ $percent = 0.0; similar_text($strValue, $charData, $percent); if($percent>$similar) {$similar = $percent;$char = $key;} } $this->text .= $char; } return $this->text; } public function echoText(){ echo $this->text; } public function train(){//此方法是用来训练字符库的 $file = fopen(self::KEY_DB_PATH, 'ab'); foreach($this->charsStringify as $keyStr){ fwrite($file, '#='.$keyStr.PHP_EOL); } fclose($file); } private function loadKeyDb(){//加载字符库 if(!file_exists(self::KEY_DB_PATH)) return false; $file = fopen(self::KEY_DB_PATH,'r'); while(!feof($file)){ $line = fgets($file); $t = explode('=', $line); $this->keysTable[$lc_0] = $lc_1; } //print_r($this->keysTable); fclose($file); } private function getImageRes(){ switch($this->imgExt){ case 'jpeg': case 'jpg': $res = imagecreatefromjpeg($this->imgFilePath);break; case 'png': $res = imagecreatefrompng($this->imgFilePath);break; case 'bmp': $res = imagecreatefromwbmp($this->imgFilePath);break; case 'gif': $res = imagecreatefromgif($this->imgFilePath);break; default: return false; } //imagefilter ($res, IMG_FILTER_GRAYSCALE); //imagefilter ($res, IMG_FILTER_EDGEDETECT); //将图像进行灰度计算,再进行黑白处理,以方便图像二值化 if (imageistruecolor($res)){ imagetruecolortopalette($res, false, 256);//如果是真彩色图象,将真彩色图像转换为调色板图像 } for ($i = 0; $i < imagecolorstotal($res);/*获得调色板中颜色的数目*/ $i++){ $rgb = imagecolorsforindex($res, $i);//获得颜色i点的颜色值 $gray = round(0.229 * $rgb['red'] + 0.587 * $rgb['green'] + 0.114 * $rgb['blue']);//获得颜色灰度值 //imagecolorset($res, $i, $gray, $gray, $gray);//设置i点颜色值,图像将变成灰度图,灰度图可以方便判断背景和前景 if($gray<128){//如果灰度值小于128,我们就认为是有效图像,将图像该点像素颜色设置为黑色 imagecolorset($res, $i, 0, 0, 0); }else{ imagecolorset($res, $i, 255, 255, 255);//将像素点设置为白色 } } return $res; } private function isAllowedImgExt($ext){ if(!in_array($ext, $this->allowedImgExt)) return false; return true; } public function setTempDir($path){ if(!file_exists($path)) $this->printError('指定的临时目录不存在'); if(!is_dir($path)) $this->printError('指定的目录不合法'); if(!is_writable($path)) $this->printError('指定的目录没有写的权限!'); $this->tempDir = $path; } public function setValidRect($rect){ if(!is_array($rect)){ $this->validRect = explode(',', $rect); }else{ $this->validRect = $rect; } } public function setFazhi($fazhi){ if(!is_array($fazhi)){ $this->fazhi = explode(',', $fazhi); }else{ $this->fazhi = $fazhi; } } public function getFileExt($file){ $lastDotPos = strrpos($file, '.'); if($lastDotPos===false){ return 'unknown'; } return substr($file, ++$lastDotPos); } public static function downloadImage($imgUrl, $imgType, $savePath=''){ if(!self::checkDir($savePath)) self::printError('指定的目录不存在或者不可写!'); $tmpFileName = date('YmdHis').'.'.ltrim($imgType,'.'); $imgContent = file_get_contents($imgUrl); $filePath = rtrim($savePath.'/').'/'.$tmpFileName; $int = file_put_contents($filePath, $imgContent); if($int>0) return $filePath; return false; } public static function checkDir($path){ if(!file_exists($path)) return false; if(!is_dir($path)) return false; if(!is_writable($path)) return false; return true; } public function printError($msg){ echo $msg; exit; } public function __destruct(){ unset($this->imgData); unset($this->charsArray); unset($this->charsStringify); unset($this->keysTable); } public function printImg($data){ $rowNum = count($data); foreach($data as $r=>$row){ $r = substr(str_repeat(' ', $rowNum).$r,-1*strlen($rowNum-1)); if(is_array($row)){ echo $r.'=> '.implode('',$row)."\r\n"; }else{ echo $r.'=> '.$row."\r\n"; } ob_flush();//释放缓冲区 flush();//输出到浏览器 } } } $vc = new verifiCodeEyes('20150516161159.png'); $vc->setValidRect(array(1,0,75,18)); $vc->setFazhi(array(250,250,250)); $vc->parseImgData(); echo $vc->getText();
实际效果:
原始图片:
灰度处理之前的识别,可以看到杂点较多:
灰度处理之后的识别结果,明显清晰了许多: