Wert von C++ nach Matlab übergeben



  • Hallo,
    ich habe in Dev-C++ ein Programm geschrieben, was eine Schleife beinhaltet in welcher ein Wert ausgegeben wird. Zweck des Programms ist folgender: eine schwarze Kugel verfährt auf der x-Achse des Bildes. Die Position des Kugelmittelpunktes soll von dem Programm ausgegeben werden.
    Dieses Programm stürzt leider nach wenigen Sekunden ab.
    Nun meine zwei Fragen;
    warum stürzt mein Programm ab?
    Und wie kann ich den Wert in Matlab abrufen?
    Die Kugelpositon kann sich ständig ändern, weshalb sich auch der Ausgabewert des Programmes ändert. Matlab muss ständigen Zugriff auf diesen Wert haben. Eine Verzögerung größer als 0,2 Sekunden wäre zu viel.

    Ich hoffe jemand kann mir helfen.
    Danke!

    #ifdef _CH_
    #pragma package <opencv>
    #endif
    
    #ifndef _EiC
    #include "cv.h"
    #include "highgui.h"
    #include <stdio.h>
    #include <ctype.h>
    #endif
    
    int main()
    {
        char Vid[] = "WebCam";
    
        IplImage * frm; // erstellt objekt "frm"
        IplImage * cimg;
        IplImage * cimg2;
        CvCapture * capture; // erstellt objekt "capture"
        int x=640;
        int y=1;
        capture = cvCaptureFromCAM(0); // capture liest ein Bild von der Kamera ein
        CvScalar sl1;
        CvScalar sl2;
        CvScalar sr1;
        CvScalar sr2;
    
        if(!cvGrabFrame(capture))      // can't capture a frame 
            {              
            printf("Could not grab a frame\n\7");
            exit(0);
            }
     if( capture ) 
            {
            cvNamedWindow (Vid); //erstellt fenster "vid"
    
            do 
               {
                frm = cvQueryFrame( capture );
                cimg = cvRetrieveFrame(capture);           // retrieve the captured frame
                cvSetImageROI (cimg, cvRect(0, 220, x, y)); //Region of interest wird definiert um später in frmbw2 kopiert zu werden
                IplImage* frmbw2=cvCreateImage(cvSize(x,y),IPL_DEPTH_8U,1); //erstellt "frmbw" mit 640x1pixeln und 8 bit sw
                cvCvtColor(cimg,frmbw2,CV_BGR2GRAY); // frm -> frmbw (ROI von cimg wird in frmbw2 kopiert und in schwarz weiß gewandelt
                cvResetImageROI(cimg);
                cvSmooth(frmbw2, frmbw2, CV_GAUSSIAN, 5, 5 ); // glättet frmbw mit gauss filter
    
                for (int i = 0; i<(x-14);i++)
                    {
                    sl1=cvGet2D(frmbw2,0,i); // grauwert des iten pixels wird ausgelesen
                    sl2=cvGet2D(frmbw2,0,i+3); //grauwert des iten+3 pixels wird ausgelesen
                    double sl1d = sl1.val[0];
                    double sl2d= sl2.val[0];
                    double diff =(sl1d-sl2d); // differenz aus beiden grauwerten
    
                    if (diff>20)              //wenn die differenz zwischen den beiden pixeln groß genug ist (vermutlich linke kante der kugel)
                       {
                       sr1=cvGet2D(frmbw2,0,i+11); //gleiches prozedere für die rechte kante der kugel
                       sr2=cvGet2D(frmbw2,0,i+14);
                       double sr1d = sr1.val[0];
                       double sr2d= sr2.val[0];
                       double diff2=sr2d-sr1d;
                       int i2=i+7;
                       if (diff2>20)
                          {
    /*!!!!!!!!!!!!!!*/    [b]printf("kugelmittelpunkt wohl bei =%i\n",i2);//dieser Wert muss nach Matlab[/b]
                          }
                       }
                    }
                printf ("n");//um zu signalisieren, dass ein neues bild eingelesen wird
                                              if( frm )                                
                                                cvShowImage (Vid, frmbw2);
    
                                               int k = cvWaitKey( 1 );
                                                    if (k == 27 || k == '\r') // Press ESC and Enter 
                                                    break;                     // for out
                } while( frm );
                {cvDestroyWindow( Vid ); // Destroy the window
                cvReleaseCapture( &capture );
            }
            } else
                 puts( "Can not Open the Webcam" );
                 return 0;
    }
    


  • Du prüfst kaum Rückgabewerte und gibst angeforderte Resourcen nicht immer wieder frei.

    #include <stdlib.h>
    #include <stdio.h>
    
    #include <cv.h>
    #include <highgui.h>
    
    int main()
    {
    	const char Vid[] = "WebCam";
    	int x = 640;
    	int y = 1;
    	int key;
    	CvCapture *capture = cvCaptureFromCAM(0);
    
    	if (!capture) {
    		fprintf(stderr, "Can not Open the Webcam\n");
    		return -1;
    	}
    
    	cvNamedWindow(Vid);
    
    	for (key = 0; key != 27 && key != '\r'; key = cvWaitKey(1)) {
    		IplImage *subfrm, *frm = cvQueryFrame(capture);
    
    		if (!frm)
    			break;
    
    		cvSetImageROI(frm, cvRect(0, 220, x, y));
    		subfrm = cvCreateImage(cvSize(x, y), IPL_DEPTH_8U, 1);
    
    		if (subfrm) {
    			cvCvtColor(frm, subfrm, CV_BGR2GRAY);
    			cvResetImageROI(frm);
    			cvSmooth(subfrm, subfrm, CV_GAUSSIAN, 5, 5);
    			for (int i = 0; i < x - 14; i++) {
    				double pl1 = cvGet2D(subfrm, 0, i).val[0];
    				double pl2 = cvGet2D(subfrm, 0, i + 3).val[0];
    
    				if (pl1 - pl2 > 20) { // Differenz groß genug, evtl linke Kante der Kugel
    					double pr1 = cvGet2D(subfrm, 0, i + 11).val[0];
    					double pr2 = cvGet2D(subfrm, 0, i + 11 + 3).val[0];
    					if (pr2 - pr1 > 20) { // Differenz groß genug, evtl rechte Kante der Kugel
    						printf("kugelmittelpunkt wohl bei = %i\n",i + 7);//dieser Wert muss nach Matlab
    					}
    				}
    			}
    			fprintf(stderr, ".");
    			cvShowImage(Vid, subfrm);
    			cvReleaseImage(subfrm);
    		}
    	}
    
    	cvDestroyWindow(Vid);
    
    	cvReleaseCapture(&capture);
    
    	return 0;
    }
    

    Schau dir mal die benutzen Befehle an und achte darauf, ob es Fehler geben kann und ob Resourcen angefordert werden, die wieder freigegeben werden müssen.

    Wegen Matlab musst du gucken, was du genau willst. Die Daten in Matlab? Nur Matlabfunktionen benutzen? Wieso das Limit von 0,2 s? Aber mit Matlab kenn ich mich eh nicht so sonderlich gut aus...
    http://www.mathworks.com/



  • Vielen Dank schonmal! Ich werde das mit den Ressourcen mal überprüfen.
    Wegen Matlab;
    Ich erkläre erstmal mein Projekt. Ich beue eine Wippe ähnlich dieser hier
    http://www.youtube.com/watch?v=sx2oCmuyQuY
    Matlab steuert dabei den Servo an, der die Wippe neigt. Die Kugelposition wird von dem C Programm bestimmt.
    Matlab braucht einfach nur den Wert dieser Kogelposition als Variable. Bzw Simulink braucht den Wert als Eingang (In). Die 0,2Sek waren einfach nur als Beispiel für die Größenordnung aus dem Raum gegriffen



  • Man kann wohl auf Programme per TCP/IP zugreifen:
    http://www.mathworks.com/tcpip

    Oder aber man erstellt ein sogenanntes MEX-File, also eine dynamisch ladbare Bibliothek, die irgendwie(tm) die Daten zurückgibt.



  • Über diese Mex Files hab ich jetzt auch schon mal was gehört. Ich werde der Sache mal nachgehen und Alarm schlagen wenn ich das hinbekommen habe.
    Zurück zum anderen Problem.
    Ich habe jetzt geschlagene 5h 😞 über dem Programm gehockt und vor mich hin und her probiert und ich finde den Übeltäter nicht.
    Ich weiß nicht was ich noch wo releasen soll, damit es geht und ob das überhaupt die Lösung des Problems ist.
    Ich habe deinen Code ein wenig umgebaut:

    #include <stdlib.h>
    #include <stdio.h>
    
    #include <cv.h>
    #include <highgui.h>
    
    int main()
    {
        const char Vid[] = "WebCam";
        int x = 640;
        int y = 1;
        int key;
        CvCapture *capture = cvCaptureFromCAM(0);
    
        if (!capture) 
        {
        fprintf(stderr, "Can not Open the Webcam\n");
        return -1;
        }
    
        cvNamedWindow(Vid);
    
        for (key = 0; key != 27 && key != '\r'; key = cvWaitKey(1)) 
        {
        IplImage *subfrm, *frm = cvQueryFrame(capture);
    
            if (!frm)
                break;
    
            cvSetImageROI(frm, cvRect(0, 220, x, y));
            subfrm = cvCreateImage(cvSize(x, y), IPL_DEPTH_8U, 1);
            cvCvtColor(frm, subfrm, CV_BGR2GRAY);
            cvResetImageROI(frm);
    
            cvSmooth(subfrm, subfrm, CV_GAUSSIAN, 5, 5);
                for (int i = 0; i < x - 14; i++) 
                {
                double pl1 = cvGet2D(subfrm, 0, i).val[0];
                double pl2 = cvGet2D(subfrm, 0, i + 3).val[0];
    
                    if (pl1 - pl2 > 20) // Differenz groß genug, evtl linke Kante der Kugel
                    { 
                    double pr1 = cvGet2D(subfrm, 0, i + 11).val[0];
                    double pr2 = cvGet2D(subfrm, 0, i + 11 + 3).val[0];
                           if (pr2 - pr2 > 20) // Differenz groß genug, evtl rechte Kante der Kugel
                           { 
                           printf("kugelmittelpunkt wohl bei = %i\n",i + 7);//dieser Wert muss nach Matlab
                           }
                    }
                }
                fprintf(stderr, ".");
                cvShowImage(Vid, subfrm);
                cvReleaseImage(&subfrm);
        }
    
        cvDestroyWindow(Vid);
    
        cvReleaseCapture(&capture);
    
        return 0;
    }
    

    Das

    if (subfrm)
    

    habe ich rausgenommen. Ist das OK so? Und dann habe ich vor dem letzten subfrm (Zeile54) ein & gesetzt. Vorher hatte sich mein Compiler über diese Zeile beschwert.
    Nun beschwert er sich nicht mehr - was für mich immer der einzige Hinweis auf Fehler ist, da ich bei dem ganzen Zeigerkram immer den Überblick verliere.
    Was ich noch probiert habe, war die Schleifen nach und nach rauszunehmen und zu schauen ob das Programm dann auch abschmiert.
    Angefangen habe ich bei dieser hier:

    if (pr2 - pr2 > 20) // Differenz groß genug, evtl rechte Kante der Kugel
                           { 
                           printf("kugelmittelpunkt wohl bei = %i\n",i + 7);//dieser Wert muss nach Matlab
                           }
    

    Nimmt man sie raus, stürzt das Programm immernoch bei der gleichen Stelle ab.
    Gleiches gilt für die übergeordnete if-Schleife. Auch ohne die stürzt das Programm ab.
    Nehme ich jedoch diese For-Schleife raus, stürzt das Programm nicht ab.

    for (int i = 0; i < x - 14; i++) 
                {
                double pl1 = cvGet2D(subfrm, 0, i).val[0];
                double pl2 = cvGet2D(subfrm, 0, i + 3).val[0];
    
                    if (pl1 - pl2 > 20) // Differenz groß genug, evtl linke Kante der Kugel
                    { 
                    double pr1 = cvGet2D(subfrm, 0, i + 11).val[0];
                    double pr2 = cvGet2D(subfrm, 0, i + 11 + 3).val[0];
                           if (pr2 - pr2 > 20) // Differenz groß genug, evtl rechte Kante der Kugel
                           { 
                           printf("kugelmittelpunkt wohl bei = %i\n",i + 7);//dieser Wert muss nach Matlab
                           }
                    }
                }
    

    Auch wenn ich das Suchintervall kleiner mache indem ich x-14 durch zb. x-300 ersetze, dann hält das Programm länger durch, stürzt aber irgendwann auch ab.
    Ich vermute jetzt einfach mal, dass es mit den

    double pl1 = cvGet2D(subfrm, 0, i).val[0];
    double pl2 = cvGet2D(subfrm, 0, i + 3).val[0];
    

    zusammenhängt. Jedoch weiß ich wirklich nicht was daran falsch ist.



  • frederenke schrieb:

    Über diese Mex Files hab ich jetzt auch schon mal was gehört. Ich werde der Sache mal nachgehen und Alarm schlagen wenn ich das hinbekommen habe.

    😉

    frederenke schrieb:

    Zurück zum anderen Problem.
    Das

    if (subfrm)
    

    habe ich rausgenommen. Ist das OK so? Und dann habe ich vor dem letzten subfrm (Zeile54) ein & gesetzt. Vorher hatte sich mein Compiler über diese Zeile beschwert.

    Wieso hast du die Überprüfung rausgenommen ob überhaupt ein neues Bild erstellt werden konnte? Also das if solltest du drin lassen.
    Das mit dem &, da hast du Recht 😉

    frederenke schrieb:

    Was ich noch probiert habe, war die Schleifen nach und nach rauszunehmen und zu schauen ob das Programm dann auch abschmiert.
    Nehme ich jedoch diese For-Schleife raus, stürzt das Programm nicht ab.
    Ich vermute jetzt einfach mal, dass es mit den

    double pl1 = cvGet2D(subfrm, 0, i).val[0];
    double pl2 = cvGet2D(subfrm, 0, i + 3).val[0];
    

    zusammenhängt. Jedoch weiß ich wirklich nicht was daran falsch ist.

    Nimm doch bitte die [cpp] ... [/cpp] Tags.

    #include <stdlib.h>
    #include <stdio.h>
    
    #include <cv.h>
    #include <highgui.h>
    
    int main()
    {
    	const char Vid[] = "WebCam";
    	int x = 640;
    	int y = 1;
    	int key;
    	CvCapture *capture;
    
    	cvSetErrMode(CV_ErrModeSilent);
    
    	capture = cvCaptureFromCAM(0);
    
    	if (!capture) {
    		fprintf(stderr, "Can not Open the Webcam\n");
    		return -1;
    	}
    
    	cvNamedWindow(Vid);
    
    	for (key = 0; key != 27 && key != '\r'; key = cvWaitKey(1)) {
    		IplImage *subfrm, *frm = cvQueryFrame(capture);
    
    		if (!frm)
    			break;
    
    		cvSetImageROI(frm, cvRect(0, 220, x, y));
    		subfrm = cvCreateImage(cvSize(x, y), IPL_DEPTH_8U, 1);
    
    		if (subfrm) {
    			cvCvtColor(frm, subfrm, CV_BGR2GRAY);
    			cvResetImageROI(frm);
    			cvSmooth(subfrm, subfrm, CV_GAUSSIAN, 5, 5);
    /*			for (int i = 0; i < x - 14; i++) {
    				double pl1 = cvGet2D(subfrm, 0, i).val[0];
    				double pl2 = cvGet2D(subfrm, 0, i + 3).val[0];
    
    				if (pl1 - pl2 > 20) { // Differenz groß genug, evtl linke Kante der Kugel
    					double pr1 = cvGet2D(subfrm, 0, i + 11).val[0];
    					double pr2 = cvGet2D(subfrm, 0, i + 11 + 3).val[0];
    					if (pr2 - pr1 > 20) { // Differenz groß genug, evtl rechte Kante der Kugel
    						printf("kugelmittelpunkt wohl bei = %i\n",i + 7);//dieser Wert muss nach Matlab
    					}
    				}
    			}*/
    			fprintf(stderr, ".");
    			cvShowImage(Vid, subfrm);
    			cvReleaseImage(&subfrm);
    		} else
    			fprintf(stderr, "Create subfrm failed: %s\n", cvErrorStr(cvGetErrStatus()));
    
    	}
    
    	cvDestroyWindow(Vid);
    
    	cvReleaseCapture(&capture);
    
    	return 0;
    }
    

    Was gibt das denn aus? Punkte?
    Wenn das funktioniert, setzt mal double pl1 = cvGet2D(subfrm, 0, 0).val[0]; genau vor die auskommentierte Schleife. Was passiert dann?

    Achja, das Abstürzen, wie hat sich das genau bemerkbar gemacht?
    (Hab jetzt mal die Fehlerbehandlung von OpenCV in Zeile 16 auf normales Verhalten eingestellt. Sonst bricht das Program nach einem Fehler einfach ab.)
    Evtl. kannst du ja noch eine Zeile wie 56 hinter das cvGet2D setzen. Vielleicht ist da ein Fehler!?

    EDIT:
    Was mir jetzt erst auffällt, gibt man nicht normalerweile immer x, y an? Für das cvGet2D?
    Und dann nochmal bischen weitergeguckt, double cvGetReal2D(const CvArr* arr, int idx0, int idx1) scheint genau das zu sein, was du an sich willst 😉



  • HA! es läuft! endlich!
    DANKE!!

    #include <stdlib.h>
    #include <stdio.h>
    
    #include <cv.h>
    #include <highgui.h>
    
    int main()
    {
        const char Vid[] = "WebCam";
        int x = 640;
        int y = 1;
        int key;
        CvCapture *capture;
    
        cvSetErrMode(CV_ErrModeSilent);
    
        capture = cvCaptureFromCAM(0);
    
        if (!capture) {
            fprintf(stderr, "Can not Open the Webcam\n");
            return -1;
        }
    
        cvNamedWindow(Vid);
    
        for (key = 0; key != 27 && key != '\r'; key = cvWaitKey(1)) {
            IplImage *subfrm, *frm = cvQueryFrame(capture);
    
            if (!frm)
                break;
    
            cvSetImageROI(frm, cvRect(0, 220, x, y));
            subfrm = cvCreateImage(cvSize(x, y), IPL_DEPTH_8U, 1);
    
            if (subfrm) {
                cvCvtColor(frm, subfrm, CV_BGR2GRAY);
                cvResetImageROI(frm);
                cvSmooth(subfrm, subfrm, CV_GAUSSIAN, 5, 5);
                for (int i = 0; i < x - 14; i++) {
                    double pl1 = cvGetReal2D(subfrm, 0, i);
                    double pl2 = cvGetReal2D(subfrm, 0, i+3);
    
                    if (pl1 - pl2 > 20) { // Differenz groß genug, evtl linke Kante der Kugel
                        double pr1 = cvGetReal2D(subfrm, 0, i+11);
                        double pr2 = cvGetReal2D(subfrm, 0, i+11+3);
                        if (pr2 - pr1 > 20) { // Differenz groß genug, evtl rechte Kante der Kugel
                            printf("kugelmittelpunkt wohl bei = %i\n",i + 7);//dieser Wert muss nach Matlab
                        }
                    }
                }
                fprintf(stderr, ".");
                cvShowImage(Vid, subfrm);
                cvReleaseImage(&subfrm);
            } else
                fprintf(stderr, "Create subfrm failed: %s\n", cvErrorStr(cvGetErrStatus()));
    
        }
    
        cvDestroyWindow(Vid);
    
        cvReleaseCapture(&capture);
    
        return 0;
    }
    

    Es war wirklich das cvGet2D. Aber wie genau hast du erkannt, dass es das getReal2d sein muss?
    Ich mach mich dann mal an die MEX files 😉
    Nochmal einen riesen Dank - ich bin hier gestern schon ziemlich verzweifelt



  • Ich bin so blind......
    Scalar != Double 😉



  • eine kurze Rückmeldung, fall mal jemand diesen Thread ausgraben sollte.
    Ich habe das Problem komplett in C gelöst und habe die Sache mit den MEX-Files hinten angestellt.
    Es hatte ziemlich lange gedauert, bis ich zwei Versionen von Matlab und Visual C++ gefunden habe, die zusammenarbeiten.
    Sollte jemand das hier nochmal brauchen - es gibt auf der Mathworks Seite eine Kompabilitätsliste von C Compilern und entsprechenden Matlab Versionen.
    Also erst checken ob eure Versionen zusammenspielen und dann mit der MEX-Files Anleitung (auch auf der Mathworks Seite) rumspielen.

    Vielen Dank nochmal an lagalopex für die Hilfe!


Log in to reply