1 Top-down approach
Your problem looks like you'd
- want to segment horizontally,
- shrink your segments from the left and right image border,
- check the number of text columns in each horizontal segment, and then
- within these segments simply look for the columns.
1.1 – segment horizontally
Laziest approach I could come up with: simply find completely white consecutive runs of lines.
To avoid detecting the whitespace between normal lines of text, have a "safe" boundary for large inter-paragraph space. Below that, check whether the non-white lines below and above roughly have the same length.
1.2 – shrink horizontally
Simply find the outmost left and right columns that contain no black. Crop these and everything beyond them out.
1.3 & 1.4 – check number of columns & vertically segment
I'd go for: find columns in the segment of pure white, approach "safety margins" just like for the horizontal segmentation. If you're left with a 1-3px wide vertical segment, check whether it roughly looks like a vertical line.
Another approach would be to directly search for vertical black lines (i.e. go through columns, count black pixels. If column more than let's say 40% black –> vertical line), or if you have to derotate the images first, anyway, start your whole process prior to 1 with a Hough transform and look for roughly vertical lines close to the center of the image – these would show up as peaks in the Houghes-typical position/angle plane.
2 Bottom-up approach based on content
Another thing I'd try is to logically:
- Detect letters' and vertical lines' outlines
- Detect the text lines' outlines (by grouping letter outlines and using vertical lines as boundaries)
- Detect the paragraphs' outlines (by grouping lines)
2.1 – detect letters
Pretty much: find black pixel, find all directly connected black pixels, find the min and max x and y of these groups, draw red rectangle enclosing them. Repeat for next black pixel. (with "draw red" I pretty much mean "mark this as already processed")
2.1a – detect vertical lines
The same as 2.1, but simply filter the detected rectangles by aspect ratio. Mark as green, or however.
2.2 – detect lines' outlines
Starting from the left, take a symbol outline, find center, move right till you either
- hit a vertical (green) line or
- exceed the maximum sensible word distance or
- hit the image border or
- hit the next symbol.
In cases 1.–3., mark all found symbols as content of one line. In case 4., add found symbol to line "stack", and repeat.
2.3 Find paragraph outlines
From top left, take a line outline. Go down.
If the next outline you hit has roughly the same start and width, add to lines stack. If not, or you hit a boundary, declare all lines on stack a paragraph, mark processed, take next unprocessed line outline from top, and repeat.
3 Bottom-up approach, whitespace-based
Idea: on black and white input
- Pick a white pixel
- Find largest undisturbed white (or red) rectangle enclosing said pixel. If area smaller than threshold, mark green. If larger than threshold, mark red
- Go back to 1.
The result should pretty much be a red mask, that, when inverted, gives you the segmentation you need.