最近期末考试考完了,我们也要放寒假了。于是突发奇想,想用PHP写一个答题卡识别程序。已经实现了一些,现分享给大家。
具体的步骤如下:
上传答题卡=>图片二值化(已实现)=>寻找定位点(已实现)=>使用定位点切割掉不要的部分(已实现)=>切割小题=>客观题自动阅卷&主观题切割后交由阅卷老师批改=>统计分数=>生成csv文档
先爆出源码:
1 <?php 2 error_reporting(0); 3 $fn="./1.jpg";//要识别的答题卡文件名,生产环境中替换为"$fn=‘./cards/‘.$_GET[‘testno‘]."/".$_GET[‘cardno‘];" 4 $m255=200;//图片二值化的阈值 5 $minx=-1;//定位点坐标,L6同。 6 $miny=-1; 7 function gett($res,$i,$j){//求某座标的灰度值 8 $m255=200; 9 $rgb = imagecolorat($res,$j,$i); 10 11 $rgbarray = imagecolorsforindex($res, $rgb); 12 $r= $rgbarray[‘red‘] * 0.333; 13 $g= $rgbarray[‘green‘] * 0.333; 14 $b= $rgbarray[‘blue‘] * 0.333; 15 $t= round(($r+$g+$b) /$m255); 16 return $t; 17 } 18 19 header(‘Content-type:image/png‘); 20 $res = imagecreatefromjpeg($fn); 21 $size = getimagesize($fn); 22 $black = imagecolorallocate($res, 0, 0, 0); 23 $white = imagecolorallocate($res, 255, 255, 255); 24 $red=imagecolorallocate($res, 255, 0, 0); 25 $fl=imagecolorallocate($res, 0, 255, 0); 26 for($j=0; $j <$size[0]; ++$j) 27 for($i=0; $i <$size[1]; ++$i) 28 { 29 //这一部分代码的Line26-Line35和Line36-Line49借鉴的网上的一位大大的文章,稍作修改,具体是哪位大大的,不太记得了,这一行献给那位大大 30 { 31 $rgb = imagecolorat($res,$j,$i); 32 $rgbarray = imagecolorsforindex($res, $rgb); 33 $r= $rgbarray[‘red‘]*0.333; 34 $g= $rgbarray[‘green‘]*0.333; 35 $b= $rgbarray[‘blue‘]*0.333; 36 $t= round(($r+$g+$b) /$m255); 37 if ($t==0) 38 { 39 imagesetpixel($res,$j,$i,$black);//原本是$data[$i][$j]=true;因为内存超限,so换成了这个,L47的一样. 40 if($minx==-1 and $miny==-1 and $i>=10 and $j>=10 and gett($res,$i+5,$j)==0 and gett($res,$i,$j+5)==0){//gett($res,$i+5,$j)==0 and gett($res,$i,$j+5)==0:防止误识别. 41 //找到左上角的定位点 42 $minx=$j; 43 $miny=$i; 44 45 } 46 }else{ 47 48 imagesetpixel($res,$j,$i,$white); 49 } 50 } 51 } 52 53 //$b=dgcz($res,$miny,$minx,$fl);//这个函数本是用于标记定位点的,后来取消了 54 imageellipse($res,$minx,$miny,40,40,$red);//标记定位点 55 //imageline($res,$minx,0,$minx,$size[1],$red); 56 //imageline($res,$size[0]-$minx,0,$size[0]-$minx,$size[1]-1,$red); 57 //画切割线 58 59 60 //imageellipse($res,$b-minx,$miny,40,40,$red); 61 62 $Out = imagecreatetruecolor ($size[0]-2*$minx,$size[1]-2*$miny);//切割后图像存放位置 63 imagecopy ( $Out,$res , 0,0 ,$minx ,$miny ,$size[0]-2*$minx,$size[1]-2*$miny );//切割 64 imagepng($Out); 65 imagedestroy($res); 66 imagedestroy($Out); 67 //$fh=fopen("./log.log","a"); 68 //fwrite($fh,"x:".$minx.";y:".$miny."\n"); 69 ?>
但效率有点低。需要二十多秒才能完成。
测试图片:
执行结果: