Reputation: 5
I am trying to extract text from an image of printed text. Along with the text itself, I am interested in detecting the spaces between the words as well. The spaces between words are not consistent (deliberate) and that is something I want detected.
To achieved this I first had to extract the text lines. I achieved that using the projection profile code attached (code copied from one of the answers by ImageAnalyst).
One way I thought of achieving this was by counting the number of white pixels between the words, if I know the number of pixels taken by a single space (say n), I could just determine the number of spaces by dividing the white pixels between the words by this 'n' to get the number of spaces.
I tried that but it did not go as planned, the results are very conflicting, even when compared against known ground truth values. Determining a baseline of every text line is proving to be difficult, for a single space between two words I am getting different pixel count. This is because as counting the white pixels from letter d to b is different from counting the white pixels from c to s (the white pixels within the curve of c is also sometimes counted.)
Any guidance or suggestions would be greatly appreciated.
Thank you
code I used :
clc;
close all;
clear;
fontSize = 16;
img = imread('Lines.png');
[rows, columns, dim] = size(img);
if dim > 1
grayImage = img(:, :, 2);
end
% Display the original gray scale image.
subplot(3, 3, 1);
imshow(grayImage, []);
title('Original image', 'FontSize', fontSize);
axis on;
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]); % Enlarge figure to full screen.
% Threshold the image.
binaryImage = grayImage < 210;
% Get rid of small areaas of 14 pixels or less
binaryImage = ~bwareaopen(binaryImage, 15);
subplot(2, 3, 2);
imshow(binaryImage);
title('Binary Image', 'FontSize', fontSize);
axis on;
% Vertical Profile
verticalProfile = sum(binaryImage, 2);
subplot(3, 3, [2 3]);
plot(verticalProfile, 'b');
grid on;
title('Vertical Profile', 'FontSize', fontSize);
rowsWithText = verticalProfile < 600;
% Find top and bottom lines
topLines = find(diff(rowsWithText) == 1);
bottomLines = find(diff(rowsWithText) == -1);
for j = 1 : length(topLines)
topRow = topLines(j);
bottomRow = bottomLines(j);
thisLine = binaryImage(topRow:bottomRow, :);
subplot(3, 3, [4 5 6]);
imshow(thisLine, []);
axis on;
caption = sprintf('Line %d of the text', j);
title(caption, 'FontSize', fontSize);
% Horizontal profile
horizontalProfile = sum(thisLine, 1);
subplot(3, 3, [7 8 9]);
plot(horizontalProfile);
grid on;
caption = sprintf('Horizontal Profile of Line %d of the text', j);
title(caption, 'FontSize', fontSize);
promptMessage = sprintf('lines %d', j);
titleBarCaption = 'Continue?';
button = questdlg(promptMessage, titleBarCaption, 'Continue', 'Cancel', 'Continue');
if strcmpi(button, 'Cancel')
return;
end
end
msgbox('Done!');
picture : Image of my program
Upvotes: 1
Views: 167
Reputation: 607
Try playing around with something like this:
% define min length of gap between words; play around with this value
min_gap_length = 5;
% define wordStarts/wordEnds like you've defined topLines/bottomLines
wordStarts = find(diff(horizontalProfile) == -1);
wordEnds = find(diff(horizontalProfile) == 1);
if wordStarts(1) > wordEnds(1)
wordStarts = [1, wordStarts];
end
if wordEnds(end) < wordStarts(end)
wordEnds = [wordEnds, length(horizontalProfile)];
end
% restrict wordStarts/wordEnds to gaps of over min_gap_length
I = wordStarts(2:end) - wordEnds(1:end-1) > min_gap_length;
wordStarts = wordStarts([true, I]);
wordEnds = wordEnds([I, true]);
Upvotes: 1