j'ai un problème avec QTimer, il me fait totalement planter mon programme lorsque je l'utilise conjointement avec une autre librairie.
j'ai déclaré dans ma classe (dérivée de QLabel avec un Q_OBJECT) un QTimer (m_timer)
ensuite dans le démarrage de mon appli, je fais :
m_timer.start(100);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(captureLoop()));
dans captureLoop() (public slots)
j'ai une fonction d'une autre librairie qui récupère une image
et appelle une autre méthode de ma classe qui détecte un visage sur l'image et retourne la position du visage. La détection s'effectue via une fonction de ma seconde librairie.
Sauf que dès qu'il arrive à la détection (la fonction de l'autre librairie en particulier), le programme me met un segmentation fault. Sans rentrer dans la fonction (mode debbugeur)
Si je désactive la détection, tout fonctionne avec le Timer de Qt.
Vous allez surement me dire : "ben le problème viens de la fonction de détection de ton autre librairie"
Eh bien non, car si je supprime le timer de Qt et que j'appelle ma méthode manuellement, tout fonctionne (mais pas de boucle possible).
J'ai l'impression que c'est le méta code crée par Qt pour les slots personnalisés qui pose problème...
Déclare m_timer comme un pointeur... J'ai récemment travaillé sur les timers, et lors de la connexion par QObject::connect, c'était ça qui me faisait planter.
Ne t'inquiète pas, tout doit bien marcher le seul problème c'est ça :
m_timer.start(100);
il est probable qu'en 100ms ton appli n'est pas fini le premier traitement fait dans captureLoop(). Il te faut donc optimiser à mort ton code. Je te conseil de pré calculer tout ce que tu peux, si tu as des variables qui ne changent pas entre deux appels de captureLoop() alors initialise les ailleurs, enfin optimise ton traitement ^^.
oui et non ^^, disons qu'il a pas fini de traiter la totalité du traitement et bim l'évènement du QTimer ce déclenche quand même, or ton appli n'est pas multi thread donc il va essayer de rappeler la même fonction qui n'a pas fini son traitement, résultat ton ordi ne sait plus ou il en est
oui et non ^^, disons qu'il a pas fini de traiter la totalité du traitement et bim l'évènement du QTimer ce déclenche quand même, or ton appli n'est pas multi thread donc il va essayer de rappeler la même fonction qui n'a pas fini son traitement, résultat ton ordi ne sait plus ou il en est
Non.
Pour faire un peu plus long : La boucle de évènementielle de Qt ne peut pas fonctionner en même temps qu'un slot (sauf si tu fais du multithreading mais dans ce cas tu le saurais), quand Qt appelle un slot il sort de sa boucle et donc les événements ne sont pas gérés jusqu'à ce que le slot finisse.
Edit : et pour répondre à Aure77, je pense que ça vient quand même de la méthode de détection quoique tu en penses peut-être un problème d'initialisation ou je ne sais quoi.
Montre ton code avec QTimer qui plante et celui sans qui ne plante pas, ça serait plus évident à voir.
Lancement de l'application version qui marche pas :
int MaClasse::run()
{
// initialisations ....
if( initialisation OK )
{
m_timer.start(100);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(captureLoop()));
}
}
Lancement de l'application version qui marche (une seule image car plus de boucle) mais s'affiche et plante pas :
int MaClasse::run()
{
// initialisations ....
if( initialisation OK )
{
captureLoop();
}
}
CaptureLoop :
void MaClasse::captureLoop()
{
ostringstream score_str;
Cercle c;
// Capture la frame on la charge dans une matrice Mat
capture >> frame;
if( frame.empty() )
break;
flip( frame, frame_copy, 1 );
if(compteur>50 || compteur<1)
{
compteur=0;
position_pt = giveRandomposition();
createRandomCreature(creature);
creature->setPosition(position_pt, ((double)NBCASES/(double)nb_cases));
}
compteur++;
// Detection de visage
if( detect_faces )
{
// Appel de la fonction pour détecter et afficher les visages
c = detect_and_draw_faces(2); // c'est dans cette fonction qui ma fait planter mon programme !!!!!!!
if(collisionCercle(creature->getPtGauche(), creature->getPtDroite(), c ))
{
creature->updateScore(score);
//score++;
cout << "Collision - Score : " << score << endl;
position_pt = giveRandomposition();
createRandomCreature(creature);
creature->setPosition(position_pt, ((double)NBCASES/(double)nb_cases));
}
}
// On affiche une grille
if( show_grid )
draw_grid();
creature->draw(frame_copy);
score_str.str("");
score_str << "Score : " << score;
putText( frame_copy, score_str.str(), Point(6,12), CV_FONT_HERSHEY_SIMPLEX, 0.40, Scalar(0, 255, 0) );
QImage test = Mat2QImage(frame_copy); // convertit Mat en QImage
this->setPixmap(QPixmap::fromImage(test));
this->update();
}
Méthode de détection :
Cercle MaClasse::detect_and_draw_faces( double scale )
{
Point pt1, pt2, centre;
int i;
Cercle c1 = { 0, Point(0,0) };
double diametre_cercle;
vector<Rect> faces;
Mat gray, smallFrame( cvRound (frame_copy.rows/scale), cvRound(frame_copy.cols/scale), CV_8UC1 );
cvtColor( frame_copy, gray, CV_BGR2GRAY ); // ça plante à cette fonction !!!!!!!!!!!!!!
resize( gray, smallFrame, smallFrame.size(), 0, 0, INTER_LINEAR );
// ............
}
Je précise que ça ne peut pas venir de temps trop court du timer car je l'ai exécuté en mode pas à pas et ça plante à la fonction que j'ai indiqué (cf le commentaire dans le code source).
ça ne peut pas venir de la fonction de l'autre librairie car si je laisse l'ancienne boucle de mon programme (qui m'oblige à laisser l'interface graphique de l'autre librairie), tout fonctionne !
Le problème de QTimer, c'est que la fonction est exécuté en tant que "SLOTS", c'est peut être ça qui pose problème...
EDIT : Par contre j'ai un autre problème : lorsque je clique sur la croix fermer de ma fenetre, il ferme bien la fenêtre mais l'exécution de la boucle s'effectue toujours en arrière plan. Comment arrêter cette boucle lorsqu'on ferme ?
J'utilise plus le timer vu qu'il me fait tout planter...donc timer.stop() pas possible...
Le problème c'est que : QApplication::processEvents(); doit laisser la QApplication lancé dans le main, comment dire de d'arrêter dans le closeEvent ?
Remplace le forever par while(isVisible()) ou un truc de ce genre.
Citation : Aure77
J'utilise plus le timer vu qu'il me fait tout planter...donc timer.stop() pas possible...
En fait, tout ce que tu peux dire, c'est que tu as une erreur dans ton code qui fait tout planter quand tu utilises le QTimer.
Le fait que la fonction soit appelée ou non comme un slot ne change rien (sauf si tu utilises les threads).
Et:
if( frame.empty() )
break;
Ça devrait être return, non ? Comme tu avais une boucle au départ, tu as sûrement oublié de le changer.
(Ça n'est même pas censé compiler comme ça).
En même temps la solution qui consiste à remplacer un slot QTimer avec une boucle qui contient processEvent, elle est bien moche.
Ca marche mais ça n'attirera que des problèmes par la suite ...
Remplace le forever par while(isVisible()) ou un truc de ce genre.
Citation : Aure77
J'utilise plus le timer vu qu'il me fait tout planter...donc timer.stop() pas possible...
En fait, tout ce que tu peux dire, c'est que tu as une erreur dans ton code qui fait tout planter quand tu utilises le QTimer.
Le fait que la fonction soit appelée ou non comme un slot ne change rien (sauf si tu utilises les threads).
Et:
if( frame.empty() )
break;
Ça devrait être return, non ? Comme tu avais une boucle au départ, tu as sûrement oublié de le changer.
(Ça n'est même pas censé compiler comme ça).
Oui ça ne c'est bien return et pas break (erreur de copier/coller).
Une erreur dans mon code ? Alors pourquoi ça fonctionne correctement avec processEvents ? Et comme je l'ai dit, l'erreur apparait sur une fonction de l'autre librairie, comment voulez vous que je débugge... ? Mais il est possible que cette fonction utilise les threads ce qui pourrai poser un problème ?
Citation : GrecKo
En même temps la solution qui consiste à remplacer un slot QTimer avec une boucle qui contient processEvent, elle est bien moche.
Ca marche mais ça n'attirera que des problèmes par la suite ...
Ben le premier problème c'est que je ne peux plus quitter mon application.
Et lorsque je force la fermeture via la console (ctrl+c), j'ai le message suivant qui s'affiche : QObject::killTimers: timers cannot be stopped from another thread
J'aimerais bien pouvoir utiliser QTimer mais je ne vois pas pourquoi ça plante...
Comment faire pour connaitre l'origine du problème ?
EDIT : Voici l'erreur que j'ai avec QTimer :
Segmentation Fault In icvBGRx2Gray_8u_CnC1R () (C:\OpenCV2.0\bin\libcv200.dll)
Une erreur dans mon code ? Alors pourquoi ça fonctionne correctement avec processEvents ? Et comme je l'ai dit, l'erreur apparait sur une fonction de l'autre librairie, comment voulez vous que je débugge... ? Mais il est possible que cette fonction utilise les threads ce qui pourrai poser un problème ?
Ça peut être un dépassement de tableau ailleurs dans ton code. Puisque que ça touche le QTimer, tu peux essayer de changer la place de "QTimer timer;" dans la classe (le déclarer avant tous les autres attributs par exemple).
Ça ne corrigera pas le problème, c'est juste pour tester.
void MaClasse::run()
{
// ...
Mat test;
Mat toto = imread("test.png");
cvtColor(toto, test, CV_BGR2GRAY); // pas de problème
timer.start(100);
// ...
}
void MaClasse::captureLoop()
{
Mat test;
Mat toto = imread("test.png");
cvtColor(toto, test, CV_BGR2GRAY); // erreur !!!!
}
Comme quoi il peut pas y avoir de problème d'allocation ou de dépassement de tableau.
le premier bloc est OK, cvtColor fonctionne.
je lance le timer qui lance CaptureLoop
le même code plante...
Comme quoi ya un truc dans l'appel de QTimer qu'il aime pas !
up, toujours pas trouvé de solutions, tout ce que je sais c'est que toutes les fonctions comprises dans la dll de openCV font planter le progamme quand on utilise QTimer ! (car j'ai essayer des les recodé à la main mais ya certaines qui sont impossible à refaire...)
Mais tous les liens concernent opencv 2.0 et openmp, et comme opencv 2.1 utilise TBB à la place d'openmp, la solution évoquée dans le 1er lien (2e page), ne changera probablement rien.
Sinon peut-être qu'il faut recompiler opencv avec la même version de mingw que Qt (parce que recompiler Qt est un peu plus long).
J'ai regardé tes liens (j'ai notamment téléchargé les libs dans la deuxième page), mais ça ne fonctionne pas car le problème provient des *.dll et pas des *.a... (sauf si une directive de compilation oblige à ne pas passer par les dll).
J'utilise OpenCV2.0. J'ai regardé la possibilité de recompiler OpenCV, mais je ne sais pas comment faire sous windows avec MinGW (avec CMake).
EDIT:
Finalement j'ai réussi à recompiler OpenCV avec une version de GCC plus récente, et maintenant tout est OK (avec QTimer)!
J'ai aussi rencontré ce problème et pour ma part j'ai opté pour une solution peut être moins opti mais bien pratique de ne pas directement connecter mon QTimer au slot que je veux activer a intervalle régulière.
A la place je connecte a un autre slot qui lui va choisir ou non d'activer le slot en question :
public slots:
void foo();
void fooAppeleParTimer();
private:
bool m_condition;
void Class::foo()
{
//le truc a faire régulierement
}
void Class::fooAppeleParTimer()
{
if (m_condition)
{
this->foo();
}
}
A la place de stopper ou déconnecter le QTimer on choisis simplement quand il peux activer foo() en changeant la valeur du booleen.
Dans mon cas un QTimer de plus ou de moins activé en fond ne pose pas de problème coté performances.
[Qt] problème avec QTimer
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Ma chaine youtube, une notion de c++ en 5 min !
Ma chaine youtube, une notion de c++ en 5 min !