Bonjour,

Je travaille actuellement sur un projet où je capte un flux video image par image d'une camera. J'aimerais pouvoir afficher ce flux dans une fenêtre qt (un streaming en quelque sorte) tout en gardant un accès au programme. C'est à dire, si je lance une boucle qui récupère l'image de ma caméra et l'affiche dans la fenêtre, le thread est occupé et je ne peux rien faire tant que la boucle n'est pas terminée.

Je n'avais pas trop d'idée pour résoudre ce problème, j'ai donc décidé de mettre la fameuse boucle sur un autre thread et d'envoyer l'image calculée à l'aide d'un signal au thread principal pour qu'il l'affiche (je ne sais pas encore comment je vais pour stopper ce nouveau thread, je dois pouvoir le tuer avec le thread principal, mais bon, chaque problème en son temps). Le problème est que le ce code produit un segmentation fault dès que j'appel le signal avec "emit". Je cherche depuis maintenant quelque temps comment contourner ce problème (notamment en passant pas une classe intermédiaire de stockage avec mutex, qui ferait le "emit" dès que les données sont modifiées, mais je retombe toujours sur le même problème, c'est à dire un segmentation fault à l'exécution du "emit".

J'ai fouillé un peu partout pour essayer de trouver une solution. Ce que je veux faire reviens à faire un lecteur vidéo en quelque sorte, sauf que mes données ne sont pas des vidéos mais des flux de caméra !

Voici mon code actuel (problème dans DisplayThread.cpp), si vous avez des idées, je vous en serait très reconnaissant. Venant du Java, j'ai tendance à avoir des codes C++ quelque fois étranges car je ne connais pas forcément parfaitement les méandres du C++.

main.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
#include <QApplication>
#include "Menu.h"
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    Menu fenetre;
    fenetre.show();
 
    return app.exec();
}
menu.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "Menu.h"
#include "CamsView.h"
 
Menu::Menu() : QWidget()
{
    button1 = new QPushButton("View Distance & Amplitude Cameras");
    button2 = new QPushButton("View Distance & Amplitude Cameras after CoordTrf");
    button3 = new QPushButton("View Distance in 3D");
    button4 = new QPushButton("View Distance after CoordTrf");
    button5 = new QPushButton("Exit");
 
    layout = new QVBoxLayout;
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
    layout->addWidget(button4);
    layout->addWidget(button5);
 
    this->setLayout(layout);
 
    QObject::connect(button1, SIGNAL(clicked()), this, SLOT(camsView()));
    QObject::connect(button5, SIGNAL(clicked()), qApp, SLOT(quit()));
}
 
void Menu::camsView()
{
    CamsView *camsView = new CamsView(this);
    camsView->exec();
}
DisplayThread
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include "DisplayThread.h"
#include "CamsView.h"
 
#define LIMIT(val,min,max) (((val)<(min))?(min):(((val)>(max))? (max):(val)))
 
//!The RGBColMap struct is used to generate colormaps.
//!This is a local class in the file OCTViewSlice.cpp
typedef struct
{
    BYTE    pos;//!<position in the color shading
    BYTE    r;  //!<red value
    BYTE    g;  //!<green value
    BYTE    b;  //!<blue value
} RGBColMap; //!<colormap entry for SetColormap()
 
static const RGBColMap jet[]={
    {0x00, 0x00, 0x00, 0x80},
    {0x20, 0x00, 0x00, 0xff},
    {0x60, 0x00, 0xff, 0xff},
    {0xa0, 0xff, 0xff, 0x00},
    {0xe0, 0xff, 0x00, 0x00},
    {0xff, 0x80, 0x00, 0x00}
};
 
static const RGBColMap jetInverted[]={
    {0x00, 0x80, 0x00, 0x00},
    {0x20, 0xff, 0x00, 0x00},
    {0x60, 0xff, 0xff, 0x00},
    {0xa0, 0x00, 0xff, 0xff},
    {0xe0, 0x00, 0x00, 0xff},
    {0xff, 0x00, 0x00, 0x80}
};
 
static const RGBColMap bAndW[]={
    {0x00, 0x00, 0x00, 0x00},
    {0x20, 0x20, 0x20, 0x20},
    {0x60, 0x60, 0x60, 0x60},
    {0xa0, 0xa0, 0xa0, 0xa0},
    {0xe0, 0xe0, 0xe0, 0xe0},
    {0xff, 0xff, 0xff, 0xff}
};
 
