Showing posts with label Windows. Show all posts
Showing posts with label Windows. Show all posts

Thursday, June 21, 2012

Tesseract OCR: Interactive Debugging Continued. Baseline Viewer

Here I'll describe a method of viewing baselines in Tesseract's interactive debug environment.

Those who use Tesseract 3.02 should first read my former post called Tesseract OCR: Setting Up Interactive Debug Environment On Windows and complete all steps from it. However instead of the installation suite mentioned there you would need another which contains updated Tess config files as Tesseract developers had renamed/removed a number of internal debug parameters since version 3.01 used in that tutorial. Download the updated suite at http://www.4shared.com/zip/FnP8RSu0/tess_debug_3_02.html. Version 3.01 users can still use the old installation suite.

So now that you've completed the step 5 from the former tutorial and the debug window has appeared, do the following:
  1. In the main menu choose Modes->Show BL Norm Word. No apparent reaction from the UI should follow. This is normal.
  2. Now click on any word you're interested in. A new window titled BlnWords should appear.
  3. At first sight the BlnWords window is empty. But in fact this is not true. Nothing is visible only because of the quirky scaling logic used by ScrollView. To find something inside the window you need to use window scrollbars to pan and mouse scroll wheel to scale up/down. I suggest the following sequence for initial setting of the view:
    • slowly drag down vertical scrollbar thumb until you see baselines and/or outlines,
    • move horizontal scrollbar thumb approximately to the center,
    • use mouse wheel to scale the window contents properly,
    • you may also resize the window to your taste.
  4. While you click other words in the main window the contents of the BlnWords window updates. You can adjust the view as needed using the methods described above.
What is displayed inside the BlnWords window are so called baseline normalized words. In this type of view words are shown as if their baselines (which can be curved and/or inclined in the source image) get straightened and positioned strictly horizontally. In addition to the baseline the window shows also x-height, ascender and descender lines. See more at Wikipedia: x-height. Using this view you can clearly see if a baseline found by Tesseract is right or wrong: incorrect baselines cause characters to "jump" or "fall."

Baseline finding greatly influences character classification. Various baseline-relative positions of the same character can lead to completely different recognition results. That's why incorrect baselines often serve as sources of errors in Tesseract recognition.

A few examples. Let's take the "conventional" phototest.tif file:
The main debug window should look like this:
All baselines seem to be found perfectly:
For more complex images things go worse. Here I've taken an photographic image of a restaurant receipt. In the image the receipt appears to be inclined and perspectively distorted. The paper is a bit curved, just like it usually happens with receipts. The image is precooked by my image processor (only done binarization and noise cleanup) so that Tesseract is able process it, at some degree of success.
The main debug window already shows several segmentation failures. Some characters are grayed out and some are missing completely:
In BlnWords one can see that many baselines are good but some are determined incorrectly, for instance:
Also there are some epic failures, like these (meaning that characters from adjacent rows get segmented into a single word):
So why would you want to use this debugging method? It can be of use when you're investigating the reasons of some Tesseract failure. Baseline viewer can help you to see that an additional preprocessing is required to cope with the image or a set of images, either programmatic or by means of 3rd party software such as ImageMagick. Passing image block by block (i.e. full or partial pre-segmentation) might also help. Another approach is tweaking internal Tesseract segmentation and baseline finding parameters via config files. Yet another approach is source code changes.
more >>

Monday, March 7, 2011

Visual C++ 2010: Detecting Memory Leaks For Global Variables

This article is a hint for those who feel desperate with finding the origin of a memory leak in their programs. I suppose you've already read the Microsoft's documentation on this topic - Finding Memory Leaks Using the CRT Library - and set up your project to enable leak detection.

The documentation states that if you did everything properly, the Output window should display all the leaked memory blocks along with source file names and line numbers. However sometimes it's not the case and there's nothing shown except a bare memory address and allocation size. And you end up staring at these numbers, puzzling over what you could do wrong with leak detection setup, placing exit()s all over the code and trying to understand logically where those damned leaks could originate from.

Actually this might be not your fault that you don't see line numbers. To be precise, it's not your fault but it's a problem of your project's design. Probably your project uses many global variables which get initialized long before source line number tracking is in effect and thus in the end debug CRT detects leaks but cannot report line numbers. Global variable usage is unavoidable in large and complex projects so we need some method to fix such leaks.

