SRL Archive - OSR Help

Help with some basic OCR techniques!


Smurfz

2013-03-21 17:31:11

I would like to do some basic OCR in simba, however, I am inexperienced so I was hoping for some help.

Currently I detect the following using TPAs:
1) Total count of pixels
2) Total count of pixels around the number/letter, not including the number/letter
3) Total count of pixels on the top, bottom, left, & right of the letter/number (think of it as folding a square paper into fours)
4) Counting the number of holes in the letter/number (Ex. an "8" has two holes)
5) width & height

I was hoping someone could give me more ideas of things I could use/do to differentiate between the numbers/letters.

I have attached three numbers I am having trouble determining with my current solution

Thanks!

rj

2013-03-21 17:34:19

Have you tried using gettextatwrap?

You will need to make them white, with a black background and save as 24 color bitmap

Text Function


Varhere:=GetTextAtExWrap(X1, Y1, X2, Y2, 0, Spacingbetweenwords, SpacingBetweenLetters, coloroftext, tolerance, 'fontfilename');


Smurfz

2013-03-21 17:38:46

From: RJJ95
Have you tried using gettextatwrap?

You will need to make them white, with a black background and save as 24 color bitmap

Text Function


Varhere:=GetTextAtExWrap(X1, Y1, X2, Y2, 0, Spacingbetweenwords, SpacingBetweenLetters, coloroftext, tolerance, 'fontfilename');



Yeah I know about it, but I wanted to try my own thing, so no DTMs either

Olly

2013-03-21 17:45:13

Could do some basic corner detection if you really wanted to.

Smurfz

2013-03-21 18:52:02

From: Ollybest
Could do some basic corner detection if you really wanted to.


Yes counting corners is something I would love to do

My google searches failed to come up with any good source code

Would anyone be interested in helping me do this? I may be able to give a nike gift card or maybe a $50 hawken credit

[Nathan]

2013-03-21 20:18:56

Let's take a step back on this. What are you trying to accomplish? There very likely is a better way to go about it.

Why can't you use what's already built?

Must you do it in simba/pascal? There are libraries built and other languages that might be better suited for this project.

What isn't working about what you have tried?

Smurfz

2013-03-21 20:40:38

From: [Nathan]
Why can't you use what's already built?


I would actually like to code something that would not need me to make new font bitmap masks each time I wanted to do a simple OCR, and DTMs do not work

From: [Nathan]
Must you do it in simba/pascal? There are libraries built and other languages that might be better suited for this project.


Yes I would like to do it in pascal, convert to a plugin later(only if I need speed)…I am not trying to break captchas here, I am simply OCRing simple stuff from games ect

From: [Nathan]
What isn't working about what you have tried?


based on all my current methods I have listed…and the 3 numbers I have attached…they are all too similar and I cannot determine them accurately

[Nathan]

2013-03-21 21:07:11

Alright that gave some good insight I was looking for and have some suggestions for you to think about.

Anything you custom make, will 90% most likely ONLY work for that exact given font, if you want it for something else, you will have to re-write a good part of it. And that would most likely be much more work than a bitmap mask of the new font.

I say that because it sounds like you want to implement this for multiple fonts in the future? Well I can assure you people much smarter than you (no offense, but its true they are much smarter than me too) have worked on this exact thing (OCR) and as far as I am aware, bitmap masks or some similar derivative are pretty much universally used, because fonts just are too variable. There really is no reason to r-invent the wheel here.

Now, as to wanting to do something your own type aspect, I completely understand that desire, makes complete sense, I just honestly don't think you will come up with a better solution than what is already available in bitmap masks. I really like the ideas you tried and the direction you were heading, but for what it sounds like you ultimately are trying to accomplish, I don't know how successful it will be.

NOW, given all that, if you still want to do it this way, here is one thing I would suggest.

Break the letter down into 9 (maybe more, maybe less, might have to experiment) separate squares, and then apply the technique you were trying to each individual square. Overall, a 3 and a 9 have might have very similar pixel counts, but their distribution will not be anywhere close to the same.

Then, take all these pixel counts, and see where the differences are. It will take a bit of time to sort through all the data, but I am confident if you break the letters down into small enough pieces, an algorithm COULD be written to examine the distribution of pixels throughout the number, and come up very accurately with what number it is.

Smurfz

2013-03-21 23:59:55

Using just what I have now Iv been able to OCR quite a bit of word games ect..but there are also a select few that give me problems

The difference between 3 and 9 would never get mixed up because 3 has zero holes and 9 has one hole

breaking them down is an interesting option, however, I would not know how to write the algo

I am looking for more "determining" factors to add to what I have already, that's why I liked the idea of counting corners…but I don't know how to count corners

Smurfz

2013-03-27 18:50:40

Giving this a little bump, still looking for someone to help me with counting corners

also I tried a grid like system, but haven't gotten very far yet, but I dunno if it is better than my current system

type
TGrid = record
bounds: TBox;
pixels: Integer;
end;

procedure createGrid;
var
TPA: TPointArray;
b: TBox;
boxes: array of TGrid;
area, bmp, h, i, numOfBoxes, w, x, y: Integer;
str: String;
begin
FindColors(TPA, 1034847, 709, 133, 756, 181);

b := GetTPABounds(TPA);
with b do
begin
//b := IntToBox(x1 - 2, y1 - 2, x2 + 2, y2 + 2);
w := x2 - x1;
h := y2 - y1;

WriteLn('Width = '+IntToStr(w));
WriteLn('Height = '+IntToStr(h));

area := w * h;
WriteLn('Area = '+IntToStr(area));

bmp := BitmapFromString(w, h, '');
CopyClientToBitmap(bmp, x1, y1, x2, y2);

for x := 0 to w do
for y := 0 to h do
FastSetPixel(bmp, x, y, clBlack);

for i := 0 to High(TPA) do
FastSetPixel(bmp, TPA[i].x - x1, TPA[i].y - y1, clWhite);

numOfBoxes := 4;
SetLength(boxes, (numOfBoxes * numOfBoxes));
for i := 0 to (numOfBoxes * numOfBoxes) - 1 do
boxes[i].bounds := IntToBox(Round(x1 + ((i mod numOfBoxes) * ((x2 - x1) / numOfBoxes))),
Round(y1 + ((i div numOfBoxes) * ((y2 - y1) / numOfBoxes))),
Round(x1 + ((x2 - x1) / numOfBoxes) + ((i mod numOfBoxes) * ((x2 - x1) / numOfBoxes))),
Round(y1 + ((y2 - y1) / numOfBoxes) + ((i div numOfBoxes) * ((y2 - y1) / numOfBoxes))));

end;

SetTargetBitmap(bmp);
SaveBitmap(bmp, ScriptPath+'b.bmp');
getbitmapsize(bmp, w, h);

writeln(inttostr(Fastgetpixel(bmp, 0,11)));
terminatescript;
for i := 0 to High(boxes) do
begin
with boxes[i].bounds do
begin
writeln(inttostr(x1)+', '+Inttostr(y1)+', '+inttostr(x2)+', '+Inttostr(y2));
writeln(inttostr(i * 5)+', '+inttostr(( i div numOfBoxes ) * 7)+', '+inttostr((i * 5) + 5)+', '+inttostr((( i div numOfBoxes ) * 7) + 7));
boxes[i].pixels := CountColor(clWhite, i * 5, ( i div numOfBoxes ) * 7, (i * 5) + 5, (( i div numOfBoxes ) * 7) + 7);
end;

str := str + IntToStr(boxes[i].pixels)+', ';
end;

WriteLn(str);

end;