4
$\begingroup$

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", 
   "https://i.stack.imgur.com/bXHyv.png", 
   "https://i.stack.imgur.com/6Uxpo.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

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

{{H,1,O},{m,Y},{d,d}}

Question

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

Or

  • 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.

$\endgroup$
  • $\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$ – Alexey Popkov Mar 21 '17 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 '17 at 19:55
  • $\begingroup$ @MarcoB I'm in 11.1 $\endgroup$ – yode Mar 21 '17 at 20:01
7
$\begingroup$

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"]

image

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

image

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]]}]

image

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. :^)

$\endgroup$
  • $\begingroup$ And do you think this is a bug behavior on TextRecognize that cannot correctly recognize single character? $\endgroup$ – yode Mar 27 '17 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$ – Alexey Popkov Mar 27 '17 at 10:06
  • $\begingroup$ I mean that case when we don't give any mask.Just TextRecognize[img, "Character"] $\endgroup$ – yode Mar 27 '17 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$ – Alexey Popkov Mar 27 '17 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 '17 at 10:43
6
$\begingroup$

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}]] & /@ %

screenshot

With this approach

TextRecognize[#, 
   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

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

output

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

More robust approach:

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

output


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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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