The good news is that such method exists. The bad news is that it involves much manual work. But at least it works.
  • First you'll need to make a whole program run to get the entire memory leak report in the Output window. Copy the memory leak report somewhere, e.g. to a Notepad window, as later you'll need these numbers in curly braces called memory allocation numbers.
  • Open the crt0dat.c file in Visual Studio. I assume that during the Visual C++ installation you had chosen the default folder, so that file should be located in "C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src".
  • Within the crt0dat.c file, search for the following string (no quotes): "__cdecl _initterm_e". Place a breakpoint at the first statement of the _initterm_e() function.
  • Run your program again. The execution stops at your breakpoint. Now go to the Watch window and type "_crtBreakAlloc" (no quotes) in the Name column. In the Value column most probably you'll see -1.
  • Disable the breakpoint in crt0dat.c. You won't need it to be hit again during this program run.
  • Now get back to your Notepad window and copy to the clipboard the first of the memory allocation numbers in curly braces. Go to the Watch window in Visual Studio and in the Value column replace the value shown with the value in the clipboard. Press Enter.
  • Resume the execution by hitting F5 or choosing Continue from the menu. After a while Visual Studio should display a message that reads "<YourProgram> has triggered a breakpoint" and stops at some location within the CRT debug code, most likely in the dbgheap.c file.
  • Now go to the Call Stack window and scan it from the top to the bottom until you find a function that is known to be written by you. Now you can conclude on what can be the reason of the memory leak. It might turn so that at the top or in the middle of the call stack there are gray lines containing only addresses. This means that symbol information is absent for some libraries used in your project. Hit Shift-F11 until you get rid of gray lines before the known functions. Ignore "No source code available" messages if they appear and keep hitting Shift-F11.
  • Once you finished your investigation with one of the leaks, you may continue with another without restarting the program. Just get the next memory allocation number from the previous memory leak report, paste it into the Value column for _crtBreakAlloc in the Watch window and hit F5. Investigate the cause of the leak. Repeat these steps until you examine all leaks you have. This works thanks to that memory leaks reported in the same order as the corresponding memory allocations happen.
Why do we need a breakpoint inside crt0dat.c? Because need to capture a memory allocation event before our main() function starts. Once main() is entered, all global variable initializations already happened and we've lost the chance to track allocation events either by hardcoding allocation numbers (using statements like "_crtBreakAlloc = 1234;") or by editing the _crtBreakAlloc watch value during the debug suspend mode. The _initterm_e() function just seems to be a good choice to place a breakpoint.

It is crucial to run your program every time with the same input conditions so as to memory allocation numbers stay unchanged between runs. Once you fixed a leak, you'll need to repeat the whole process from the start as allocation numbers likely have changed.

Hope this info will help fixing your very own leaks.
more >>

Sunday, February 6, 2011

Tesseract OCR: Setting Up Interactive Debug Environment On Windows

The following are the step-by-step instructions for setting up and running Tesseract’s internal state viewer (called "ScrollView") on Windows.

Although there already exists a dedicated wiki article (and the instructions herein are based upon it), it can cause some confusion for Tesseract newbies and those who don’t feel comfortable with the technology mixture required for the setup.
  1. First off, you need to make sure you have Java Runtime Environment (or simply “Java”) installed. If you haven’t, then go to http://www.java.com/en/download/manual.jsp and download it. Most likely, an offline version for Windows will suit you well. After the download completes, run the downloaded executable, follow several wizard steps and wait until the installation is finished.
  2. Tesseract’s viewer requires a few JAR files which hadn’t been changed for years and are a bit of hassle to get. So I decided to pack them all into a single archived installation suite along with the Tesseract 3.01 executable and other required minimal infrastructure. You can grab it here: http://www.4shared.com/get/Z4gnbJdP/tess_debug.html
  3. Then create some folder say C:\tess_debug and extract into it all the files from the downloaded installation suite preserving the folder structure.
  4. Launch the Windows Command Prompt and change the current directory to your folder by running the command
    cd C:\tess_debug
  5. Now you are ready to launch the Tesseract debug environment. My installation suite contains the test file phototest.tif so the command to display segmentation data for it would be
    tesseract phototest.tif test1 segdemo inter
    Type the above command in the Windows Command Prompt. The viewer window containing letter outlines should appear shortly.
    A few words on the command-line parameters used:
    • test1 indicates the name of the txt file which will be created as a result of Tesseract’s work. It will contain the recognized text.
    • segdemo and inter are config files required to run Tesseract in this kind of debug mode (segmentation debugging); you can see these within installation suite’s folder.
    • To run segmentation debugging with your file, indicate its name instead of phototest.tif. If your file is located outside installation suite’s folder then you’ll need to prefix the filename with the path.
    • The above command runs recognition using the default language file eng.traineddata. To use your own language file, specify it using the -l command-line argument e.g.
      tesseract image.tif test1 -l yourlang segdemo inter
      In order for this command to run successfully, the language file called yourlang.traneddata should be placed into the tessdata subfolder of the installation suite folder.
  6. The above paragraph describes how to debug the segmentation. Nearly the same technique is used to debug the classifier. One thing you need in order to change the debugging mode is to replace in the command line segdemo with matdemo, like this:
    tesseract phototest.tif test1 matdemo inter
    NOTE: The matdemo config file can also be found in the installation suite folder.
