¿Por qué los arrays VectorOfKeyPoint y Mat están siendo sobrescritos por los nuevos resultados del detector SIFT?

During execution of PictureBox1_Click(object sender, EventArgs e):

using Emgu.CV;
using Emgu.CV.Features2D;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        static VectorOfKeyPoint _templateKeyPoints = new VectorOfKeyPoint();
        static Mat _templateDescriptor = new Mat();
        VectorOfKeyPoint[] templateKeyPoints = new VectorOfKeyPoint[2];
        Mat[] templateDescriptor = new Mat[2];
        Bitmap[] croppedImage = new Bitmap[2];
        public Form1()
        {
            InitializeComponent();
            pictureBox1.Load("https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_960_720.jpg");
            pictureBox2.Load("https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_960_720.jpg");
            croppedImage[0] = (Bitmap)pictureBox1.Image.Clone();
            croppedImage[1] = (Bitmap)pictureBox2.Image.Clone();
        }

        private void PictureBox1_Click(object sender, EventArgs e)
        { 
            for (int i = 0; i < 2; i++)
            {
                try
                {
                    var processTemplate = ProcessTemplate(croppedImage[i].ToImage());
                    templateKeyPoints[i] = processTemplate.tempKeyPoints;
                    templateDescriptor[i] = processTemplate.tempDescriptor;
                }
                catch(Exception exp)
                {
                    MessageBox.Show(exp.Message);
                }
               
            }
        }        

        public static (VectorOfKeyPoint tempKeyPoints, Mat tempDescriptor)
            ProcessTemplate(Image template)
        {
            try
            {
                SIFT detector = new SIFT();
                detector.DetectAndCompute(template, null, _templateKeyPoints, _templateDescriptor, false);

            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }

            return (_templateKeyPoints, _templateDescriptor);
        }
    }
}
  • Durante la primera iteración:

    Cuando templateKeyPoints[0] y templateDescriptor[0] poblada, obtengo los resultados correctos.

  • Durante la segunda iteración:

    Los nuevos resultados de processTemplate.tempKeyPoints y processTemplate.tempDescriptor ser sobrescrito al primero elementos de templateKeyPoints[i] y templateDescriptor[i], respectivamente (no como se desee) y también se poblan a su segundo elemento respectivo (como deseado). ¿Por qué ocurre esta sobreescritura?

Pregunta hecha hace 3 años, 4 meses, 29 días - Por codecraftsman32c9


