Count the crossing words
Slip, 18 + 3 = 21 bytes

&gt;? ( +(X|$^)&lt;&lt;){2}


Run with the flags no (hence the +3), and uses space/X instead of space/#. Annoyingly this is longer than CJam/Pyth, but I guess Slip wasn't designed to be particular golfy...

Try it online. Note that the first example is missing spaces on a few lines.

Explanation

&gt;?           Optionally turn right, hence matching either horizontally or vertically
[space]      Match a space
(    ){2}    Group, twice:
[space]+       Match 1+ spaces
(X|$^)         Either an X or the boundary of the grid
&lt;&lt;             Reverse the match pointer by turning left twice


The n flag makes output print the number of matches, and the o flag enables overlapping matches starting from the same square. The reason for the back-and-forth is because Slip tries matches starting from every square, and we want to make sure we only match a full row rather than a partial one. Slip only returns unique matches, even if they started from different positions.

Note: Originally I had &gt;?(  +(X|$^)&lt;&lt;){2}, with the first space on the inside. This would miss some cases with 2 space long words at the edge, since the pointer would go like this:

XXX       XXX       XXX       XXX
X&gt;        X &gt;       X&lt;        &lt;
XXX       XXX       XXX       XXX

[sp]    [sp]+$^    &lt;&lt;[sp]    [sp]+   (uh oh match fails)