unit bmp2number; {将传递进来的图像进行对比,识别出图片中的数字。 本程序使用的是模式识别的方式,需要照片标准,数字无反光。 电表只有4位数字+1位小数,小数因为在拍照中不能保证停止,所以本程序也不作小数位的识别 因此。如果当前的数字 已经识别到了4位,程序就返回, 我们预设一个记录,用来记录这被识别的出4位数字的具体位置,再通过对TOP及LEFT位置的进行排序组合后返回 对于本模板的重要方法说明: Function GetNumber:string 功能:返回识别出的数字字符串 按照对TBmp2Number对象的下列属性: SoruceBitmap:需要被识别的图像 Temp_Index:模板编号 Temp_path:模板文件目录 discern_rate:识别率 } interface uses windows,math,classes,controls,graphics,jpeg,sysutils,dialogs,extctrls,forms, stdctrls,ComCtrls; Type pRGBTripleArray = ^TRGBTripleArray; TRGBTripleArray = array [0 .. 65535] of TRGBTriple; Ptemplate=^Ttemplate; //被识别的数字当用记录保存起来 Ttemplate=record number:integer; top:Integer; Left:Integer; end; TBmp2Number=class(Tobject) private FSourceBitMap:Tbitmap; FTempl_index:integer; Ftempl_Path:String; Fdiscern_rate:Double; FNumber:string; FNumberList:TList; tmeplate:Ptemplate; fStop:Boolean; FShowDemo:Boolean; protected procedure SetTempl_index(value:Integer); procedure SetTempl_path(Value:String); procedure InitTemplate; Function GetNumber:String; public memo1:TRichedit; image1,image2:Timage; pb_Count,pb_deta:TProgressbar; constructor Create; published property SourceBitMap:Tbitmap read FSourceBitMap write FSourceBitmap; property Templ_index:integer read Ftempl_index write SetTempl_index; Property Templ_Path:String read Ftempl_Path write SetTempl_path; property discern_rate:Double read Fdiscern_rate write Fdiscern_rate ; property Number:String read GetNumber; property Stop:Boolean read Fstop write FStop; property ShowDemo:Boolean read FShowDemo write FShowDemo; end; //SourceBitmap:电表图片,template_index:调用的模板号 template_path;模板存放的目录 Function Pic2Bmp(PicFileName:String):TBitmap; implementation //将图片转换成BMP格式,以便比较,主要是因为数码相机采集的图片基本上是JPEG 格式的。 //所以在装入时需要将其转换成BMP图片,便于比较 Function Pic2Bmp(PicFileName:String):TBitmap; var Str:String; Icon: TIcon; Jpeg1:TJPEGIMAGE; MetaFile:TMetafile; begin result:=TBitMap.create; result.PixelFormat:=pf24bit; Str := ExtractFileExt(PicFileName); Str :=Uppercase(Copy(Str,2,3)); if (Str='BMP') then result.LoadFromFile(PicFileName) else //Jpeg转换成BMP if (Str='JPG') or (Str='JPEG') then begin Jpeg1 := TJPEGIMAGE.Create; Jpeg1.LoadFromFile(PicFileName); result.Assign(Jpeg1); Jpeg1.free; end else //ICO 转换成BMP if (Str='ICO') or (Str='ico') then begin Icon := TIcon.Create; Icon.LoadFromFile(PicFileName); result := TBitmap.Create; result.Width := Icon.Width; result.Height := Icon.Height; result.Canvas.Draw(0, 0, Icon); Icon.Free; end else //WMF转换成BMP if Str='WMF' then begin Metafile:=TMetaFile.create; MetaFile.LoadFromFile(PicFileName); with result do begin Height:=Metafile.Height; Width:=Metafile.Width; Canvas.Draw(0,0,MetaFile); end; MetaFile.Free; end; end; constructor TBmp2Number.Create; begin inherited Create; Ftempl_index:=1; Ftempl_Path:='template'; Fdiscern_rate:=100; end; //设置模板索引 procedure TBmp2Number.SetTempl_index(value:integer); begin FtempL_index:=Value; initTemplate; end; procedure TBmp2Number.SetTempl_path(value:String); begin FTempl_path:=value; initTemplate; end; //初始化运行模板库 procedure TBmp2Number.InitTemplate; begin if tempL_Index=0 then exit; if Not DirectoryExists(Templ_Path) then exit; end; //逐行扫描的方式识别图片中的数字 function TBmp2Number.GetNumber:string; var tmpleBmp,midbmp:TBitMap; row,Col,mRow,mCol,numberNo:integer; NewRow,NewCol:integer; PSource, Ptemple: pRGBTripleArray; mR, mG, mB, tR, tG, tB: Integer; mP, tP: pRGBTripleArray; succ:Boolean;//对比是否成功 begin //数据的初步检查 if sourcebitmap=nil then begin showmessage('请装入目标图片!'); exit; end; FNumberList:=Tlist.Create; try if assigned(pb_Count) then pb_Count.Max:= SourceBitMap.width; if assigned(pb_deta) then pb_deta.Max:= SourceBitMap.Height; for Col:=0 to SourceBitMap.width-1 do begin if stop then exit; if ShowDemo then memo1.Lines.Add('本列是:'+inttostr(col)); if assigned(pb_Count) then begin pb_Count.Position:=col; Application.ProcessMessages; end; for Row:=0 to SourceBitMap.Height-1 do begin if assigned(pb_deta) then begin pb_deta.Max:= SourceBitMap.Height; pb_deta.Position:=Row; Application.ProcessMessages; end; if stop then exit; for numberNo:=0 to 9 do //0至9的数字分别装入模板 begin if not fileexists(Templ_Path+inttostr(numberNo)+'_'+inttostr(Templ_index)+'.bmp') then continue; if stop then exit; tmpleBmp:=TBitMap.create; tmpleBmp:=Pic2Bmp(Templ_Path+inttostr(numberNo)+'_'+inttostr(Templ_index)+'.bmp'); // tmpleBmp.LoadFromFile(Templ_Path+inttostr(numberNo)+'_'+inttostr(Templ_index)+'.bmp'); if ShowDemo then image1.Picture.bitmap:=tmplebmp; //从原图像中驳离出来与模板文件同样大小的文件来 midbmp:=Tbitmap.Create; midbmp.PixelFormat:= tmpleBmp.PixelFormat; midbmp.Width:=tmplebmp.Width; midbmp.height:=tmplebmp.Height; application.ProcessMessages; // midbmp.Canvas.CopyRect(Rect(0,0,midbmp.width,midbmp.height), sourcebitmap.canvas, Rect(Col,row,Col+tmpleBmp.width,row+tmpleBmp.height)); if ShowDemo then image2.picture.bitmap:=midbmp; Assert(midbmp.PixelFormat = tmpleBmp.PixelFormat); //然后逐行取值比较 for mRow:=0 to MidBmp.Height-1 do begin mp:= midBmp.ScanLine[mRow]; tp:= tmplebmp.ScanLine[mRow]; if stop then exit; for mcol:=0 to MidBmp.Width -1 do begin if stop then exit; mR := mp[mcol].rgbtRed; mG := mP[mcol].rgbtGreen; mB := mP[mcol].rgbtBlue; tR := tP[mcol].rgbtRed; tG:= tP[mcol].rgbtGreen; tB:=tP[mcol].rgbtBlue; if ShowDemo then memo1.Lines.Add('Mrow:'+Inttostr(mrow)+'MCol:'+inttostr(Mcol)+'mr:' +inttostr(mr)+'mg:'+inttostr(mg)+'mb:'+ inttostr(mb)+'tr:'+inttostr(tr)+'tg:'+inttostr(tg)+'tb:'+ inttostr(tb)); if (mR <> tR) or (mG <> tG) or (mB <> tB) then//如果像素不等 begin succ:=false; break; end else succ:=true; end; // end mcol:=0 to midbmp.width -1 do end; //end mrow:=0 to midbmp.height-1 do freeandnil(midbmp); if succ then begin//对比成功 new(tmeplate); tmeplate.number:= numberNo; tmePlate.top := Row; tmePlate.left:=col; FNumberList.Add(tmeplate); end ; // else // break; freeandnil(tmpleBmp); end; //end for number end; //end for row end; // end for col except showmessage('对比失败!'); end; for row:=0 to FNumberList.Count -1 do Result:=result+inttostr(Ptemplate(FNumberlist.Items[row]).number); for row:=FNumberList.count-1 downto 0 do begin Dispose(Ptemplate(FNumberList[Row])); FNumberlist.Delete(row); end; FNumberlist.free; end; end. |
|