Tcl does OCR with TWAPI and Microsoft Office

GS (20130717) Since Office 2003, there is a library called MODI (Microsoft Office Document Imaging). With it you can perform OCR (Optical Character Recognition) and extract text from document images. So, with less than 10 lines of Tcl you can get your text.

I say less than 10 lines ! OK let's go :

The sample image will be a part of the text from www.tcl.tk in BMP image format :

http://wfr.tcl.tk/fichiers/images/tcltktext.jpg

package require twapi
set doc [twapi::comobj MODI.Document]
$doc Create "tcltk.bmp"
$doc OCR
set img [[$doc Images] Item 0]
set ly [$img Layout]
set page [$ly Text]
$doc Close

In the variable page, you will get this raw text without formatting :

 Welcome to the Tcl Developer Xchange!

 Join the many thousands of software developers who are already more productive with help from 
 the Tcl programming language and the Tk graphical user interface toolkit.

 Tcl (Tool Command Language) is a very powerful but easy to learn dynamic programming language, 
 suitable for a very wide range of uses, including web and desktop applications, networking, 
 administration, testing and many more. Open source and business-friendly, Tcl is a mature yet 
 evolving language that is truly cross platform, easily deployed and highly extensible.

 Tk is a graphical user interface toolkit that takes developing desktop applications to a 
 higher level than conventional approaches. Tk is the standard GUI not only for Tcl, but 
 for many other dynamic languages, and can produce rich, native applications that run 
 unchanged across Windows, Mac OS X, Linux and more.

A few comments about this little funny piece of code

 set doc [twapi::comobj MODI.Document]

Create an instance of MODI.Document object.

 $doc Create "tcltk.bmp"

Assign an image file to the document instance. Supported image formats are TIFF, multi-page TIFF and BMP.

 $doc OCR

Calling the OCR method. The OCR method can take 3 optional parameters :

$doc OCR <LangId> <OCROrientImage> <OCRStraightenImage>

LangId : the language of the document. 20 languages are supported. OCR engine always use default regional settings. Czech = 5, Danish = 6, English = 9, Finnish = 11, French = 12, German = 7, Greek = 8, Italian = 16, Spanish = 10, Russian = 25.

OCROrientImage : a boolean value which specifies whether the OCR engine attempts to determine the orientation of the page. Default is true.

OCRStraightenImage : a boolean value which specifies whether the OCR engine attempts to "de-skew" the page to correct for small angles of misalignment from the vertical. Default is true.

 set img [[$doc Images] Item 0]

Each page of the document is an image object. We get the first and only image (Item 0). If you have more than one page, you have to do a loop over all the images and to use TIFF format. The number of images is : set n [$doc Images] Count] .

 set ly [$img Layout]

Get the layout. At this stage you haven't any text because the Text property is in a nested object. To sum up, the object hierarchy is something like that :

(Document (Images (Layout (Text))))

 set page [$ly Text]

Finally we get the full text in the Layout.

Now you can process the text easilly with Tcl.

But if you want to go further, you can use the Words accessor property of the Layout to retrieve some statistics about the text :

set word [$ly Words]
set nbword [$word Count]
for {set i 0} {$i < $nbword} {incr i} {
    set s [$word Item $i]
    set t [$s Text]
    set Id [$s Id]
    set LineId [$s LineId]
    set RegionId [$s RegionId]
    set FontId [$s FontId]
    set RecognitionConfidence [$s RecognitionConfidence]
    puts "Id : $Id LineId : $LineId Text : $t \t\t RegionId : $RegionId FontId : $FontId RecognitionConfidence : $RecognitionConfidence"
}

