Bug introduced in 11.0 and persisting through 11.3

From this answer, I doubt the capability to work on single character. So I give some test to verify this possibility. You can get my test imgs by this code

imgs = Binarize[
    Import[#]] & /@ {"https://i.stack.imgur.com/PvuFe.png", 

Note the TextRecognize[#, "Character"] & /@ imgs will get nothing. We can get a example from the documentation in Examples/Applications, that indicate the appropriate mask maybe can improve the performance to get a character, but I don't very like this method. Because it is hard to build a mask for characters "i","j" like

   Masking -> MorphologicalTransform[#, "BoundingBoxes", Infinity], 
   RecognitionPrior -> "Character"] & /@ imgs



  • Any workaround that can improve the recognition quality when TextRecognize work on single character


  • If we want to improve the recognition quality by mask, how to build correct mask?

I desire to make my this answer better by TextRecognize.

  • $\begingroup$ I recommend you putting your test images on imgur.com, that those who use Mathematica version lower than 10 could work with them too. $\endgroup$ Mar 21, 2017 at 19:51
  • $\begingroup$ TextRecognize[#, "Character"] & is not recognized syntax, as indicated by the stream of errors it generates. Furthermore, there is no indication in the documentation of that usage. Why do you suppose that it should work? $\endgroup$
    – MarcoB
    Mar 21, 2017 at 19:55
  • $\begingroup$ @MarcoB I'm in 11.1 $\endgroup$
    – yode
    Mar 21, 2017 at 20:01

2 Answers 2


I felt that I miss some simple way to unite closely located components and finally I found it: ImageForestingComponents (thanks to this answer)!

  • It is unfortunate that a link to this function isn't included in the "See Also" drop-down list neither on the Docs page for ComponentMeasurements, nor MorphologicalComponents, nor MorphologicalTransform. That's why I wasn't able to find it quickly...

I'll show how it can be used on the most problematic case with letter "i" which is formed by two not connected clusters of points:

i = Import["https://i.stack.imgur.com/PvuFe.png"]


With horizontal radius 1 and vertical radius 6 we get a segmentation where our letter "i" is counted as a single component:

ImageForestingComponents[i, Automatic, {1, 6}] // Colorize


Using ComponentMeasurements we can get the bounding boxes of our characters dropping the background:

c = ComponentMeasurements[ImageForestingComponents[i, Automatic, {1, 6}], 
  "BoundingBox", #"ConvexCoverage" < .9 &]
{2 -> {{66., 125.}, {79., 161.}}, 3 -> {{46., 61.}, {84., 98.}}}
HighlightImage[i, {Yellow, Rectangle @@@ c[[All, 2]]}]


TextRecognize accepts a set of Rectangle primitives as a Mask (it is documented under the Examples ► Options ► Masking sub-subsection):

TextRecognize[i, Masking -> Rectangle @@@ c[[All, 2]], RecognitionPrior -> "Character"]
{"i", "O"}

That's all. :^)

  • $\begingroup$ And do you think this is a bug behavior on TextRecognize that cannot correctly recognize single character? $\endgroup$
    – yode
    Mar 27, 2017 at 10:04
  • $\begingroup$ @yode When you give an improper mask to TextRecognize it is expected that it won't be able to recognize the character correctly. $\endgroup$ Mar 27, 2017 at 10:06
  • $\begingroup$ I mean that case when we don't give any mask.Just TextRecognize[img, "Character"] $\endgroup$
    – yode
    Mar 27, 2017 at 10:20
  • $\begingroup$ @yode RecognitionPrior -> "Character" assumes that we have only one character on the image (or on each masked area). And TextRecognize correctly recognizes the character "i" when it is the only char on the image: TextRecognize[ImageTake[i, 80], RecognitionPrior -> "Character"]. $\endgroup$ Mar 27, 2017 at 10:28
  • $\begingroup$ I do not mean use TextRecognize[i, RecognitionPrior -> "Character"](and I know what you have say in here).I just think TextRecognize[i, "Character"] should give a correct result. $\endgroup$
    – yode
    Mar 27, 2017 at 10:43

You can use Dilation with rectangular kernel to extend the bounding boxes vertically in order to connect closely related components:

MorphologicalTransform[#, "BoundingBoxes", Infinity] & /@ imgs
Dilation[#, Table[1, {6}, {1}]] & /@ %


With this approach

   Masking -> Dilation[MorphologicalTransform[#, "BoundingBoxes", Infinity], 
     Table[1, {6}, {1}]], RecognitionPrior -> "Character"] & /@ imgs
{{"i", "O"}, {"m", "Y"}, {"d", "d"}}

Use ImageFilter to connect only closely located bounding boxes:

uniteBoxes[image_, range_: 6] := 
 ImageFilter[If[#[[{1, -1}, 1]] == {1, 1}, 1, #[[Ceiling[Length[#]/2], 1]]] &, 
  image, {range {1, 1}, {0, 0}}]

uniteBoxes@MorphologicalTransform[#, "BoundingBoxes", Infinity] & /@ imgs

   Masking -> uniteBoxes[MorphologicalTransform[#, "BoundingBoxes", Infinity]], 
   RecognitionPrior -> "Character"] & /@ imgs


{{"i", "O"}, {"m", "Y"}, {"d", "d"}}

More robust approach:

fillGaps[list_, length_: 6] := 
   List /@ Flatten[Range @@@ SequencePosition[list, {1, Repeated[0, {1, length}], 1}]] -> 
connectVertically[image_, distance_: 6] := 
 Image[Transpose[fillGaps[#, distance] & /@ Transpose[ImageData[image]]]]
connectVertically@MorphologicalTransform[#, "BoundingBoxes", Infinity] & /@ imgs


P.S. It is possible that approaches shown in the following threads can be used to speed-up searching for closely located components (knowing the coordinates of their bounding boxes):

Also, DistanceMatrix can be of use here.

  • $\begingroup$ The Dilation will enlager all mask, though the character is not i or j $\endgroup$
    – yode
    Mar 22, 2017 at 15:16
  • $\begingroup$ @yode I updated the answer with an approach that affects only closely located components. $\endgroup$ Mar 22, 2017 at 16:06
  • $\begingroup$ Thanks for your update,I need some time to through it... $\endgroup$
    – yode
    Mar 23, 2017 at 5:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.