# How do I reconstruct text from an image using only morphological operations?

I want to reconstruct the text from the following image as best as possible. The tricky part is that I want to do it only using morphorogical operations on the image

I tried using erosion, dilation, opening and closing but the result is not very good.

Is this even possible?

## migrated from stackoverflow.comDec 12 '11 at 23:34

This question came from our site for professional and enthusiast programmers.

• Dilation looks like the obvious first step to smooth out those fuzzy edges ? – Paul R Dec 12 '11 at 22:23
• Yes, I think this is the first step of every combination I tried. – Jackobsen Dec 12 '11 at 22:25
• I think you need to define your problem more. For example if you mean how can you make it more readable, then a little dilation is probably sufficient. If you want to reconstruct exactly how it looked before whatever distortion process, then that is not possible, because your morphological algorithm has no knowledge of the shapes of the particular font used. – so12311 Dec 13 '11 at 0:51
• To make it more readable I made an imdilate with [0 1 0; 1 1 1; 0 1 0]. I am looking for something that will make the text look very close with the original one. – Jackobsen Dec 13 '11 at 10:58

If you're willing to add/subtract etc. morphologically transformed images, you can count how many signal pixels are in the vicinity of each pixel, and threshold based on that number.

n = false(3);n(4) = 1;
s = false(3);s(6) = 1;
w = false(3);w(2) = 1;
e = false(3);e(8) = 1;

%# note that you could convolve with a cross instead
fourNeighbourCount = imerode(img,n) + imerode(img,s) + imerode(img,w) + imerode(img,3) + img;

%# require at least two neighbours
img = fourNeighbourCount > 1;

If you then convolve with a 3x3 mask that has a hole in the middle, you can get something like this:

This is quite an interesting problem to solve! Try a median filter. See the reference here and here for more details.

Though I haven't put my hands to simulate your problem, this is a suggestion. My gut feeling says that it might give you great benefit because, it is known to counter salt-n-pepper type of noise. In your case, the images has extra white dots around the border which will either get converted to full white or full black depending on which side of the alphabet it is. Here is how it looks after median filtering:

If for some reason you're limited to using morphological operations, then you can consider using a "voting scheme" of oriented close operations.

One problem with morphological operations is that they don't really take directionality into account. For the center pixel, a neighborhood like this

1 0 0
1 1 0
0 1 1

is really no different than a neighborhood like this

0 1 0
1 1 0
1 1 0

That can cause problems since dilation and erosion aren't directionally biased when you might like them to be. So one thing you can do is find the most appropriate directionally biased morphological operation using kernels something like these:

1 1 0   1 0 0   1 0 0
0 1 0   1 1 0   1 1 0
0 1 1   0 1 1   0 1 1 . . .

This would be better with 5 x 5 kernels, but I think the idea is clear enough. Basically, the idea of a corner detection kernel is stretch a bit so that it's a line segment detection kernel. You could also use it to find best-fit curves:

0 0 0 1 1
0 0 1 1 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1

Obviously this leads to a huge number of kernels, but if the basic idea works shows promise for you there's a way to optimize the technique so that the best-fit kernel is found in a single pass.

In any case, if you use multiple kernels and some logic, each operation at (x,y) requires more calculations than a traditional morphological step:

1. At each pixel (x,y), apply each of several morphological operators. For each operator, calculate both the result of the morphological operation AND the degree to which the input matches the kernel. ("Degree" = number of pixels that match)
2. Choose the morphological result for the kernel that most closely matches the actual on/off pixel configuration.

The size of the kernel must be matched to the size of the input. Rather than using a larger kernel, you could use a "spread" kernel to reduce the number of operations. The following kernel is just a 3 x 3 kernel with a radius larger than 1.

1 0 0 0 0 0 0
0 0 0 0 0 0 0
1 0 0 1 0 0 0
0 0 0 0 0 0 0
1 0 0 0 0 0 1