Laden...

Kinect: Mittelwertbildung des nächstgelegen Punktes

Erstellt von sterotony89 vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.192 Views
S
sterotony89 Themenstarter:in
3 Beiträge seit 2014
vor 10 Jahren
Kinect: Mittelwertbildung des nächstgelegen Punktes

Hallo Leute,

ich versuche gerade mittels einer Kinect den nächstgelegenen Punkt zu dieser zu bestimmen. Der Punkt soll sich in aber in einer von mir erstellten Gebiet befinden, da ich die Objektlage eines Objekt bestimmen soll und dieses Objekt in einer Gitterbox liegt(die immer am nächsten an der Kamera ist.
Das hab ich auch soweit hinbekommen, allerdings ist der ausgegebene Punkt relativ ungenau, was mit dem Rauschen der Kamera zusammenhängt.

Deshalb möchte ich diesen Punkt mitteln um eine höhere Genauigkeit zu gewährleisten.

Konzept ist volgendermaßen:

  1. Bestimmung des nächstgelegenen Punktes( Referenzpunkt)
  2. Bestimmung eines weiteren nächstgelegenen Punktes (Vergleichspunkt)
  3. Wenn Punkt nicht zu weit von Refenrenzpunkt abweicht, wird er in ein Array geschrieben(Länge vorgegeben)
  4. Iterative Durchführung bis der Array mit Vergleichspunkten voll ist

Theoretisch hab ich das schon verstanden, aber für die Praxis fehlt es mir leider an Programmiererfahrung

Nun mein Problem:
Das Programm schaut immer dasselbe Tiefenbild an, weshalb logischerweise auch jedes mal der gleiche Vergleichspunkt bestimmt wird.
Wie kann man einstellen, dass die suche eines Vergleichspunktes immer auf ein neueres Bild durchgeführt wird ???
Es geht los bei der Bestimmung der Vergleichspunkte (Do-Schleife)

Ich entschuldige mich direkt für den langen Code. Die Kommentare sollten reichen um mein Vorgehen nachvollziehen zu können.
Vielen Dank für eure Hilfe


        private void button2_Click(object sender, EventArgs e)//Suchen des nächsten Punktes NUR IN KISTE !!!
        {
            depth = depthstream;

            int nächsterpunkt1z = int.MaxValue, max = int.MinValue;
            nächsterpunkt1x = -1;
            nächsterpunkt1y = -1;

            int nächsterpunkt2z = int.MaxValue, maxref = int.MinValue;

            //Position im Array
            int a = -1;

            //Arraya zu den Koordinaten
            int[] koordinateX = new int[50];
            int[] koordinateY = new int[50];
            int[] koordinateZ = new int[50];
            int summeX = 0;
            int summeY = 0;
            int summeZ = 0;


            //der gemittelte Punkt
            float ergebnisX;
            float ergebnisY;
            float ergebnisZ;

            //Referenzpunkt bestimmen
            for (int y = Kiste.Y; y < Kiste.Y + Kiste.Height; y++)
                for (int x = Kiste.X; x < Kiste.X + Kiste.Width; x++) // nur das innere der Kiste wird betrachtet
                {
                    int i = y * 320 * 2 + x * 2; // width durch die weite des Gesamtbildes (320) ersetzt
                    int dist = GetDistance(depth[i], depth[i + 1]);

                    if (dist < nächsterpunkt1z && dist > 0)// vergleicht die Distanz des aktuellen Punktes mit bisherigem Minimum
                    {
                        nächsterpunkt1z = dist;
                        nächsterpunkt1x = x;
                        nächsterpunkt1y = y;
                    }
                    if (dist > max) max = dist; // falls Distanz kleiner, wird Punkt ersetzt 

                    //HIER NÄCHSTER PUNKT GESETZT
                    NEXT.Y = nächsterpunkt1y;
                    NEXT.X = nächsterpunkt1x;
                    richTextBox1.Text = "";
                    richTextBox1.AppendText("Abstand zum nächsten Punkt " + nächsterpunkt1z + " und seine Koordinaten sind: x = " + nächsterpunkt1x + " y = " + nächsterpunkt1y);

                }


            //Vergleichspunkt bestimmen
            do
            {

                for (int yref = Kiste.Y; yref < Kiste.Y + Kiste.Height; yref++)
                {
                    for (int xref = Kiste.X; xref < Kiste.X + Kiste.Width; xref++) // nur das innere der Kiste wird betrachtet*/
                    {
                        int j = yref * 320 * 2 + xref * 2; // width durch die weite des Gesamtbildes (320) ersetzt
                        int distref = GetDistance(depth[j], depth[j + 1]);

                        if (distref < nächsterpunkt2z && distref > 0)// vergleicht die Distanz des aktuellen Punktes mit bisherigem Minimum
                        {
                            nächsterpunkt2z = distref;
                            nächsterpunkt2x = xref;
                            nächsterpunkt2y = yref;
                        }
                        if (distref > maxref)
                        { maxref = distref; } // falls Distanz kleiner, wird Punkt ersetzt  
                    }
                }
                //Beträge der Differenzen
                int vx = Math.Abs(nächsterpunkt1x - nächsterpunkt2x);
                int vy = Math.Abs(nächsterpunkt1y - nächsterpunkt2y);
                int vz = Math.Abs(nächsterpunkt1z - nächsterpunkt2z);

                //Grobe Abweichungen aussortieren um Mittelung zu verbessern
                if (vx * vx + vy * vy < 16 && vz < 4)
                {
                    a++;
                    if (a > -1)
                    {
                        koordinateX[a] = nächsterpunkt2x;
                        koordinateY[a] = nächsterpunkt2y;
                        koordinateZ[a] = nächsterpunkt2z;
                    }
                }

            } while (a < koordinateX.Length-1); //Schleife voll

            //Mittelung des Punktes

            if (a == koordinateX.Length-1)
            {
                for (int p = 0; p < koordinateX.Length; p++)
                {
                    summeX += koordinateX[p];
                    summeY += koordinateY[p];
                    summeZ += koordinateZ[p];
                }

                    ergebnisX = summeX / koordinateX.Length;
                    ergebnisY = summeY / koordinateY.Length;
                    ergebnisZ = summeZ / koordinateZ.Length;

                    richTextBox2.Text = "";
                    richTextBox2.AppendText("gemittelter Abstand zum nächsten Punkt " + ergebnisZ + " und seine Koordinaten sind: x = " + ergebnisX + " y = " + ergebnisY);
                    Array.Clear(koordinateX, 0, koordinateX.Length);


5.657 Beiträge seit 2006
vor 10 Jahren

Hi sterotony89,

ich kann weder deinen Quellcode nachvollziehen, noch deine Beschreibung. Ich kann auch keinen direkten Zusammenhang mit der Kinect erkennen. Letztendlich willst du ein S/W-Bild mit Tiefeninformationen auswerten, und das ist ein grafisches Problem. Daher hat der Beitrag auch nichts im WinForms-Forum zu suchen, sondern gehört in das Grafik-Forum (==> verschoben). Zu deinem Problem:
Was meinst du mit "Das Programm schaut immer dasselbe Tiefenbild an"? Wird das nicht bei jedem Frame aktualisiert? Was ist die "KISTE"? Wie bestimmst du die sogenannten Referenzpunkte und Vergleichspunkte? Und was ist nun dein eigentliches Problem dabei?

Christian

Weeks of programming can save you hours of planning

173 Beiträge seit 2009
vor 10 Jahren

Hi,

folgende Fragen habe ich dazu:

Weißt du immer ganz genau, wo sich im Tiefenbild "Die Kiste" befindet, bzw. welche Koordinaten die Fläche dazwischen beschreiben?

Was ist "depthstream" und wann wird es gesetzt?

Soweit ich mich erinnere kannst du ein Event benutzen, dass von der Kinect ausgelöst wird, immer dann wenn das Tiefenbild aufgenommen wurde.

Also entweder sammelst du nen Zeit lang mehrere Tiefenbilder in einer Liste und wertest dann zum Beispeil aus, sobald du 10 Stück hast, oder du wertest jedes Tiefenbild aus, sobald der Event kommt und speicherst das Ergebnis.


Ist es bei der aktuellen Kinect eigentlich immer noch so das das Tiefenbild eine andere Auflösung als das Farbbild hat?

S
sterotony89 Themenstarter:in
3 Beiträge seit 2014
vor 10 Jahren

Hallo,

vielen Dank erstmal für eure schnellen Antworten.
@MrSparkle: Ich habe nicht den gesamten Code gepostet. Die Kinect wurde vorher initialisiert und das funktioniert auch. Sorry für meine Anfängerfehler, wusste nicht genau was vom Code euch interessiert und was nicht, deshalb habe ich nur die problembezogenen Stellen geposet.

Schließlich soll es darum gehen die Lage eines Objekts zu lokalisieren, welches sich in einer Gitterbox befindet(In meinem Fall die Kiste). Da aber mehrere Objekte in der Kiste liegen, soll immer das nächstgelegene betrachtet werden ----> brauche den zur Kinect nächstgelegenen Punkt, der aber nicht der Kistenrand sein darf. Dabei taste ich jeden Pixel im inneren der Kiste ab und vergleiche die Tiefenwerte. Die Koordinaten des Punktes die zum kleinsten Tiefenwert gehören, sind die meines Bezugspunktes.
Die Abmaße der Kiste lege ich über einen PictureBoxClick fest. (Siehe Bild)

Der gefundene Punkt schwankt aber extrem, weshalb ich für eine genauere Bestimmung diesen Vorgang mehrfach wiederholen will ( das ist die do-while-Schleife bei Vergleichspunkt bestimmen) und schließlich aus den gefundenen Punkten einen Mittelwert bilde.

Mein Problem ist nun: Der gebildete Mittelwert ist identisch zu dem Referenzpunkt. Das kann allerdings nicht sein, da nur ca. 20% der gefundenen Punkte diesem Wert entsprechen (über Tests ermittelt) .
Meine Annahme für das Problem: Das Programm tastet nur ein Bild immer und immer wieder ab, sodass das Rauschen der Kamera gar nicht berücksichtigt wird -----> es kommt immer der gleiche Punkt raus, der nach Mittelwertbildung folglich auch gleich bleibt. Das könnte daran liegen, dass die Kinect 32fr/sek zu langsam für das Programm ist. Aber das ist nur meine Theorie.

@akunz: der depth Stream wird außerhalb der Methoden gesetzt

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Runtime nui;
        public Byte[] depthstream;
        public Byte[] depth;
        Bitmap TIEFENBILD;//für Depthstream in Picture Box

Soweit ich mich erinnere kannst du ein Event benutzen, dass von der Kinect ausgelöst wird, immer dann wenn das Tiefenbild aufgenommen wurde.

Diesen Ansatz finde ich sehr interessant. Kennst du zufällig dieses Event, weil ich schon gesucht habe und es leider nicht finden konnte.

Ist es bei der aktuellen Kinect eigentlich immer noch so das das Tiefenbild eine andere Auflösung als das Farbbild hat?

Komischerweise ja. Farbbild 640 x 480 und Tiefenbild 320 x 240. Aber meine Kinect ist auch schon 3 Jahre alt, könnten sie mit der neuen (XboxOne) geändert haben.

Puuuuh 😄 geschafft

Dankeschön im Vorraus für eure Mühen
Da fühlt man sich direkt kompetent beraten

173 Beiträge seit 2009
vor 10 Jahren
  Diesen Ansatz finde ich sehr interessant. Kennst du zufällig dieses Event, weil ich schon gesucht habe und es leider nicht finden konnte.

Hab noch etwas alten Code von mir gefunden:


  private void KinectImageThread(object stateInfo)
        {
            if (runtime == null)
            {
                runtime = new Runtime();
                runtime.Initialize(RuntimeOptions.UseColor | RuntimeOptions.UseDepth);

                runtime.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(runtime_DepthFrameReady);
                runtime.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution640x480, ImageType.Depth);

              
                runtime.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(runtime_VideoFrameReady);
                runtime.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution1280x1024, ImageType.Color);
            }
        }

5.657 Beiträge seit 2006
vor 10 Jahren

Hi sterotony89,

es kommt immer der gleiche Punkt raus, der nach Mittelwertbildung folglich auch gleich bleibt. Das könnte daran liegen, dass die Kinect 32fr/sek zu langsam für das Programm ist. Aber das ist nur meine Theorie.

Und warum überprüfst du die Theorie nicht? Ob jedesmal das gleiche Bild verwendet wird, läßt sich doch leicht herausfinden. Und irgendwie ist es für mich selbstverständlich, daß du warten mußt, bis die Kinect ein neues Bild erstellt, wenn du mehrere unterschiedliche Bilder miteinander vergleichen willst.

Christian

Weeks of programming can save you hours of planning

S
sterotony89 Themenstarter:in
3 Beiträge seit 2014
vor 10 Jahren

Hey...

ich teste heute mal dieses DepthframeReady-Event und gebe bescheid ob es funktioniert hat.
@MrSparkle: Du hast natürlich Recht. Es wird immer das gleiche Bild verwendet, da sonst als Media niemals der gleiche Punkt ausgegeben werden würde.(Aufrund des Rauschens der Kinect)

Danke nochmal

173 Beiträge seit 2009
vor 10 Jahren

Da fallen mir gerade noch ein paar Sachen ein zur Kinect.

Wenn du die Kinect per Code startest sind die ersten Bilder (Farb und Tiefen) nicht zu gebrauchen, wegen AutoFocus usw.

Wir haben damals die ersten paar Bilder weggeschmissen und erst dann ausgewertet.

Hier noch etwas Code:


 void runtime_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)
{
    
    PlanarImage Image = e.ImageFrame.Image;

    BitmapSource bs = BitmapSource.Create(Image.Width, Image.Height, 96, 96, PixelFormats.Bgr565, null, Image.Bits, Image.Width * Image.BytesPerPixel);
...
}