This is all that can be said about installation of and launching the Tesseract viewer. For information on how to use Tesseract viewer’s user interface please refer to http://code.google.com/p/tesseract-ocr/wiki/ViewerDebugging
more >>

Thursday, November 4, 2010

Getting Boost.Regex + Unicode to work with Microsoft VC++ 2010

[ This article pertains to Boost version 1.44. It may or may not remain useful in the future, when newer Boost versions appear, depending on how Boost.Regex’s developers would arrange the build process. ]

Although the subject above may seem to be overly specific, I think many people might want to use regular expressions with international text support in their programs being developed in Windows/Microsoft environment. I’m in no way a Boost.Regex expert or even seasoned Boost user. I just would like to share my “newbie” experience with programmers who are trying to achieve the same as I did. And for the current Boost’s version - 1.44 - it is not so easy.
And one thing should be mentioned before we start. I adhere to the principle of least resistance. For the process of software library linking that means the following: use vendor-supplied compiled binaries as much as you can and use your hands as sparingly as you can. Probably the moment when you need to build a library from sources (which can be quite troublesome) or do some manual tweaking will come. Maybe, but it’s a future, so leave all hassles for that future. For now we are going to get our libraries up and running, and to do it fast. At least on Windows platform, this approach seems to be sound.

OK, let’s start. As it’s noted here, to support Unicode you have two approaches: the simple one and the good one. For some cases the simple approach can suffice however actually it is not portable and has several disadvantages. To help you build a true Unicode-aware application, Boost.Regex - one of the best regular expression libraries - requires ICU – one of the best Unicode libraries. The following describes how to get Boost.Regex and ICU work together.

First we need to obtain the latest release of ICU from here. In the download page choose ICU4C as we need to interface the ICU library with C/C++ programs. Download the Windows binaries .zip file and unpack it to some folder on your hard drive, say C:\Distr\icu.

What we need to do in order to build Boost.Regex with ICU is described in detail here. However building from scratch is still not a preferred option, and when I was looking for an alternative I came across the BoostPro Installer which can provide us with binaries for every possible Boost library, every compiler, threading model, etc. But… BoostPro does not cover per-library specifics such as ICU-enabled Regex.

Therefore we have no other choice but to compile Boost.Regex by hand. However BoostPro Installer still can be of use for us because it can serve as a convenient download tool that will provide us with Boost sources and (what is more important) some compiled Boost tools (you will be able to see below why we need them). For now run BoostPro and proceed until the wizard page appears where compilers and variants can be selected. There you should select no checkboxes at all. On the next page leave only four checkboxes checked at the top of the list. Then advance to the end of the wizard and wait for files to be downloaded and installed.

Assume you chose to install Boost to the default installation folder (C:\Program Files\boost\boost_1_44). In the C:\Program Files\boost\boost_1_44\libs\regex\build folder you will find several vc*.mak files which – what a pleasant surprise! - outnumber those mentioned in the documentation on the Boost's web site. But what is not so good surprise is that they lack one for MSVC10. Running vc9.mak by VC10’s nmake.exe gives many errors and unknown option warnings which look a bit scary. Editing makefiles manually is not an option for us as we need the result as soon as possible.

