Skit3000 Admin Team
Joined: 11 May 2002 Posts: 2166 Location: The Netherlands
|
Posted: Sun Apr 09, 2006 6:54 pm Post subject: [Open Source]: Simple OCR (Optical Character Recognition) |
|
|
Because I make a lot of (paper) notes at school, I started looking for a way to scan them into my computer. I tried some standard applications which do OCR and ICR, but both did not return good results. That is why I started making my own OCR/ICR engine.
Normal letters are difficult for computers to read. An "a" looks like a "d", an "c" like a "e" or "o", etc. To overcome this problem, I created my own characters. In the version of the program which comes with this post, eight different characters can be recognized and outputted as numbers corresponding to them. Just like with morse code and braille, you can combine two characters to create more combinations (8*8=64). For now, my program does not do this since it is far from done and maybe it still will be possible to let it read normal letters.
I used a normal ballpoint to write my characters on normal paper with lines. To get better recognition results you can use a black fine-liner.
Here comes the source code, maybe some people can improve it/use it in their own projects... The images used can be found in the zip file included
Code: | # Turn the output bitmap on or off
%%DebugOutput = on
#define command,image
#define function,image,IsPixel,RecognizeChar,IsCharPixel
# Enter your registration info for the vdsimage.dll below
# vdsimage.dll is a part of Tommy Sools' VDSDLL3
external @path(%0)vdsimage.dll
option decimalsep,.
%%Inputfile = @path(%0)Input.bmp
title Basic OCR
DIALOG CREATE,Basic OCR,-1,0,850,500
DIALOG ADD,STYLE,sBLUE,,,,BLUE,
DIALOG ADD,STYLE,sRED,,,,RED,
DIALOG ADD,STYLE,sGRAY,,,,SILVER,
DIALOG ADD,STYLE,sOUTPUT,Courier New,8,,,
DIALOG ADD,LINE,LINE1,348,-2,854,150
DIALOG ADD,BITMAP,bInput,0,0,852,350,%%Inputfile
DIALOG ADD,TEXT,Leftmargin,0,113,1,350,,,sRED,CLICK,HSPLIT
DIALOG ADD,TEXT,Rightmargin,0,801,1,350,,,sBLUE,CLICK,HSPLIT
DIALOG ADD,TEXT,Firstline,90,0,852,1,,,sRED,CLICK,VSPLIT
DIALOG ADD,TEXT,Helpline1,119,0,852,1,,,sGRAY
DIALOG ADD,TEXT,Helpline2,148,0,852,1,,,sGRAY
DIALOG ADD,TEXT,Secondline,177,0,852,1,,,sBLUE,CLICK,VSPLIT
DIALOG ADD,BUTTON,bStart,366,12,192,24,Start processing
DIALOG ADD,BUTTON,bStop,396,12,192,24,Stop processing
DIALOG ADD,PROGRESS,pStatus,450,12,192,18,0
DIALOG ADD,EDIT,eOutput,366,246,486,102,How to use:@cr()@lf()@cr()@lf()Put the horizontal blue line on the first line of your picture. Put the red line on the fourth line. (Note the helplines will take positions on the second and third line) Now specify the left and right margin with the two vertical lines and press the Start processing button!,,MULTI,WRAP,SCROLL,TABS,sOUTPUT
DIALOG ADD,MENU,File,Open bitmap,Close
DIALOG ADD,STATUS,Statusbar,
DIALOG ADD,BITMAP,bChars,366,756,42,108,@path(%0)Chars.bmp
DIALOG SHOW
dialog disable,bStop
:Evloop
wait event
goto @event()
:LeftmarginCLICK
# Move the left margin line
%%MousedownX = @diff(@mousepos(X),@dlgpos(Leftmargin,L))
while @mousedown(L)
if @greater(@diff(@dlgpos(Rightmargin,L),30),@diff(@mousepos(X),%%MousedownX))
dialog setpos,Leftmargin,0,@diff(@mousepos(X),%%MousedownX)
end
wend
goto Evloop
:RightmarginCLICK
# Move the right margin line
%%MousedownX = @diff(@mousepos(X),@dlgpos(Rightmargin,L))
while @mousedown(L)
if @greater(@diff(@mousepos(X),%%MousedownX),@sum(@dlgpos(Leftmargin,L),30))
dialog setpos,Rightmargin,0,@diff(@mousepos(X),%%MousedownX)
end
wend
if @greater(@dlgpos(Rightmargin,L),@dlgpos(,W))
dialog setpos,Rightmargin,0,@diff(@dlgpos(,W),10)
end
goto Evloop
:FirstlineCLICK
# Move the first horizontal line + the helplines
%%MousedownY = @diff(@mousepos(Y),@dlgpos(Firstline,T))
while @mousedown(L)
if @greater(@diff(@dlgpos(Secondline,T),10),@diff(@mousepos(Y),%%MousedownY))
dialog setpos,Firstline,@diff(@mousepos(Y),%%MousedownY)
# Adjust helplines
dialog setpos,Helpline1,@sum(@dlgpos(Firstline,T),@div(@diff(@dlgpos(Secondline,T),@dlgpos(Firstline,T)),3))
dialog setpos,Helpline2,@sum(@dlgpos(Firstline,T),@prod(@div(@diff(@dlgpos(Secondline,T),@dlgpos(Firstline,T)),3),2))
end
wend
goto Evloop
:SecondlineCLICK
# Move the second horizontal line + the helplines
%%MousedownY = @diff(@mousepos(Y),@dlgpos(Secondline,T))
while @mousedown(L)
if @greater(@diff(@mousepos(Y),%%MousedownY),@sum(@dlgpos(Firstline,T),10))
dialog setpos,Secondline,@diff(@mousepos(Y),%%MousedownY)
# Adjust helplines
dialog setpos,Helpline1,@sum(@dlgpos(Firstline,T),@div(@diff(@dlgpos(Secondline,T),@dlgpos(Firstline,T)),3))
dialog setpos,Helpline2,@sum(@dlgpos(Firstline,T),@prod(@div(@diff(@dlgpos(Secondline,T),@dlgpos(Firstline,T)),3),2))
end
wend
if @greater(@dlgpos(Secondline,T),@dlgpos(bInput,H))
dialog setpos,Secondline,@diff(@dlgpos(bInput,H),10)
end
goto Evloop
:Open BitmapMENU
# Open a new file
%%Temp = @filedlg(*.bmp)
if @file(%%Temp)
%%Inputfile = %%Temp
dialog set,bInput,%%Inputfile
end
goto Evloop
:bStartBUTTON
dialog disable,bStart
dialog enable,bStop
dialog clear,eOutput
image open,%%Inputfile
%%ImageHeight = @image(height)
%%ImageWidth = @image(width)
%%Firstline = @dlgpos(Firstline,T)
%%Secondline = @dlgpos(Secondline,T)
%%Leftmargin = @dlgpos(Leftmargin,L)
%%Rightmargin = @dlgpos(Rightmargin,L)
%%LineHeight = @div(@diff(@dlgpos(Secondline,T),@dlgpos(Firstline,T)),3)
%%LineWidth = @diff(%%Leftmargin,%%Rightmargin)
%%CurrentLine = 0
%%CurrentLineY = %%Firstline
%%TotalLines = @div(@diff(%%ImageHeight,%%Firstline),%%LineHeight)
dialog set,pStatus,@format(@fmul(@fdiv(1,%%TotalLines),100),0.0)
dialog set,Statusbar,Decoding line 1 of %%TotalLines
# Loop through all lines or until the stop button is pressed
while @both(@greater(%%ImageHeight,@sum(%%CurrentLineY,%%LineHeight)),@unequal(@event(),bStopBUTTON))
%%CurrentColumn = 0
%%CurrentColumnX = %%Leftmargin
%%LeftCharBorder = -1
%%RightCharBorder = -1
# Loop through all columns from %%Leftmargin to %%Rightmargin
while @greater(%%Rightmargin,%%CurrentColumnX)
# Loop through all pixels of the current column to see if it is empty or not.
# Empty pixels have a value of 9500000 or higher. Non empty pixels have a value
# of 9500000 or lower.
%%NonEmptyPixel = 0
%%CurrentPixel = 0
%%CurrentPixelY = %%CurrentLineY
while @both(@greater(@sum(%%CurrentLineY,%%LineHeight),%%CurrentPixelY),@equal(%%NonEmptyPixel,0))
%%Pixel = @IsPixel(%%CurrentColumnX,%%CurrentPixelY)
# Check if the pixel is empty or not
if %%Pixel
%%NonEmptyPixel = @succ(%%NonEmptyPixel)
end
%%CurrentPixel = @succ(%%CurrentPixel)
%%CurrentPixelY = @sum(%%CurrentLineY,%%CurrentPixel)
wend
if @greater(%%NonEmptyPixel,0)
# This column contains a pixel (begin of character)
if @equal(%%RightCharBorder,-1)
if @equal(%%LeftCharBorder,-1)
# The left border is determined
%%LeftCharBorder = %%CurrentColumnX
%%RightCharBorder = -1
end
end
else
# This column is empty (end of character)
if @unequal(%%LeftCharBorder,-1)
%%RightCharBorder = @succ(%%RightCharBorder)
if @equal(%%RightCharBorder,1)
# The right border is determined
%%RightCharBorder = @pred(%%CurrentColumnX)
if @greater(@diff(%%RightCharBorder,%%LeftCharBorder),5)
%%TempTop = %%CurrentLineY
%%TempBottom = @sum(%%CurrentLineY,%%LineHeight)
%%TempLeft = %%LeftCharBorder
%%NonEmptyPixel = 0
# Determine the exact top
while @equal(%%NonEmptyPixel,0)
while @both(@greater(%%RightCharBorder,%%TempLeft),@equal(%%NonEmptyPixel,0))
if @ispixel(%%TempLeft,%%TempTop)
%%NonEmptyPixel = 1
end
%%TempLeft = @succ(%%TempLeft)
wend
%%TempLeft = %%LeftCharBorder
%%TempTop = @succ(%%TempTop)
wend
%%TempLeft = %%LeftCharBorder
%%NonEmptyPixel = 0
# Determine the exact bottom
while @equal(%%NonEmptyPixel,0)
while @both(@greater(%%RightCharBorder,%%TempLeft),@equal(%%NonEmptyPixel,0))
if @ispixel(%%TempLeft,%%TempBottom)
%%NonEmptyPixel = 1
end
%%TempLeft = @succ(%%TempLeft)
wend
%%TempLeft = %%LeftCharBorder
%%TempBottom = @pred(%%TempBottom)
wend
# Check if a space should be added before the character
if @greater(%%LeftCharBorder, @sum(%%LastRightBorder,@diff(%%RightCharBorder,%%LeftCharBorder),10))
# Check if the character is not the first one in a line
if %%LastRightBorder
dialog set,eOutput,@dlgtext(eOutput)" "
end
end
# Recognize character
dialog set,eOutput,@dlgtext(eOutput)@RecognizeChar(%%TempTop,%%TempBottom,%%LeftCharBorder,%%RightCharBorder)
if @equal(%%DebugOutput,on)
image line,%%TempTop,%%LeftCharBorder,@diff(%%RightCharBorder,%%LeftCharBorder),0,BLACK
image line,%%TempBottom,%%LeftCharBorder,@diff(%%RightCharBorder,%%LeftCharBorder),0,BLACK
image line,%%TempTop,%%LeftCharBorder,0,@diff(%%TempBottom,%%TempTop),BLACK
image line,%%TempTop,%%RightCharBorder,0,@diff(%%TempBottom,%%TempTop),BLACK
end
%%LastRightBorder = %%RightCharBorder
end
%%LeftCharBorder = -1
%%RightCharBorder = -1
end
end
end
%%CurrentColumn = @succ(%%CurrentColumn)
%%CurrentColumnX = @sum(%%Leftmargin,%%CurrentColumn)
wend
%%CurrentLine = @succ(%%CurrentLine)
%%CurrentLineY = @sum(%%Firstline,@prod(%%CurrentLine,%%LineHeight))
%%LastRightBorder =
dialog set,eOutput,@dlgtext(eOutput)@cr()@lf()
dialog set,Statusbar,Decoding line @succ(%%CurrentLine) of %%TotalLines
dialog set,pStatus,@format(@fmul(@fdiv(@succ(%%CurrentLine),%%TotalLines),100),0.0)
wend
dialog set,Statusbar,Done decoding
if @equal(%%DebugOutput,on)
image save,@path(%0)DebugOutput.bmp
end
dialog enable,bStart
dialog disable,bStop
info Done
goto Evloop
:Close
exit
:RecognizeChar
# This function gets the top, bottom, left and right pixel positions of the
# found character. Use these coordinates to "see" which character was written down.
# %1 = top
# %2 = bottom
# %3 = left
# %4 = right
%3 = @succ(%3)
%4 = @pred(%4)
# Char 1, 3, 4, 6, 7 & 8
# Left Top
if @IsCharPixel(%3,%1)
# Left Bottom
if @IsCharPixel(%3,%2)
# Right Top
if @IsCharPixel(%4,%1)
# Right Bottom
if @IsCharPixel(%4,%2)
# = Left Top + Left Bottom + Right Top + Right Bottom
exit 7
else
# = Left Top + Left Bottom + Right Top + <> Right Bottom
exit 1
end
# Right Bottom
elsif @IsCharPixel(%4,%2)
# = Left Top + Left Bottom + Right Bottom
exit 3
else
# If not Right Top & Right Bottom
if @both(@not(@IsCharPixel(%4,%1)),@not(%4,%2))
# = Left Top + Left Bottom + <> Right Top + <> Right Bottom
exit 8
end
end
else
# Right Top
if @IsCharPixel(%4,%1)
# Right Bottom
if @IsCharPixel(%4,%2)
# = Left Top + Right Top + Right Bottom
exit 4
end
# Right Bottom
elsif @IsCharPixel(%4,%2)
# = Left Top + Right Bottom
exit 6
end
end
# Char 2 & 5
# Right Top
elsif @IsCharPixel(%4,%1)
# Right Bottom
if @IsCharPixel(%4,%2)
# Left Bottom
if @IsCharPixel(%3,%2)
# = Right Top + Right Bottom + Left Bottom
exit 2
end
# Left Bottom
elsif @IsCharPixel(%3,%2)
# = Right Top + Left Bottom
exit 5
end
end
# Character was not recognized, return an error X
exit X
:IsCharPixel
# This function will return 1 if the specified pixel is not empty (including a neighbour pixel) or
# returns Null if the pixel is empty. Same as the IsPixel function, with the exception that this
# one is greedier; it returns 1 more often.
# %1 = x
# %2 = y
%5 = @image(pixel,@pred(%1),%2)
%6 = @image(pixel,@succ(%1),%2)
%7 = @image(pixel,%1,@succ(%2))
%8 = @image(pixel,%1,@pred(%2))
%9 = @image(pixel,%1,%2)
if @greater(10000000,%5)@equal(%5,BLACK)@greater(10000000,%6)@equal(%6,BLACK)@greater(10000000,%7)@equal(%7,BLACK)@greater(10000000,%@equal(%8,BLACK)@greater(10000000,%9)@equal(%9,BLACK)
# Pixel is not empty
exit 1
end
exit
:IsPixel
# This function will return 1 if the specified pixel is not empty (including a neighbour pixel) or
# returns Null if the pixel is empty.
# %1 = x
# %2 = y
%9 = @image(pixel,%1,%2)
if @greater(9500000,%9)@equal(%9,BLACK)
# Pixel is not empty, check its neighbours; left, right and below
%7 = @image(pixel,@pred(%1),%2)
%8 = @image(pixel,@succ(%1),%2)
%9 = @image(pixel,%1,@succ(%2))
if @greater(9500000,%7)@equal(%7,BLACK)@greater(9500000,%@equal(%8,BLACK)@greater(9500000,%9)@equal(%9,BLACK)
exit 1
end
exit
end
exit |
Description: |
Screenshot of the main program |
|
Filesize: |
250.97 KB |
Viewed: |
2109 Time(s) |
|
Description: |
Source code, used images and dlls |
|
Download |
Filename: |
ocr.zip |
Filesize: |
528.62 KB |
Downloaded: |
2111 Time(s) |
_________________ [ Add autocomplete functionality to your VDS IDE windows! ]
Voor Nederlandse beginners met VDS: bekijk ook eens deze tutorial! |
|