3 Respuestas:

  • Resolví el problema. Esto fue porque no estaba creando un nuevo VectorOfKeyPoint y 'Mat' instancia cuando llamo ProcessTemplate() método. Así que me mudé VectorOfKeyPoint _templateKeyPoints = new VectorOfKeyPoint(); y Mat _templateDescriptor = new Mat(); al método como sigue:

            public static (VectorOfKeyPoint tempKeyPoints, Mat tempDescriptor)
                ProcessTemplate(Image template)
            {
                VectorOfKeyPoint _templateKeyPoints = new VectorOfKeyPoint();
                Mat _templateDescriptor = new Mat();
                try
                {
                    SIFT detector = new SIFT();
                    detector.DetectAndCompute(template, null, _templateKeyPoints, _templateDescriptor, false);
    
                }
                catch (Exception exp)
                {
                    MessageBox.Show(exp.Message);
                }
    
                return (_templateKeyPoints, _templateDescriptor);
            }
    

    Respondida el Dec 17, 2020 a las 04:05 - por devdynamox

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando se debe a que estás utilizando variables estáticas (templateKeyPoints y _templateDescriptor) en tu método ProcessTemplate para almacenar los puntos clave y descriptores SIFT. Al ser estáticas, estas variables conservan su valor entre las llamadas al método, lo que significa que en cada iteración del bucle en PictureBox1Click estás sobrescribiendo las mismas variables estáticas _templateKeyPoints y _templateDescriptor con los resultados de la detección de SIFT de la imagen actual, causando que los resultados se guarden en la misma ubicación de memoria y se reflejen en todos los índices de templateKeyPoints y templateDescriptor.

    Para resolver este problema, te recomendaría que elimines las variables estáticas templateKeyPoints y _templateDescriptor, y en su lugar, declares y uses variables locales dentro del método ProcessTemplate. De esta manera, cada llamada al método creará nuevas instancias de los resultados de SIFT que no se sobrescribirán entre iteraciones del bucle en el evento PictureBox1Click.

    Aquí te dejo una versión modificada del código para que puedas implementar esta solución:

    csharp
    using Emgu.CV;
    using Emgu.CV.Features2D;
    using Emgu.CV.Structure;
    using Emgu.CV.Util;
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            VectorOfKeyPoint[] templateKeyPoints = new VectorOfKeyPoint[2];
            Mat[] templateDescriptor = new Mat[2];
            Bitmap[] croppedImage = new Bitmap[2];
    
            public Form1()
            {
                InitializeComponent();
                pictureBox1.Load("https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_960_720.jpg");
                pictureBox2.Load("https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_960_720.jpg");
                croppedImage[0] = (Bitmap)pictureBox1.Image.Clone();
                croppedImage[1] = (Bitmap)pictureBox2.Image.Clone();
            }
    
            private void PictureBox1_Click(object sender, EventArgs e)
            {
                for (int i = 0; i < 2; i++)
                {
                    try
                    {
                        var processTemplate = ProcessTemplate(croppedImage[i].ToImage());
                        templateKeyPoints[i] = processTemplate.tempKeyPoints;
                        templateDescriptor[i] = processTemplate.tempDescriptor;
                    }
                    catch (Exception exp)
                    {
                        MessageBox.Show(exp.Message);
                    }
    
                }
            }
    
            public static (VectorOfKeyPoint tempKeyPoints, Mat tempDescriptor) ProcessTemplate(Image template)
            {
                VectorOfKeyPoint tempKeyPoints = new VectorOfKeyPoint();
                Mat tempDescriptor = new Mat();
    
                try
                {
                    SIFT detector = new SIFT();
                    detector.DetectAndCompute(template, null, tempKeyPoints, tempDescriptor, false);
    
                }
                catch (Exception exp)
                {
                    MessageBox.Show(exp.Message);
                }
    
                return (tempKeyPoints, tempDescriptor);
            }
        }
    }
    

    Con esta modificación, cada llamada a ProcessTemplate creará nuevos vector de puntos clave y matriz de descriptores que serán independientes entre sí y no se sobrescribirán entre iteraciones del bucle en el evento PictureBox1_Click.

    Respondida el Dec 18, 2020 a las 04:05 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El problema surge porque estás utilizando variables estáticas (_templateKeyPoints y _templateDescriptor) dentro de la función ProcessTemplate. Esto significa que estas variables se comparten entre todas las instancias de la función, por lo que cuando se llaman por segunda vez, las sobrescribe con los nuevos resultados.

    Para resolver este problema, debes pasar las variables _templateKeyPoints y _templateDescriptor como parámetros a la función ProcessTemplate en lugar de utilizar variables estáticas. De esta forma, cada llamada a la función tendrá su propio conjunto de variables y no se sobrescribirán entre sí.

    Aquí tienes el código modificado:

    csharp
    public static (VectorOfKeyPoint tempKeyPoints, Mat tempDescriptor)
        ProcessTemplate(Image template, VectorOfKeyPoint templateKeyPoints, Mat templateDescriptor)
    {
        try
        {
            SIFT detector = new SIFT();
            detector.DetectAndCompute(template, null, templateKeyPoints, templateDescriptor, false);
    
        }
        catch (Exception exp)
        {
            MessageBox.Show(exp.Message);
        }
    
        return (templateKeyPoints, templateDescriptor);
    }
    

    Y en el método PictureBox1_Click:

    csharp
    private void PictureBox1_Click(object sender, EventArgs e)
    { 
        for (int i = 0; i < 2; i++)
        {
            try
            {
                var processTemplate = ProcessTemplate(croppedImage[i].ToImage(), new VectorOfKeyPoint(), new Mat());
                templateKeyPoints[i] = processTemplate.tempKeyPoints;
                templateDescriptor[i] = processTemplate.tempDescriptor;
            }
            catch(Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
    
        }
    }
    

    Ahora, cada llamada a ProcessTemplate utilizará su propio conjunto de variables templateKeyPoints y templateDescriptor, y no se sobrescribirán entre sí.

    Respondida el Dec 18, 2020 a las 04:07 - por Gemini

    Votos positivos: 0 | Votos negativos: 0