Somehow guys at BoostPro had managed to built Regex library with MSVC10 and are unlikely to conceal their secret knowledge from the public, so it has to be somewhere around. In Boost.Regex’s build folder there are also some .sh files which are Unix shell scripts, a .cpp file and a cryptic Jamfile.v2. Relating this name and the information obtained from Regex’s building guide lets us conclude that we need a program called bjam (which in fact is a part of Boost’s own build system) to run Jamfile.v2. Fortunately, as a result of installation by BoostPro, a compiled bjam.exe can be found in the C:\Program Files\boost\boost_1_44\bin folder.

Now let’s launch a command line window and change the working directory to Regex’s build folder. The straight-forward (partially borrowed from the Regex installation guide and Google search results) command
"C:\Program Files\boost\boost_1_44\bin\bjam" -sICU_PATH="C:\Distr\icu" toolset=msvc-10.0 release threading=multi link=shared

among other info outputs an undesired message

has_icu builds : no,

which indicates that the test program has_icu_test.exe could not be compiled or linked correctly and the build script falls back to compilation/linking of Regex without ICU. After struggling for a while with this strange problem I found that by some reason the build tool requests for debug versions of ICU libraries which of course I have none of and didn’t intend to use. I must confess, I’m not fond of studying new software tools that I’m sure I wouldn’t use much on but here I had no other choice. Eventually I found that ‘lib’ rule sets select wrong alternatives, even when configuration features are explicitly provided via command-line arguments, just like in the command above. E.g. this block in the Jamfile.v2 file

   lib icuuc : : <search>$(ICU_PATH)/lib <link>shared <runtime-link>shared ;
   lib icuuc : : <toolset>msvc <variant>debug <name>icuucd <search>$(ICU_PATH)/lib <link>shared <runtime-link>shared ;
   lib icuuc : : <name>this_is_an_invalid_library_name ;

chooses the second line, i.e. the icuucd library (debug version of one of ICU’s libraries) but supposed to choose the first line, i.e. icuuc library (release version of that ICU’s library). Other rule sets behave in a similar way. I had no time to investigate why this may happen and I don’t see any reasons not to follow the path of least resistance and use a no-brainer: I commented out in the Jamfile.v2 file all alternatives which may lead to selection of incorrect libraries, like this:

   lib icuuc : : <search>$(ICU_PATH)/lib <link>shared <runtime-link>shared ;
#   lib icuuc : : <toolset>msvc <variant>debug <name>icuucd <search>$(ICU_PATH)/lib <link>shared <runtime-link>shared ;
#   lib icuuc : : <name>this_is_an_invalid_library_name ;
#   lib icudt : : <search>$(ICU_PATH)/lib <name>icudata <link>shared <runtime-link>shared ;
   lib icudt : : <search>$(ICU_PATH)/lib <name>icudt <toolset>msvc <link>shared <runtime-link>shared ;
#   lib icudt : : <name>this_is_an_invalid_library_name ;
#   lib icuin : : <search>$(ICU_PATH)/lib <name>icui18n <link>shared <runtime-link>shared ;
#   lib icuin : : <toolset>msvc <variant>debug <name>icuind <search>$(ICU_PATH)/lib <link>shared <runtime-link>shared ;
   lib icuin : : <toolset>msvc <variant>release <name>icuin <search>$(ICU_PATH)/lib <link>shared <runtime-link>shared ;
#   lib icuin : : <name>this_is_an_invalid_library_name ;

Mostly this is it. Save corrections to the Jamfile.v2 file and run the above command again. This should work the right way. My configuration for bjam was release threading=multi link=shared which means: I need release (non-debug) version, I need multi-threaded, I need DLL. You might probably want another configuration, then you may change release to debug, multi to single or shared to static.

When everything is going right, at the beginning of bjam’s console output you should see a message has_icu builds : yes.

As a result of bjam’s work, all generated files will be placed into the C:\Program Files\boost\boost_1_44\bin.v2\libs\regex\build\msvc-10.0\release\threading-multi folder (the last two subfolders can vary depending on your options).

To double check, you can examine a couple of .rsp files which also would reside in the output folder. E.g. the file c_regex_traits.obj.rsp should contain the line

   -DBOOST_HAS_ICU=1

And the file boost_regex-vc100-mt-1_44.dll.rsp should contain the lines

   "icuuc.lib"                   
   "icudt.lib"
   "icuin.lib"

That’s it. For how to use ICU-powered Boost.Regex please refer here
more >>