Below are some techniques that together with @nikie answer give you a powerful way of detecting specific table grids.

The Rubber Band Algorithm
=========================

The 3 columns to be detected must be very close to 40%, 15% and 45% of the total table width. Similarly, the line heights have a proportion to follow.  So the first problem to solve is how to identify a sequence that matches a proportions pattern.

I first tried to look for a _Mathematica_ built-in function as this is a very generic task. The closest I could find is the `SequenceAlignment` function but it work only on strings. So I developed my own algorithm which is explained in this [video](http://www.youtube.com/watch?v=d_FntrHdRyY)

This is how I implemented it:

    rubberBandComparePair[wanted_List, suspectsSubset_List] :=
      Module[{rubberBand, reducedSuspects},
        rubberBand = Rescale[wanted, 
                             { Min@wanted        , Max@wanted         },
                             { Min@suspectsSubset, Max@suspectsSubset }];
        
        reducedSuspects = If[Length @ rubberBand < Length @ suspectsSubset, 
                             Flatten[Nearest[suspectsSubset, #] & /@ rubberBand],
                             suspectsSubset];
        
        {EuclideanDistance[rubberBand, reducedSuspects] /
         (Max@reducedSuspects - Min@reducedSuspects),
         reducedSuspects}
      ] /; Length@wanted <= Length@suspectsSubset
   
   
    rubberBandCompare[wanted_List, suspects_List] := 
      Module[{w, k = Length @ wanted, costs, sortedSuspects},
        sortedSuspects = Union @ Sort @ suspects;
        w = Length @ sortedSuspects;
        costs = Flatten[#, 1] & @ 
          Table[rubberBandComparePair[wanted, sortedSuspects[[start ;; end]]],
                {start, 1, w - k + 1},
                {end, start + k - 1, w}];
        SortBy[costs, First][[1]]
      ] /; Length @ Union @ suspects >= Length @ wanted
    
    rubberBandCompare[wanted_List, suspects_List] := 
    {∞, {}} /; Length[Union@suspects] < Length[wanted]

For example if we are looking for a sequence proportional to {1,2,4} in the list {9, 10, 15, 21, 40, 55}:

    In[1] = rubberBandCompare[{1, 2, 4}, {9, 10, 15, 21, 40, 55}]
    Out[1] = {1/30, {10, 21, 40}}

and we have detected that {10,21,40} matches {1,2,4} with an error of 1/30. Notice that this error is a relative error that does not change with scale:

    In[2] = rubberBandCompare[{1, 2, 4}, {90, 100, 150, 210, 400, 550}]
    Out[2] = {1/30, {100, 210, 400}}
    

Detecting horizontal and vertical lines
=======================================

In order to detect lines we can use `ImageLines[]` or we can use the lower lever `Radon[]`. The advantage of `ImageLines` is that it is fast and simple, but it always looks for lines in all directions whereas `Radon` lets you look for lines in a specific direction.  I implemented solutions using both, but I'll explain here only the ImageLines[] solution which worked well in a large number of cases.

`ImageLines` returns a list of lines where each line is defined by 2 points. So we first write this very simple function to calculate the angle of a line:

    lineAngle::usage = "lineAngle[{{x1,y1},{x2,y2}}] returns the angle of the line that goes
                        through points {x1,y1} and {x2,y2}.";
                        
    lineAngle[{{ x_?NumericQ, y_?NumericQ},{x_          , y_          }}]:=Indeterminate
    lineAngle[{{ x_?NumericQ,y1_?NumericQ},{x_          , y2_?NumericQ}}]:=Pi/2
    lineAngle[{{x1_?NumericQ,y1_?NumericQ},{x2_?NumericQ, y2_?NumericQ}}]:=ArcTan[(y2-y1)/(x2-x1)]
    
When we call ImageLines later on, it will return a list of lines, so we need a function to select the ones that are close to the desired direction. For this I wrote this function:

    selectLinesNearAngle::usage = 
        "selectLinesNearAngle[{{{x1,y1},{x2,y2}},...}, angle, tolerance] \
         selects the lines that have an inclination of angle +/- tolerance. \
         Each line is defined by a pair of points.";

    selectLinesNearAngle[lines_List, angle_?NumericQ, angularTolerance:(_?NumericQ): 4°] :=
      Select[
        lines, 
        Or @@ Thread[Abs[lineAngle[#] - angle + {-Pi, 0, Pi}] < angularTolerance] &]

Now we are ready to write our modified version of `ImageLines` for horizontal or vertical lines:

    Options[angularImageLines] = {"Debug" -> False};

    angularImageLines[img_Image, α_, OptionsPattern[]]:=
      Module[
        {lines, selectedLines, binarizedImage},
        binarizedImage = Binarize@GaussianFilter[img, 3, Switch[α, 0, {2,0}, Pi/2, {0,2}]];
        lines = ImageLines[binarizedImage];
        selectedLines = selectLinesNearAngle[lines,α];
        If[OptionValue["Debug"],
           Print[Show[binarizedImage, Epilog -> {Green, Line /@ selectedLines}]]];
        selectedLines
      ]/; α==0 || α==Pi/2

Notice that `binarizedImage` is using GaussianFilters as @nikie recommends. This is an example of how it works:

![Mathematica graphics](https://i.sstatic.net/vxcuF.png)


Searching for the lines that match wanted proportions
=====================================================

It is now the time to use `rubberBandCompare` and `angularImageLines` together:

    matchedLines[wanted_List, g_Image, α_] := 
      Module[
        {candidateSequence, suspects, error, bestMatch, lines}, 
        lines = angularImageLines[g, α];
        suspects = Sort[Switch[α, Pi/2, First, 0, Last] /@ ((#1[[1]] + #1[[2]])/2 & ) /@ lines]; 
        candidateSequence = rubberBandCompare[wanted, suspects]; 
        If[Head[candidateSequence] === rubberBandCompare, Return[$Failed]]; 
        {error, bestMatch} = candidateSequence;  
        If[α == Pi/2 && error > 0.01176495, Return[$Failed]];
        If[α == 0    && error > 0.02994115, Return[$Failed]];
        (Cases[lines, {{x1_, y1_}, {x2_, y2_}} /; 
         Switch[α, Pi/2, (x1+x2)/2, 0, (y1+y2)/2] == #1, 1, 1][[1]] & ) /@ candidateSequence[[2]]
      ]

Notice that the error needs to be lower than a calibration constant for the solution to be accepted. These constants are found using a set of sample files, and making a histogram of the errors.

This is an example:

![Mathematica graphics](https://i.sstatic.net/337Eb.png)

Lines Intersections
===================

This function finds the intersection of two lines. It was found in the `PlaneGeometry.m` package by Eric Weisstein (see <http://mathworld.wolfram.com/Line-LineIntersection.html>):

    Intersections[Line[{{x1_, y1_}, {x2_, y2_}}], 
                  Line[{{x3_, y3_}, {x4_, y4_}}]] := 
      Module[
        {d   = (x1-x2) * (y3-y4) - (x3-x4) * (y1-y2), 
         d12 = Det[{{x1, y1}, {x2, y2}}], 
         d34 = Det[{{x3, y3}, {x4, y4}}]}, 
        If[NumericQ[d] && d == 0., 
           PointAtInfinity,
           {Det[ {{d12, x1-x2}, {d34, x3-x4}} ]/d, 
            Det[ {{d12, y1-y2}, {d34, y3-y4}} ]/d}]
      ]

Uniformize Background
=====================

This technique is explained by @nikes [here](http://dsp.stackexchange.com/questions/1932/what-are-the-best-algorithms-for-document-image-thresholding-in-this-example/1934#1934). I just added the `/.0. -> 0.0001` in order to avoid division by zero when large pure black areas are present:

    uniformizeBackground[g_Image] := Image[ImageData[g]/(ImageData[Closing[g, DiskMatrix[5]] /. 0. -> 0.0001)]
    

Grid Centers
============

    gridCenters[g_Image] := 
      Module[
        {gAdjusted, hLines, vLines, 
         wantedX = {16.5, 224.5, 302.5, 535.5}, 
         wantedY = {22.5,  50.5,  97.5, 125.5, 154.5}}, 

        gAdjusted = uniformizeBackground[g];
        {hLines, vLines} = {{wantedY, 0}, {wantedX, Pi/2}} /. 
                    {wanted_List, (α_)?NumericQ} :> matchedLines[wanted, gAdjusted, α, opts]; 
        If[hLines == $Failed || vLines == $Failed, Return[$Failed]]; 
        Outer[Intersections, Line /@ hLines, Line /@ vLines]
      ]

The `wantedX` and `wantedY` are found from a sample image using the get coordinates tool from the drawing tools palette.
Once we have the grid centers, we can use the same techniques that @nikie used to identify and straighten any of the cells.

This is an example:

![very light table](https://i.sstatic.net/3TC5b.png)

![gridCenters example](https://i.sstatic.net/J9IFz.png)

![Mathematica graphics](https://i.sstatic.net/RrVIt.png)

A final comment
===============

My main contribution in this answer in the rubberBandCompare function which useful to other people in other areas. If it was already invented somewhere else, please let me know.