//!fills a folormap with a desired color shading
void SetColormap(const RGBColMap* cm, RGBQUAD* col)
{
    int i,x;
    float f;
    col[0].rgbBlue =(BYTE)cm[0].b;
    col[0].rgbGreen=(BYTE)cm[0].g;
    col[0].rgbRed  =(BYTE)cm[0].r;
    col[0].rgbReserved=0x00;
    x=1;
    for (i=1;i<256;i++)
    {
        while (cm[x].pos<i)x++;
        f=((float)i-cm[x-1].pos)/(cm[x].pos-cm[x-1].pos);
        col[i].rgbBlue =(BYTE)(f*cm[x].b+(1.-f)*cm[x-1].b);
        col[i].rgbGreen=(BYTE)(f*cm[x].g+(1.-f)*cm[x-1].g);
        col[i].rgbRed  =(BYTE)(f*cm[x].r+(1.-f)*cm[x-1].r);
        col[i].rgbReserved=0x00;
    }
}
 
void DisplayThread::run()
{
    initCam();
    localDisplayFunc();
    closeCam();
}
 
void DisplayThread::initCam(){
    int res;
 
    //--------- SR_CheckForNewDllVersion ---------
#ifdef _WIN32
    res=SR_CheckForNewDllVersion(0);
    res=SR_CheckForNewDllVersion(1);
    res=SR_CheckForNewDllVersion(2);
#endif
 
#ifdef __BFIN__
    res=SR_Open(&srCam);
#else
    res=SR_OpenDlg(&srCam,3,0);
#endif
    printf("libusbTester: SR_OpenXXX() called result:%d\n",res);
    if(res<0)
    {
        printf("libusbTester: SR_OpenXXX() falied. abort Test.");
        return;
    }
 
    SR_SetMode(srCam,AM_COR_FIX_PTRN|AM_MEDIAN);
}
 
void DisplayThread::setDisplay(CamsView* window){
    QObject::connect(this, SIGNAL(displayCall(QImage)), window, SLOT(display(QImage)));
}
 
void DisplayThread::localDisplayFunc(){
    QImage image = image = QImage(176, 144, QImage::Format_RGB32);
    int res;
 
    res=SR_Acquire(srCam);
    ImgEntry* imgEntryArray;
    float v;
 
    BITMAPINFO   *_bmiCam;          //!<bitmap infos structure for the camera images (bmis are 32bit)
    BITMAPINFO   *_bmiScale;        //!<bitmap infos structure for the scale bar and the camera images (bmis are 32bit)
    RGBQUAD      *_dibCam;          //!<DIB for the camera image
    BYTE         *_dibScale;        //!<DIB for the scale image
    int           _numImg;          //!<number of images
 
    _bmiCam=(BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER)+1*sizeof(RGBQUAD));
    memset(_bmiCam,0,sizeof(BITMAPINFOHEADER));
    _bmiCam->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    _bmiCam->bmiHeader.biPlanes = 1;
    _bmiCam->bmiHeader.biBitCount = 32;
    _bmiCam->bmiHeader.biCompression = BI_RGB;
 
    _bmiScale=(BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD));
    memset(_bmiScale,0,sizeof(BITMAPINFOHEADER));
    _bmiScale->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    _bmiScale->bmiHeader.biPlanes = 1;
    _bmiScale->bmiHeader.biBitCount = 8;
    _bmiScale->bmiHeader.biCompression = BI_RGB;
    _bmiScale->bmiHeader.biWidth=256;
    _bmiScale->bmiHeader.biHeight=1;
 
    //alloc and fill scale DIB
    _dibScale=(BYTE*)malloc(256*sizeof(BYTE));
    for (int x=0;x<256;x++)_dibScale[x]=x;
    SetColormap(jet,_bmiScale->bmiColors);
 
    _numImg = SR_GetImageList(srCam, &imgEntryArray);
 
    int w,h;
 
    w=SR_GetCols(srCam);
    h=SR_GetRows(srCam);
 
    _dibCam=(RGBQUAD*)malloc(w*h*sizeof(RGBQUAD));//RGBQUAD,  RGBTRIPLE, BYTE, WORD
    _bmiCam->bmiHeader.biWidth =w;
    _bmiCam->bmiHeader.biHeight=-h;
 
    // 0 = raw distance
    WORD* p=(WORD*)imgEntryArray[0].data;
    float step=(float)0xff/(30000.f-0);
    for(int i=0;i<w*h;i++)
    {
        v=((float)p[i])*step;
        _dibCam[i]=_bmiScale->bmiColors[(BYTE)LIMIT(v,0,255)];
    }
 
    for (int i = 0; i < w; i++){
        for (int j = 0; j < h; j++){
            image.setPixel(i,j,qRgb(_dibCam[i+w*j].rgbRed, _dibCam[i+w*j].rgbGreen, _dibCam[i+w*j].rgbBlue));
        }
    }
 
    emit displayCall(image); // LE PROBLEME EST ICI ?
}
 