Here is the result :

 Id : 0 LineId : 0 Text : Welcome          RegionId : 0 FontId : 1 RecognitionConfidence : 209
 Id : 1 LineId : 0 Text : to                  RegionId : 0 FontId : 1 RecognitionConfidence : 210
 Id : 2 LineId : 0 Text : the                  RegionId : 0 FontId : 1 RecognitionConfidence : 211
 Id : 3 LineId : 0 Text : Tcl                  RegionId : 0 FontId : 1 RecognitionConfidence : 59
 Id : 4 LineId : 0 Text : Developer          RegionId : 0 FontId : 1 RecognitionConfidence : 209
 Id : 5 LineId : 0 Text : Xchange!          RegionId : 0 FontId : 1 RecognitionConfidence : 108
 Id : 6 LineId : 0 Text : Join                  RegionId : 1 FontId : 2 RecognitionConfidence : 208
 Id : 7 LineId : 0 Text : the                  RegionId : 1 FontId : 2 RecognitionConfidence : 210
 Id : 8 LineId : 0 Text : many                  RegionId : 1 FontId : 2 RecognitionConfidence : 210
 Id : 9 LineId : 0 Text : thousands          RegionId : 1 FontId : 2 RecognitionConfidence : 210
 Id : 10 LineId : 0 Text : of                  RegionId : 1 FontId : 2 RecognitionConfidence : 210
 Id : 11 LineId : 0 Text : software          RegionId : 1 FontId : 2 RecognitionConfidence : 207
 Id : 12 LineId : 0 Text : developers          RegionId : 1 FontId : 2 RecognitionConfidence : 209
 Id : 13 LineId : 0 Text : who                  RegionId : 1 FontId : 2 RecognitionConfidence : 210
 Id : 14 LineId : 0 Text : are                  RegionId : 1 FontId : 2 RecognitionConfidence : 210
 Id : 15 LineId : 0 Text : already          RegionId : 1 FontId : 2 RecognitionConfidence : 211
 Id : 16 LineId : 0 Text : more                  RegionId : 2 FontId : 2 RecognitionConfidence : 210
 Id : 17 LineId : 0 Text : productive          RegionId : 2 FontId : 2 RecognitionConfidence : 210
 Id : 18 LineId : 0 Text : with                  RegionId : 2 FontId : 2 RecognitionConfidence : 212
 Id : 19 LineId : 0 Text : help                  RegionId : 2 FontId : 2 RecognitionConfidence : 211
 Id : 20 LineId : 0 Text : from                  RegionId : 2 FontId : 2 RecognitionConfidence : 210
 Id : 21 LineId : 0 Text : the                  RegionId : 2 FontId : 2 RecognitionConfidence : 212
 Id : 22 LineId : 0 Text : Tcl                  RegionId : 2 FontId : 3 RecognitionConfidence : 134
 Id : 23 LineId : 0 Text : programming          RegionId : 2 FontId : 3 RecognitionConfidence : 199
 Id : 24 LineId : 0 Text : language          RegionId : 2 FontId : 3 RecognitionConfidence : 208
 Id : 25 LineId : 0 Text : and                  RegionId : 3 FontId : 2 RecognitionConfidence : 207
 Id : 26 LineId : 0 Text : the                  RegionId : 3 FontId : 2 RecognitionConfidence : 210
 Id : 27 LineId : 0 Text : Tk                  RegionId : 3 FontId : 3 RecognitionConfidence : 134
 Id : 28 LineId : 0 Text : graphical          RegionId : 3 FontId : 3 RecognitionConfidence : 196
 Id : 29 LineId : 0 Text : user                  RegionId : 3 FontId : 3 RecognitionConfidence : 206
 Id : 30 LineId : 0 Text : interface          RegionId : 3 FontId : 3 RecognitionConfidence : 115
 Id : 31 LineId : 0 Text : toolkit.          RegionId : 3 FontId : 3 RecognitionConfidence : 200
 Id : 32 LineId : 0 Text : Tcl                  RegionId : 4 FontId : 4 RecognitionConfidence : 169
 Id : 33 LineId : 0 Text : (Tool          RegionId : 4 FontId : 4 RecognitionConfidence : 206
 Id : 34 LineId : 0 Text : Command          RegionId : 4 FontId : 4 RecognitionConfidence : 210
 Id : 35 LineId : 0 Text : Language)          RegionId : 4 FontId : 4 RecognitionConfidence : 205
 Id : 36 LineId : 0 Text : is                  RegionId : 4 FontId : 4 RecognitionConfidence : 209
 Id : 37 LineId : 0 Text : a                  RegionId : 4 FontId : 4 RecognitionConfidence : 212
 Id : 38 LineId : 0 Text : very                  RegionId : 4 FontId : 4 RecognitionConfidence : 211
 Id : 39 LineId : 0 Text : powerful          RegionId : 4 FontId : 4 RecognitionConfidence : 207
 Id : 40 LineId : 0 Text : but                  RegionId : 4 FontId : 4 RecognitionConfidence : 210
 Id : 41 LineId : 0 Text : easy                  RegionId : 4 FontId : 4 RecognitionConfidence : 210
 Id : 42 LineId : 0 Text : to                  RegionId : 4 FontId : 4 RecognitionConfidence : 212
 Id : 43 LineId : 0 Text : learn          RegionId : 4 FontId : 4 RecognitionConfidence : 212
 Id : 44 LineId : 0 Text : dynamic          RegionId : 4 FontId : 4 RecognitionConfidence : 210
 Id : 45 LineId : 0 Text : programming          RegionId : 5 FontId : 4 RecognitionConfidence : 212
 Id : 46 LineId : 0 Text : language,          RegionId : 5 FontId : 4 RecognitionConfidence : 202
 Id : 47 LineId : 0 Text : suitable          RegionId : 5 FontId : 4 RecognitionConfidence : 212
 Id : 48 LineId : 0 Text : for                  RegionId : 5 FontId : 4 RecognitionConfidence : 212
 Id : 49 LineId : 0 Text : a                  RegionId : 5 FontId : 4 RecognitionConfidence : 213
 Id : 50 LineId : 0 Text : very                  RegionId : 5 FontId : 4 RecognitionConfidence : 211
 Id : 51 LineId : 0 Text : wide                  RegionId : 5 FontId : 4 RecognitionConfidence : 210
 Id : 52 LineId : 0 Text : range          RegionId : 5 FontId : 4 RecognitionConfidence : 213
 Id : 53 LineId : 0 Text : of                  RegionId : 5 FontId : 4 RecognitionConfidence : 213
 Id : 54 LineId : 0 Text : uses,          RegionId : 5 FontId : 4 RecognitionConfidence : 206
 Id : 55 LineId : 0 Text : including          RegionId : 5 FontId : 4 RecognitionConfidence : 212
 Id : 56 LineId : 0 Text : web                  RegionId : 5 FontId : 4 RecognitionConfidence : 213
 Id : 57 LineId : 0 Text : and                  RegionId : 5 FontId : 4 RecognitionConfidence : 213
 Id : 58 LineId : 0 Text : desktop          RegionId : 6 FontId : 4 RecognitionConfidence : 210
 Id : 59 LineId : 0 Text : applications,  RegionId : 6 FontId : 4 RecognitionConfidence : 207
 Id : 60 LineId : 0 Text : networking,          RegionId : 6 FontId : 4 RecognitionConfidence : 204
 Id : 61 LineId : 0 Text : administration, RegionId : 6 FontId : 4 RecognitionConfidence : 204
 Id : 62 LineId : 0 Text : testing          RegionId : 6 FontId : 4 RecognitionConfidence : 212
 Id : 63 LineId : 0 Text : and                  RegionId : 6 FontId : 4 RecognitionConfidence : 214
 Id : 64 LineId : 0 Text : many                  RegionId : 6 FontId : 4 RecognitionConfidence : 212
 Id : 65 LineId : 0 Text : more.          RegionId : 6 FontId : 4 RecognitionConfidence : 201
 Id : 66 LineId : 0 Text : Open                  RegionId : 6 FontId : 4 RecognitionConfidence : 210
 Id : 67 LineId : 0 Text : source          RegionId : 7 FontId : 4 RecognitionConfidence : 213
 Id : 68 LineId : 0 Text : and                  RegionId : 7 FontId : 4 RecognitionConfidence : 214
 Id : 69 LineId : 0 Text : business-friendly, RegionId : 7 FontId : 4 RecognitionConfidence : 204
 Id : 70 LineId : 0 Text : Tcl                  RegionId : 7 FontId : 4 RecognitionConfidence : 125
 Id : 71 LineId : 0 Text : is                  RegionId : 7 FontId : 4 RecognitionConfidence : 214
 Id : 72 LineId : 0 Text : a                  RegionId : 7 FontId : 4 RecognitionConfidence : 214
 Id : 73 LineId : 0 Text : mature          RegionId : 7 FontId : 4 RecognitionConfidence : 211
 Id : 74 LineId : 0 Text : yet                  RegionId : 7 FontId : 4 RecognitionConfidence : 213
 Id : 75 LineId : 0 Text : evolving          RegionId : 7 FontId : 4 RecognitionConfidence : 210
 Id : 76 LineId : 0 Text : language          RegionId : 7 FontId : 4 RecognitionConfidence : 212
 Id : 77 LineId : 0 Text : that                  RegionId : 7 FontId : 4 RecognitionConfidence : 210
 Id : 78 LineId : 0 Text : is                  RegionId : 7 FontId : 4 RecognitionConfidence : 214
 Id : 79 LineId : 0 Text : truly          RegionId : 7 FontId : 4 RecognitionConfidence : 211
 Id : 80 LineId : 0 Text : cross          RegionId : 8 FontId : 4 RecognitionConfidence : 212
 Id : 81 LineId : 0 Text : platform,          RegionId : 8 FontId : 4 RecognitionConfidence : 209
 Id : 82 LineId : 0 Text : easily          RegionId : 8 FontId : 4 RecognitionConfidence : 212
 Id : 83 LineId : 0 Text : deployed          RegionId : 8 FontId : 4 RecognitionConfidence : 212
 Id : 84 LineId : 0 Text : and                  RegionId : 8 FontId : 4 RecognitionConfidence : 214
 Id : 85 LineId : 0 Text : highly          RegionId : 8 FontId : 4 RecognitionConfidence : 211
 Id : 86 LineId : 0 Text : extensible.          RegionId : 8 FontId : 4 RecognitionConfidence : 204
 Id : 87 LineId : 0 Text : Tk                  RegionId : 9 FontId : 4 RecognitionConfidence : 190
 Id : 88 LineId : 0 Text : is                  RegionId : 9 FontId : 4 RecognitionConfidence : 210
 Id : 89 LineId : 0 Text : a                  RegionId : 9 FontId : 4 RecognitionConfidence : 210
 Id : 90 LineId : 0 Text : graphical          RegionId : 9 FontId : 4 RecognitionConfidence : 212
 Id : 91 LineId : 0 Text : user                  RegionId : 9 FontId : 4 RecognitionConfidence : 210
 Id : 92 LineId : 0 Text : interface          RegionId : 9 FontId : 4 RecognitionConfidence : 212
 Id : 93 LineId : 0 Text : toolkit          RegionId : 9 FontId : 4 RecognitionConfidence : 212
 Id : 94 LineId : 0 Text : that                  RegionId : 9 FontId : 4 RecognitionConfidence : 212
 Id : 95 LineId : 0 Text : takes          RegionId : 9 FontId : 4 RecognitionConfidence : 211
 Id : 96 LineId : 0 Text : developing          RegionId : 9 FontId : 4 RecognitionConfidence : 211
 Id : 97 LineId : 0 Text : desktop          RegionId : 9 FontId : 4 RecognitionConfidence : 212
 Id : 98 LineId : 0 Text : applications          RegionId : 9 FontId : 4 RecognitionConfidence : 212
 Id : 99 LineId : 0 Text : to                  RegionId : 10 FontId : 4 RecognitionConfidence : 212
 Id : 100 LineId : 0 Text : a                  RegionId : 10 FontId : 4 RecognitionConfidence : 214
 Id : 101 LineId : 0 Text : higher          RegionId : 10 FontId : 4 RecognitionConfidence : 212
 Id : 102 LineId : 0 Text : level          RegionId : 10 FontId : 4 RecognitionConfidence : 211
 Id : 103 LineId : 0 Text : than          RegionId : 10 FontId : 4 RecognitionConfidence : 212
 Id : 104 LineId : 0 Text : conventional  RegionId : 10 FontId : 4 RecognitionConfidence : 212
 Id : 105 LineId : 0 Text : approaches.          RegionId : 10 FontId : 4 RecognitionConfidence : 189
 Id : 106 LineId : 0 Text : Tk                  RegionId : 10 FontId : 4 RecognitionConfidence : 195
 Id : 107 LineId : 0 Text : is                  RegionId : 10 FontId : 4 RecognitionConfidence : 212
 Id : 108 LineId : 0 Text : the                  RegionId : 10 FontId : 4 RecognitionConfidence : 212
 Id : 109 LineId : 0 Text : standard          RegionId : 10 FontId : 4 RecognitionConfidence : 211
 Id : 110 LineId : 0 Text : GUI                  RegionId : 10 FontId : 4 RecognitionConfidence : 205
 Id : 111 LineId : 0 Text : not                  RegionId : 10 FontId : 4 RecognitionConfidence : 211
 Id : 112 LineId : 0 Text : only          RegionId : 10 FontId : 4 RecognitionConfidence : 211
 Id : 113 LineId : 0 Text : for                  RegionId : 11 FontId : 4 RecognitionConfidence : 211
 Id : 114 LineId : 0 Text : Tcl,          RegionId : 11 FontId : 4 RecognitionConfidence : 167
 Id : 115 LineId : 0 Text : but                  RegionId : 11 FontId : 4 RecognitionConfidence : 212
 Id : 116 LineId : 0 Text : for                  RegionId : 11 FontId : 4 RecognitionConfidence : 212
 Id : 117 LineId : 0 Text : many          RegionId : 11 FontId : 4 RecognitionConfidence : 213
 Id : 118 LineId : 0 Text : other          RegionId : 11 FontId : 4 RecognitionConfidence : 212
 Id : 119 LineId : 0 Text : dynamic          RegionId : 11 FontId : 4 RecognitionConfidence : 212
 Id : 120 LineId : 0 Text : languages,          RegionId : 11 FontId : 4 RecognitionConfidence : 204
 Id : 121 LineId : 0 Text : and                  RegionId : 11 FontId : 4 RecognitionConfidence : 213
 Id : 122 LineId : 0 Text : can                  RegionId : 11 FontId : 4 RecognitionConfidence : 210
 Id : 123 LineId : 0 Text : produce          RegionId : 11 FontId : 4 RecognitionConfidence : 212
 Id : 124 LineId : 0 Text : rich,          RegionId : 11 FontId : 4 RecognitionConfidence : 204
 Id : 125 LineId : 0 Text : native          RegionId : 11 FontId : 4 RecognitionConfidence : 211
 Id : 126 LineId : 0 Text : applications  RegionId : 12 FontId : 4 RecognitionConfidence : 210
 Id : 127 LineId : 0 Text : that          RegionId : 12 FontId : 4 RecognitionConfidence : 212
 Id : 128 LineId : 0 Text : run                  RegionId : 12 FontId : 4 RecognitionConfidence : 213
 Id : 129 LineId : 0 Text : unchanged          RegionId : 12 FontId : 4 RecognitionConfidence : 210
 Id : 130 LineId : 0 Text : across          RegionId : 12 FontId : 4 RecognitionConfidence : 214
 Id : 131 LineId : 0 Text : Windows,          RegionId : 12 FontId : 4 RecognitionConfidence : 202
 Id : 132 LineId : 0 Text : Mac                  RegionId : 12 FontId : 4 RecognitionConfidence : 206
 Id : 133 LineId : 0 Text : OS                  RegionId : 12 FontId : 4 RecognitionConfidence : 177
 Id : 134 LineId : 0 Text : X,                  RegionId : 12 FontId : 4 RecognitionConfidence : 186
 Id : 135 LineId : 0 Text : Linux          RegionId : 12 FontId : 4 RecognitionConfidence : 205
 Id : 136 LineId : 0 Text : and                  RegionId : 12 FontId : 4 RecognitionConfidence : 212
 Id : 137 LineId : 0 Text : more.          RegionId : 12 FontId : 4 RecognitionConfidence : 202

References :

- http://msdn.microsoft.com/en-us/library/aa202819%28v=office.11%29.aspx

- http://www.documentsnap.com/using-microsoft-office-document-imaging-to-ocr-for-free/

PO Added OCR functionality in CAWT version 1.0.2.

GS (20130730) Nice addition. CAWT is becoming a usefull toolbox.