# Extract table from image

I have the image of a matrix (download it to see it bigger):

Is there a way to convert this into a Mathematica numerical matrix, using Mathematica?

• Do you know the bounds of the values of your matrix? Are they all 0/1/-1/2?
– rm -rf
Commented Jan 13, 2014 at 20:58
• @rm-rf Yes. You can assume that the values are all in the set {-1, 0, 1, 2}.
– a06e
Commented Jan 13, 2014 at 21:00
• ImageCorrelate is probably your friend here.
– rm -rf
Commented Jan 13, 2014 at 21:02
• Various methods are described here here. If you know the dimension of this matrix as well as how the columns are spatially distributed it might help, because a useful first step is probably to partition the image (and then use ImageCorrelate like rm -rf said). Commented Jan 13, 2014 at 21:12
• @anon You can also assume that you know the dimensions of the matrix. In this example, the matrix is 46x34. The columns and rows are clearly delineated in the image.
– a06e
Commented Jan 13, 2014 at 21:19

TextRecognize works fine after some tweaks and error corrections:

x = Import["https://i.sstatic.net/NQr6I.png"];
res = TextRecognize[Binarize[ImageResize[x, Scaled[5]], 0.7],"SegmentationMode" -> 6];

m = ToExpression /@ StringSplit[#] & /@
StringSplit[
StringReplace[
res, {"O" | "D" | "U" -> "0", "~" | "\"" -> "-", "I" -> "1"}],
"\n"];

m // MatrixForm


I have used the undocumented option "SegmentationMode" -> 6.

• SegmentationMode details here Commented Jan 14, 2014 at 0:52
• @Murta My last line is clickable with the same link :) Commented Jan 14, 2014 at 0:56
• +1 for proving that TextRecognize works. It seems the text needs to be large enough for it to work.
– shrx
Commented Jan 14, 2014 at 9:01
• +1. But I've found one error: m[[28,28]] gives -1. It should be 1.
– a06e
Commented Jan 14, 2014 at 14:32

Here is one way:

data = ColorNegate@Import@"https://i.sstatic.net/NQr6I.png";

points=ComponentMeasurements[ MorphologicalComponents[Sharpen[Dilation[Binarize@data,1.5],1]] ,"Centroid"][[All,2]];
box=ComponentMeasurements[ MorphologicalComponents[Sharpen[Dilation[Binarize@data,1.5],1]] ,"BoundingBox"][[All,2]];

{posX,posY}=Mean/@Split[#,If[Abs[#1-#2]<5,True,False]&]&/@{Sort@points[[All,1]],Sort@points[[All,2]]}


We can see that grid position worked in this plot:

ListPlot[points,PlotRange->All,GridLines->{posX,posY},PlotStyle->Red]


Now let's do image partition:

imagePartition = ParallelMap[ImageTrim[Binarize@data, #] &, box];


Here is a sample:

imagePartition[[;; 15]]


Now the part that has to be improved, here is one attempt to recognize the numbers.

getNumber[img_]:=Module[{r,comp},
comp=ComponentMeasurements[img,{"PerimeterCount","Holes"}][[All,2]];
r=Which[
Length@#==2,-1
,#[[1,2]]==1,0
,#[[1,1]]<15,1
,True,2
]&[comp];
(*{r,comp,img}*)
r
]


Two elements finds -1, one hole find 0, no hole with perimeter < 15 finds 1 and the rest is 2.

Applying it data partition as:

numberData=Partition[ParallelMap[getNumber,imagePartition],Length@posX]//MatrixForm


We get:

Grid[numberData,Spacings->0,Alignment-> NumberPoint,Dividers->LightGray,BaseStyle->{FontSize-> 11}]


Not perfect, but can be a start point. It's just improve getNumber.

## Update

With some calibration in getNumber and using Binarize intead of Sharpen, now all cases are ok.

• Related to the last part: coming soon. First application example
– Rojo
Commented Jan 14, 2014 at 2:23
• Yes I know! Tks for show that this documentation is already public :) Commented Jan 14, 2014 at 10:06
• +1 But it has some mistakes. numberData[[6, 5]] and numberData[[6, 6]] both give 0, but should be -1 and 1 respectively.
– a06e
Commented Jan 16, 2014 at 18:04