g | x | w | all
Bytes Lang Time Link
010Vyxal 3250622T210519Zpacman25
038J210213T194931ZJonah
nan150605T161842Zedc65
011CJam150605T141306ZMartin E
013Pyth150605T153703ZJakube
nanSlip150605T144322ZSp3000
081Haskell150605T150135Znimi

Vyxal 3, 10 bytes

TJ¨※“⎘⌊\“L

Vyxal It Online!

flagless ten, takes input with 0 for black space and 1 for white space

TJ¨※“⎘⌊\“L­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁤​‎⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌­
TJ          # ‎⁡Join with transpose
  ¨※        # ‎⁢group each row/column by consecutive equal values
    “⎘⌊     # ‎⁣join on nothing and convert to number, giving a unary length for each word in the puzzle and 0 to represent some amount black spaces
       \“   # ‎⁤reject by absolute value less than or equal to 1
         L  # ‎⁢⁡length of remaining list
💎

Created with the help of Luminespire.

J, 38 bytes

1#.1<[:#;._1 1:,@,.[:(,!.1|:)'#'&=;._2

Try it online!

JavaScript (ES6) 87 121 147

Build the transposition of input string and append it to input, then count the strings of 2 or more spaces.

Run the snippet in Firefox to test.

Credits @IsmaelMiguel, a solution for ES5 (122 bytes):

function F(z){for(r=z.split(/\n/),i=0;i<r[j=0][L='length'];i++)for(z+='#';j<r[L];)z+=r[j++][i];return~-z.split(/  +/)[L]};

F=z=>
(
  r=z.split(/\n/),
  [r.map(r=>z+=r[i],z+='#')for(i in r[0])],
  ~-z.split(/  +/).length
)

// TEST
out=x=>O.innerHTML += x + '\n';

[
'     #    #    \n     #    #    \n          #    \n   #   #       \n###     ##   ##\n               \n     ##   #    \n   #       #   \n    #   ##     \n               \n##   ##     ###\n       #   #   \n    #          \n    #    #     \n    #    #     ', '##\n #\n##', '    #\n    #\n    #',
 '######\n#    #\n  ####\n# ## #\n# ## #\n#### #',
 '   #    ##   #       \n   #    #    #       \n   #         #       \n       #     ###   ##\n    #       #        \n##   #   #           \n        #       ##   \n      #   ##         \n   #        ##      #\n         #   ###   ##\n#   ##         ##   #\n##   ###   #         \n#      ##        #   \n         ##   #      \n   ##       #        \n           #   #   ##\n        #       #    \n##   ###     #       \n       #         #   \n       #    #    #   \n       #   ##    #   '  
].forEach(x=>out(x.replace(/ /g,'.')+'\n'+F(x)+'\n'))
<pre id=O></pre>

CJam, 18 17 13 11 bytes

2 bytes saved by Dennis.

Uses spaces for filled cells and 1 for empty cells:

qN/_z+:~1-,

Test it here.

Explanation

q    e# Read the entire input.
N/   e# Split into lines.
_z   e# Make a copy and transpose it.
+    e# Add the lines of the two grids together.
:~   e# Evaluate each line which will push a rep-digit number for each empty-cell chunk.
1-   e# Remove all the 1s as these correspond to individual empty cells.
,    e# Get the length of the array.

Pyth, 15 14 13 bytes

lftTcjd+.zC.z

I'm using as seperator and # as fill characters instead of their opposite meaning from the OP. Try it online: Demonstration

Instead of # as fill character this accepts also letters. So you could actually take the solved crossword puzzle, and it would print the number of words. And if you remove the l command, it even prints all words. Test it here: May 10's Sunday NY Times puzzle

Explanation

        .z      all input rows
          C.z   all input columns (C transposes)
       +        add them (all rows and columns)
     jd         join by spaces
    c           split by spaces
 f              filter for pieces T, which satisfy:
  tT              len(T) > 1
l               length, implicitly printed

Slip, 18 + 3 = 21 bytes

>? ( +(X|$^)<<){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

>?           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
<<             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 >?( +(X|$^)<<){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>        X >       X<        <
XXX       XXX       XXX       XXX

[sp]    [sp]+$^    <<[sp]    [sp]+   (uh oh match fails)

Haskell, 81 bytes

import Data.List
m x=sum[1|(_:_:_)<-words x]
f x=m x+m(unlines$transpose$lines x)

Uses spaces as block characters and any other (non whitespace) character as an empty cell.

How it works: split input into list of words at spaces. Take a 1 for every word with at lease 2 characters and sum those 1s. Apply the same procedure to the transposition (split at \n) of the input. Add both results.