void DisplayThread::closeCam(){
    int res = SR_Close(srCam);
    printf("libusbTester: SR_Close() called result:%d\n",res);
}
CamsView.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "CamsView.h"
#include <QMessageBox>
 
CamsView::CamsView(Menu* parent):QDialog(parent){
 
    close = new QPushButton("Close");
    read = new QPushButton("Read camera");
 
    connect(close, SIGNAL(clicked()), this, SLOT(accept()));
    connect(read, SIGNAL(clicked()), this, SLOT(readCam()));
 
    label = new QLabel();
    image = QImage(176, 144, QImage::Format_RGB32);
 
    for (int i = 0; i < 176; i++){
        for (int j = 0; j < 144; j++){
            image.setPixel(i,j,qRgb(100,200,20));
        }
    }
    pixmap = QPixmap();
 
    QVBoxLayout *layoutPrincipal = new QVBoxLayout;
 
    pixmap = QPixmap::fromImage(image);
    pixmap = pixmap.scaled(2*176, 2*144);
    label->setPixmap(pixmap);
    layoutPrincipal->addWidget(label);
    layoutPrincipal->addWidget(read);
    layoutPrincipal->addWidget(close);
 
    setLayout(layoutPrincipal);
 
    //thread.setDisplay(this);
 
}
 
void CamsView::display(QImage imageNew){
    pixmap = QPixmap::fromImage(imageNew);
    pixmap = pixmap.scaled(2*176, 2*144);
    label->setPixmap(pixmap);
    label->repaint();
}
 
void CamsView::readCam(){
    thread.setDisplay(this);
    thread.start();
}
Headers

menu.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef MENU_H
#define MENU_H
 
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
 
class Menu : public QWidget
{
    Q_OBJECT
 
    public:
    Menu();
 
    public slots:
    void camsView();
 
    private:
    QPushButton *button1;
    QPushButton *button2;
    QPushButton *button3;
    QPushButton *button4;
    QPushButton *button5;
    QVBoxLayout *layout;
};
 
 
#endif // MENU_H
DisplayThread.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef DISPLAYTHREAD_H
#define DISPLAYTHREAD_H
#include <QThread>
#include <QImage>
#include "libMesaSR.h"
 
class CamsView;
 
class DisplayThread : public QThread
{
    Q_OBJECT
public:
    void setDisplay(CamsView* const window);
 
signals:
    void displayCall(QImage imageNew);
 
protected:
    void run();
 
private:
    void localDisplayFunc();
    void initCam();
    void closeCam();
    CMesaDevice* srCam;
};
 
#endif // DISPLAYTHREAD_H
CamsView.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#ifndef CAMSVIEW_H
#define CAMSVIEW_H
 
#include <iostream>
#include "windows.h"
#include <stdio.h>
#include <QApplication>
#include <QtGui>
#include <unistd.h>
#define _getch getchar
#include <string.h>
#include "libMesaSR.h"
#include "Menu.h"
#include "DisplayThread.h"
 
class CamsView: public QDialog
{
    Q_OBJECT
public:
    CamsView(Menu *parent);
    //void closeCam();
    //void initCam();
    //void display();
 
public slots:
    void readCam();
    void display(QImage imageNew);
 
private:
    QLabel *label;
    QPushButton *close;
    QPushButton *read;
    QImage image;
    QPixmap pixmap;
    DisplayThread thread;
};
 
#endif // CAMSVIEW_H
Il ne faut pas que j'oublie de préciser que je travaille avec Qt Creator sous Qt 4.6.2.

Je vous remercie d'avance

Thomas