/// <summary>
 /// Envolvemos el lanzamiento del evento BitmapBeingRecognized, por comodidad.
 /// </summary>
 /// <param name="bitmap">
 /// La imagen que hemos comenzado a reconocer, que sera enviada como
 /// argumentod del evento.
 /// </param>
 protected void BitmapProcessedByDatabaseInvoker(MathTextBitmap bitmap)
 {
     if (BitmapProcessedByDatabase != null)
     {
         BitmapProcessedByDatabase(this, new BitmapProcessedArgs(bitmap));
     }
 }
Esempio n. 2
0
        /// <summary>
        /// Este metodo realiza la descomposicion de la imagen descomponiendola por
        /// los bordes de los huecos presentes en la proyeccion.
        /// Distintas implementaciones difieren en si se eliminan alguno de estos huecos
        /// de forma que se agrupan ciertas subimagenes para ser tratadas como una sola.
        /// </summary>
        /// <param name="image">La imagen que deseamos descomponer.</param>
        /// <returns>
        /// Un array con las distintas partes en que hemos descompuesto
        /// la imagen de entrada.
        /// </returns>
        public override List <MathTextBitmap> Segment(MathTextBitmap image)
        {
            //Creamos la proyeccion
            BitmapProjection proj  = BitmapProjection.CreateProjection(mode, image);
            List <Hole>      holes = proj.Holes;

            //Aqui decidimos a partir de que tamao de hueco vamos a cortar la imagen

            int threshold = GetImageCutThreshold(holes);

            //Eliminamos los huecos que tengan menor tamaño que el umbral
            int i = 1;

            while (i < holes.Count - 1)
            {
                if (((Hole)holes[i]).Size < threshold)
                {
                    holes.Remove(holes[i]);
                }
                else
                {
                    i++;
                }
            }

            return(ImageCut(image, holes));
        }
        /// <summary>
        /// Metodo que se encarga de dibujar un recuadro sobre la imagen original
        /// para señalar la zona que estamos tratando.
        /// </summary>
        /// <param name="mtb">La subimagen que estamos tratando.</param>
        private void MarkImage(MathTextBitmap mtb)
        {
            Pixbuf originalMarked = imageOriginal.Copy();

            // We tint the copy in red.
            originalMarked =
                originalMarked.CompositeColorSimple(originalMarked.Width,
                                                    originalMarked.Height,
                                                    InterpType.Bilinear,
                                                    100, 1,
                                                    0xAAAAAA, 0xAAAAAA);

            // Over the red tinted copy, we place the piece we want to be
            // normal.
            imageOriginal.CopyArea(mtb.Position.X,
                                   mtb.Position.Y,
                                   mtb.Width,
                                   mtb.Height,
                                   originalMarked,
                                   mtb.Position.X,
                                   mtb.Position.Y);


            imageAreaOriginal.Image = originalMarked;
        }
        /// <summary>
        /// Establece la imagen inicial para segmentar y reconocer sus
        /// caracteres.
        /// </summary>
        /// <param name="image">
        /// La imagen inicial.
        /// </param>
        private void SetInitialImage(string filename)
        {
            imageOriginal           = new Pixbuf(filename);
            imageAreaOriginal.Image = imageOriginal;
            store.Clear();

            // Generamos el MaxtTextBitmap inical, y lo añadimos como
            // un nodo al arbol.
            MathTextBitmap mtb  = new MathTextBitmap(imageOriginal);
            SegmentedNode  node =
                new SegmentedNode(System.IO.Path.GetFileNameWithoutExtension(filename),
                                  mtb,
                                  treeview);

            store.AddNode(node);

            rootNode = node;

            controller.StartNode = node;

            Log("¡Archivo de imagen «{0}» cargado correctamente!", filename);

            alignNextButtons.Sensitive = true;
            segmentBtn.Sensitive       = true;
            gotoTokenizerBtn.Sensitive = false;
            buttonsNB.Page             = 0;
        }
        /// <summary>
        /// Sets the database the symbols will be learned into, and makes the
        /// proper interface elementents (un)sensitive.
        /// </summary>
        /// <param name="database">
        /// A <see cref="MathTextDatabase"/>
        /// </param>
        private void SetDatabase(MathTextDatabase database)
        {
            this.database = database;

            database.StepDone +=
                new ProcessingStepDoneHandler(OnLearningStepDone);

            messageInfoHB.Visible = false;

            mtb = null;


            toolSaveAs.Sensitive = true;
            menuSaveAs.Sensitive = true;

            imagesHB.Sensitive = true;
            imagesVB.Sensitive = true;

            imagesStore.Clear();

            hboxSymbolWidgets.Sensitive = false;
            nextButtonsHB.Sensitive     = false;

            editPropertiesBtn.Sensitive = true;

            symbolLabelEditor.Label = "";

            SetDatabaseInfo();
        }
        private void OnImagesIVSelectionChanged(object s, EventArgs a)
        {
            removeImageBtn.Sensitive = imagesIV.SelectedItems.Length > 0;

            TreeIter selectedIter;

            if (imagesIV.SelectedItems.Length > 0)
            {
                TreePath selectedImagePath = imagesIV.SelectedItems[0];

                imagesStore.GetIter(out selectedIter, selectedImagePath);

                Gdk.Pixbuf orig = (Gdk.Pixbuf)(imagesStore.GetValue(selectedIter, 1));

                mtb = new MathTextBitmap(orig);
                mtb.ProcessImage(database.Processes);

                imageAreaOriginal.Image  = orig;
                imageAreaProcessed.Image = mtb.LastProcessedImage.CreatePixbuf();
            }
            else
            {
                imageAreaOriginal.Image  = null;
                imageAreaProcessed.Image = null;
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Con este metodos almacenamos un nuevo simbolo en la base de
        /// datos.
        ///
        /// Lanza <c>DuplicateSymbolException</c> si ya existe un simbolo
        /// con la misma etiqueta y caracteristicas binarias en la base de datos.
        /// </summary>
        /// <param name="bitmap">
        /// La imagen cuyas caracteristicas aprenderemos.
        /// </param>
        /// <param name="symbol">
        /// El simbolo que representa a la imagen.
        /// </param>
        public override bool Learn(MathTextBitmap bitmap, MathSymbol symbol)
        {
            if (characteristics == null)
            {
                characteristics = CharacteristicFactory.CreateCharacteristicList();
            }

            FloatBitmap processedBitmap = bitmap.LastProcessedImage;
            CheckVector vector          = CreateVector(processedBitmap);


            int position = symbolsDict.IndexOf(vector);

            if (position >= 0)
            {
                // The vector exists in the list

                List <MathSymbol> symbols = symbolsDict[position].Symbols;
                if (symbols.Contains(symbol))
                {
                    return(false);
                }
                else
                {
                    symbols.Add(symbol);
                }
            }
            else
            {
                vector.Symbols.Add(symbol);
                symbolsDict.Add(vector);
            }

            return(true);
        }
Esempio n. 8
0
        public void LearningTest()
        {
            MathTextBitmap bitmap =
                new MathTextBitmap(new FloatBitmap(5, 5), new Gdk.Point(0, 0));

            bitmap.ProcessImage(new List <BitmapProcesses.BitmapProcess>());

            CharacteristicTreeDatabase database =
                new CharacteristicTreeDatabase();

            MathSymbol aSymbol = new MathSymbol("a");
            MathSymbol bSymbol = new MathSymbol("b");

            database.Learn(bitmap, aSymbol);

            List <MathSymbol> symbols = database.Match(bitmap);

            bool a1Learned = symbols.Count == 1 &&
                             symbols[0] == aSymbol;

            bool a2Learned = true;

            a2Learned = database.Learn(bitmap, aSymbol);


            database.Learn(bitmap, bSymbol);
            symbols = database.Match(bitmap);

            bool b1Learned = symbols.Count == 2;

            Assert.IsTrue(a1Learned, "Fallo el aprender la primera a");
            Assert.IsFalse(a2Learned, "No se detecto el conflicto de la segunda a");
            Assert.IsTrue(b1Learned, "Fallo el aprender la b");
        }
Esempio n. 9
0
        /// <summary>
        /// Metodo que obtiene las subimagenes a partir de los huecos.
        /// </summary>
        /// <param name="image">La imagen a segmentar.</param>
        /// <param name="holes">
        /// Los huecos considerados para separar las partes de la imagen.
        /// </param>
        /// <returns>Un array con las subimagenes obtenidas al segmentar.</returns>
        private List <MathTextBitmap> ImageCut(MathTextBitmap image,
                                               List <Hole> holes)
        {
            List <MathTextBitmap> newBitmaps = new List <MathTextBitmap>();

            int start, size;
            int xpos = image.Position.X;
            int ypos = image.Position.Y;

            for (int i = 0; i < holes.Count - 1; i++)
            {
                //El texto esta entre el final de un hueco, y el inicio del siguiente;
                start = ((Hole)holes[i]).EndPixel;
                size  = ((Hole)holes[i + 1]).StartPixel - start + 1;

                int x0, y0;
                int width0, height0;
                if (mode == ProjectionMode.Horizontal)
                {
                    x0      = start;
                    y0      = 0;
                    width0  = size;
                    height0 = image.Height;
                }
                else
                {
                    x0      = 0;
                    y0      = start;
                    width0  = image.Width;
                    height0 = size;
                }

                // Recortamos
                FloatBitmap cutImage =
                    image.FloatImage.SubImage(x0, y0, width0, height0);

                // Encuadramos
                Gdk.Point pd;
                Gdk.Size  sd;
                GetEdges(cutImage, out pd, out sd);
                cutImage = cutImage.SubImage(pd.X, pd.Y, sd.Width, sd.Height);
                // Montamos el bitmap
                MathTextBitmap newBitmap =
                    new MathTextBitmap(cutImage,
                                       new Point(xpos + x0 + pd.X,
                                                 ypos + y0 + pd.Y));

                newBitmaps.Add(newBitmap);
            }

            if (newBitmaps.Count == 1)
            {
                newBitmaps.Clear();
            }


            return(newBitmaps);
        }
Esempio n. 10
0
        /// <summary>
        /// <c>SegmentedNode</c>'s constructor
        /// </summary>
        /// <param name="bitmap">
        /// A <see cref="MathTextBitmap"/>
        /// </param>
        /// <param name="view">
        /// The parent node's <c>NodeView</c>.
        /// </param>
        public SegmentedNode(MathTextBitmap bitmap, NodeView view)
        {
            this.view = view;

            this.bitmap = bitmap;

            this.position = String.Format("({0}, {1})",
                                          bitmap.Position.X, bitmap.Position.Y);
        }
Esempio n. 11
0
        /// <summary>
        /// Este metodo intenta recuperar los simbolos de la base de datos
        /// correspondiente a una imagen.
        /// </summary>
        /// <param name="image">
        /// La imagen cuyos simbolos asociados queremos encontrar.
        /// </param>
        /// <returns>
        /// Los simbolos que se puedieron asociar con la imagen.
        /// </returns>
        public override List <MathSymbol> Match(MathTextBitmap image)
        {
            if (characteristics == null)
            {
                characteristics = CharacteristicFactory.CreateCharacteristicList();
            }

            List <MathSymbol> res = new List <MathSymbol>();

            FloatBitmap processedImage = image.LastProcessedImage;

            CheckVector vector = CreateVector(processedImage);

            // We have this image vector, now we will compare with the stored ones.

            // We consider a threshold.
            int threshold = (int)(characteristics.Count * epsilon);

            foreach (CheckVector storedVector in symbolsDict)
            {
                // If the distance is below the threshold, we consider it valid.
                if (vector.Distance(storedVector) <= threshold)
                {
                    foreach (MathSymbol symbol in storedVector.Symbols)
                    {
                        // We don't want duplicated symbols.
                        if (!res.Contains(symbol))
                        {
                            res.Add(symbol);
                        }
                    }

                    string msg =
                        String.Format("Distancia({0}, {1}) <= {2}",
                                      vector.ToString(),
                                      storedVector.ToString(),
                                      threshold);

                    msg += "\nSe añadieron los símbolos almacenados.";

                    StepDoneInvoker(new StepDoneArgs(msg));
                }
                else
                {
                    string msg = String.Format("Distancia({0}, {1}) > {2}",
                                               vector.ToString(),
                                               storedVector.ToString(),
                                               threshold);

                    StepDoneInvoker(new StepDoneArgs(msg));
                }
            }

            return(res);
        }
        public override bool Apply(FloatBitmap image)
        {
            MathTextBitmap bitmap = new MathTextBitmap(image, new Gdk.Point(0, 0));

            foreach (BitmapSegmenter segmenter in segmenters)
            {
                if (segmenter.Segment(bitmap).Count > 1)
                {
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 13
0
 /// <summary>
 /// Creates the projection.
 /// </summary>
 /// <param name="image">
 /// The <see cref="MathTextBitmap"/> to be projected.
 /// </param>
 protected override void CreateProjection(MathTextBitmap image)
 {
     Values = new int [image.Height];
     for (int i = 0; i < image.Height; i++)
     {
         for (int j = 0; j < image.Width; j++)
         {
             if (image[j, i] != FloatBitmap.White)
             {
                 Values[i]++;
             }
         }
     }
 }
        /// <summary>
        /// This method is used to add new symbols to the database.
        /// </summary>
        /// <param name="bitmap">
        /// The image containing the symbol.
        /// </param>
        /// <param name="symbol">
        /// The symbol contained in the image.
        /// </param>
        public override bool Learn(MathTextBitmap bitmap, MathSymbol symbol)
        {
            FloatBitmap         processedBitmap = bitmap.LastProcessedImage;
            TristateCheckVector newVector       = CreateVector(processedBitmap);

            TristateCheckVector found = null;

            foreach (TristateCheckVector vector in symbolsDict)
            {
                if (vector.Symbols.Contains(symbol))
                {
                    found = vector;
                    break;
                }
            }

            if (found == null)
            {
                // The symbol wasnt present in the database.
                newVector.Symbols.Add(symbol);
                symbolsDict.Add(newVector);
            }
            else
            {
                // The symbol is present, we may have to retrain the database.
                if (newVector.Equals(found))
                {
                    // It's the same one, so there is a conflict.
                    return(false);
                }
                else
                {
                    // We have to find the differnces, and change them to
                    // don't care values.
                    for (int i = 0; i < found.Length; i++)
                    {
                        if (found[i] != TristateValue.DontCare &&
                            found[i] != newVector[i])
                        {
                            // If the value is different from what we had learned,
                            // then we make the vector more general in that point.
                            found[i] = TristateValue.DontCare;
                        }
                    }
                }
            }

            return(true);
        }
Esempio n. 15
0
        /// <summary>
        /// El constructor de <code>FormulaNode</code>
        /// </summary>
        /// <param name="name">
        /// El texto que aparecera en el nodo.
        /// </param>
        /// <param name="bitmap">
        /// El objeto <code>MathTextBitmap</code> asociado al nodo.
        /// </param>
        /// <param name="view">
        /// El árbol al que añadimos el nodo.
        /// </param>
        public SegmentedNode(string name, MathTextBitmap bitmap, NodeView view)
            : base()
        {
            this.name   = name;
            this.label  = "";
            this.bitmap = bitmap;

            position = String.Format("({0}, {1})",
                                     bitmap.Position.X,
                                     bitmap.Position.Y);

            this.view = view;

            this.symbols = new List <MathSymbol>();
        }
        private void OnUnassistedProcessBtnClicked(object sender, EventArgs args)
        {
            // We try to free memory.
            GC.Collect();
            segmentationStore.Clear();


            MainRecognizerWindow.ProcessItemsSensitive = true;
            unassistedControlHBB.Sensitive             = false;
            unassistedTaskNameLabel.Text = "Segmentación y OCR";

            unassistedGlobalProgressBar.Fraction = 0;

            // We create the image to be recognized.

            Bitmap bitmap = handwritingArea.Bitmap;

            FloatBitmap floatBitmap =
                new FloatBitmap(bitmap.Width, bitmap.Height);

            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    floatBitmap[i, j] = bitmap.GetPixel(i, j).GetBrightness();
                }
            }

            // The original image is set.
            originalImage = floatBitmap.CreatePixbuf();

            MathTextBitmap mtb = new MathTextBitmap(originalImage);

            SegmentedNode node = new SegmentedNode("Raíz",
                                                   mtb,
                                                   null);

            segmentationStore.AddNode(node);

            ocrController.StartNode      = node;
            ocrController.SearchDatabase = false;
            ocrController.Databases      =
                Config.RecognizerConfig.Instance.Databases;
            ocrController.Next(ControllerStepMode.UntilEnd);
        }
Esempio n. 17
0
        /// <summary>
        /// Con este metodos almacenamos un nuevo simbolo en la base de
        /// datos.
        ///
        /// Lanza <c>DuplicateSymbolException</c> si ya existe un simbolo
        /// con la misma etiqueta y caracteristicas binarias en la base de datos.
        /// </summary>
        /// <param name="bitmap">
        /// La imagen cuyas caracteristicas aprenderemos.
        /// </param>
        /// <param name="symbol">
        /// El simbolo que representa a la imagen.
        ///</param>
        public override bool Learn(MathTextBitmap bitmap, MathSymbol symbol)
        {
            if (characteristics == null)
            {
                characteristics = CharacteristicFactory.CreateCharacteristicList();
            }

            CharacteristicNode node = rootNode;
            bool characteristicValue;

            FloatBitmap processedBitmap = bitmap.LastProcessedImage;

            // Recorremos las caracteristicas, y vamos creando el arbol segun
            // vamos necesitando nodos.
            foreach (BinaryCharacteristic bc in characteristics)
            {
                if (characteristicValue = bc.Apply(processedBitmap))
                {
                    if (node.TrueTree == null)
                    {
                        node.TrueTree = new CharacteristicNode();
                    }

                    node = node.TrueTree;
                }
                else
                {
                    if (node.FalseTree == null)
                    {
                        node.FalseTree = new CharacteristicNode();
                    }
                    node = node.FalseTree;
                }

                StepDoneArgs a =
                    CreateStepDoneArgs(bc, characteristicValue, null);

                this.StepDoneInvoker(a);
            }

            return(node.AddSymbol(symbol));
        }
        /// <summary>
        /// Creates BitmapProjection instances.
        /// </summary>
        /// <param name="mode">
        /// The <see cref="ProjectionMode"/> used for the projection.
        /// </param>
        /// <param name="mtb">
        /// The <see cref="MathTextBitmap"/> to be projected.
        /// </param>
        /// <returns>
        /// The <see cref="BitmapProjection"/> created.
        /// </returns>
        public static BitmapProjection CreateProjection(ProjectionMode mode,
                                                        MathTextBitmap mtb)
        {
            BitmapProjection res = null;

            switch (mode)
            {
            case (ProjectionMode.Horizontal):
                res = new HorizontalBitmapProjection(mtb);
                break;

            case (ProjectionMode.Vertical):
                res = new VerticalBitmapProjection(mtb);
                break;

            default:
                throw new ArgumentException(
                          "No puede usar None para crear una nueva projección");
            }
            return(res);
        }
Esempio n. 19
0
        /// <summary>
        /// Segmenta una imagen.
        /// </summary>
        /// <param name="image">
        /// La imagen a segmentar.
        /// </param>
        /// <returns>
        /// Una lista con las imagenes que se han obtenido.
        /// </returns>
        private List <MathTextBitmap> CreateChildren(MathTextBitmap image)
        {
            List <MathTextBitmap> children = new List <MathTextBitmap>();

            bool segmented = false;

            for (int i = 0; i < segmenters.Count && !segmented; i++)
            {
                // Intentamos segmentar.
                children = segmenters[i].Segment(image);

                if (children.Count > 1)
                {
                    segmented = true;
                }
                else if (children.Count == 1)
                {
                    throw new Exception("MathTextBitmap incorrectly segmented");
                }
            }

            return(children);
        }
        /// <summary>
        /// Muestra el mensaje que indica como termino el proceso de aprendizaje,
        /// e inicicializa contadores y otras variables relacionadas
        /// con el proceso de aprendizaje actual.
        /// </summary>
        private void AllImagesLearned()
        {
            string conflictsMessage = "";

            // Generamos la cadena que informa de los conflictos
            switch (conflicts)
            {
            case 0:
                break;

            case 1:
                conflictsMessage = "Hubo un conflicto entre caracteres.";
                break;

            default:
                conflictsMessage =
                    String.Format("Hubo {0} conflictos entre caracteres.",
                                  conflicts);
                break;
            }

            // Informamos al usuario.
            OkDialog.Show(mainWindow,
                          MessageType.Info,
                          "Todos los caracteres fueron procesados.\n{0}",
                          conflictsMessage);

            mtb = null;

            // Reinciamos el contador de conflictos.
            conflicts = 0;

            nextImageBtn.Sensitive = false;

            imagesVB.Sensitive = true;
        }
        /// <summary>
        /// Sets the image to be processed.
        /// </summary>
        /// <param name="image">
        /// The initial image's path.
        /// </param>
        private void SetInitialImage(string filename)
        {
            segmentationStore.Clear();

            Gdk.Pixbuf imageOriginal = new Gdk.Pixbuf(filename);
            originalImageArea.Image = imageOriginal;


            // Generamos el MaxtTextBitmap inicial, y lo añadimos como
            // un nodo al arbol.
            MathTextBitmap mtb  = new MathTextBitmap(imageOriginal);
            SegmentedNode  node =
                new SegmentedNode(System.IO.Path.GetFileNameWithoutExtension(filename),
                                  mtb,
                                  null);

            segmentationStore.AddNode(node);

            ocrController.StartNode = node;

            Log("¡Archivo de imagen «{0}» cargado correctamente!", filename);

            unassistedProcessBtn.Sensitive = true;
        }
Esempio n. 22
0
        /// <summary>
        /// Obtiene el menor rectangulo que contiene los pixeles negros de
        /// la imagen y devuelve sus esquinas superior izquierda e
        /// inferior derecha como (x1,y1) y (x2,y2) respectivamente.
        /// </summary>
        /// <param name="image">Imagen sobre la que se trabaja</param>
        /// <param name="x1">Minima coordenada horizontal</param>
        /// <param name="y1">Minima coordenada vertical</param>
        /// <param name="x2">Maxima coordenada horizontal</param>
        /// <param name="y2">Maxima coordenada vertical</param>
        public static void BoxImage(MathTextBitmap image, out int x1, out int y1, out int x2, out int y2)
        {
            FloatBitmap im = image.LastProcessedImage;

            BoxImage(im, out x1, out y1, out x2, out y2);
        }
Esempio n. 23
0
 /// <summary>
 /// Constructor de la clase.
 /// </summary>
 /// <param name="bitmap">La imagen que se ha comenzado a reconocer.</param>
 public BitmapProcessedArgs(MathTextBitmap bitmap)
     : base()
 {
     b = bitmap;
 }
Esempio n. 24
0
 internal VerticalBitmapProjection(MathTextBitmap image)
     : base(image)
 {
 }
 /// <summary>
 /// Creates the projection.
 /// </summary>
 /// <param name="image">
 /// The <see cref="MathTextBitmap"/> being projected.
 /// </param>
 protected abstract void CreateProjection(MathTextBitmap image);
 /// <summary>
 /// <see cref="BitmapProjection"/>'s constructor
 /// </summary>
 /// <param name="image">
 /// The <see cref="MathTextBitmap"/> to be projected.
 /// </param>
 protected BitmapProjection(MathTextBitmap image)
 {
     CreateProjection(image);
 }
Esempio n. 27
0
 /// <summary>
 /// Con este metodos almacenamos un nuevo simbolo en la base de
 /// datos.
 /// </summary>
 /// <param name="bitmap">
 /// La imagen que aprenderemos.
 /// </param>
 /// <param name="symbol">
 /// El simbolo que representa a la imagen.
 /// </param>
 /// <returns>
 /// If the symbol was learned or there was a conflict.
 /// </returns>
 public abstract bool Learn(MathTextBitmap bitmap, MathSymbol symbol);
Esempio n. 28
0
 /// <summary>
 /// Busca una imagen en la base de datos.
 /// </summary>
 /// <param name="image">
 /// La imagen que se procesará y buscará en la base de datos.
 /// </param>
 /// <returns>
 /// Una lista con todos los simbolos que coincidan con los parametros
 /// asociados a la imagen.
 /// </returns>
 public abstract List <MathSymbol> Match(MathTextBitmap image);
Esempio n. 29
0
        /// <summary>
        /// Con este metodo cramos un arbol de imagenes, de forma recursiva.
        /// Primero intentamos reconocer la imagen como un caracter, si no es
        /// posible, la intentamos segmentar. Si ninguno de estos procesos es
        /// posible, la imagen nopudo ser reconocida.
        /// </summary>
        /// <param name="node">
        /// El nodo donde esta la imagen sobre la que trabajaremos.
        /// </param>
        private void RecognizerTreeBuild(SegmentedNode node)
        {
            // Seleccionamos el nodo.

            NodeBeingProcessedInvoker(node);
            SuspendByNode();

            node.Select();

            while (node.ChildCount > 0)
            {
                node.RemoveChild((SegmentedNode)node[0]);
            }

            MathTextBitmap bitmap = node.MathTextBitmap;

            MessageLogSentInvoker("=======================================");
            MessageLogSentInvoker("Tratando la subimagen «{0}»",
                                  node.Name);

            // Lanzamos el reconocedor de caracteres para cada una de
            // las bases de datos.
            List <MathSymbol> associatedSymbols = new List <MathSymbol>();

            if (searchDatabase)
            {
                foreach (MathTextDatabase database in databases)
                {
                    MessageLogSentInvoker("---------- «{0}» ------------",
                                          database.ShortDescription);


                    bitmap.ProcessImage(database.Processes);
                    BitmapProcessedByDatabaseInvoker(bitmap);

                    // Añadimos los caracteres reconocidos por la base de datos
                    foreach (MathSymbol symbol in database.Recognize(bitmap))
                    {
                        if (!associatedSymbols.Contains(symbol))
                        {
                            // Solo añadimos si no esta ya el simbolo.
                            associatedSymbols.Add(symbol);
                        }
                    }
                }
            }


            // We associate all symbols to the node, so we can postargate
            // the decission step.
            node.Symbols = associatedSymbols;

            //Si no hemos reconocido nada, pues intentaremos segmentar el caracter.
            if (associatedSymbols.Count == 0)
            {
                if (searchDatabase)
                {
                    MessageLogSentInvoker("La imagen no pudo ser reconocida como un "
                                          + "simbolo por la base de datos, se tratará de "
                                          + "segmentar");
                }
                else
                {
                    MessageLogSentInvoker("Se procede directamente a segmentar la imagen");
                    this.SearchDatabase = true;
                }

                List <MathTextBitmap> children = CreateChildren(bitmap);

                if (children.Count > 1)
                {
                    MessageLogSentInvoker("La imagen se ha segmentado correctamente");

                    //Si solo conseguimos un hijo, es la propia imagen, asi que nada

                    List <SegmentedNode> nodes = new List <SegmentedNode>();

                    foreach (MathTextBitmap child in children)
                    {
                        SegmentedNode childNode = new SegmentedNode(child, node.View);
                        node.AddSegmentedChild(childNode);
                        nodes.Add(childNode);
                    }

                    foreach (SegmentedNode childNode in nodes)
                    {
                        RecognizerTreeBuild(childNode);
                    }
                }
                else
                {
                    MessageLogSentInvoker("La imagen no pudo ser segmentada, el "
                                          + "símbolo queda sin reconocer");
                }
            }
            else
            {
                // We prepare the string.
                string text = "";
                foreach (MathSymbol s in associatedSymbols)
                {
                    text += String.Format("«{0}», ", s.Text);
                }

                text = text.TrimEnd(',', ' ');
                MessageLogSentInvoker("Símbolo reconocido por la base de datos como {0}.",
                                      text);
            }
        }
 /// <summary>
 /// El metodo que sera invocado para intentar descomponer
 /// una imagen.
 /// </summary>
 /// <param name="mtb">La imagen que queremos descomponer.</param>
 /// <returns>
 /// Un array con las distintas partes en que se
 /// ha descompuesto la imagen.
 /// </returns>
 public abstract List <MathTextBitmap> Segment(MathTextBitmap mtb);