2012-04-15 10 views
9

Sto lavorando a un'applicazione interattiva che ha bisogno di leggere e manipolare diverse immagini molto grandi contemporaneamente (25 immagini alla volta, circa 350 Mb di dimensione totale). OpenCV è abbastanza veloce e gestisce gli algoritmi con relativa facilità. Ma disegnarli con Qt si sta dimostrando un problema. Ecco due soluzioni meno che ideali che ho provato.Integrazione efficiente di Qt e OpenCV

Soluzione 1 (troppo lento)

Ogni volta che è necessario disegnare un'immagine diversa OpenCV, convertirlo in un QImage e disegnare quello. La conversione, purtroppo, richiede un po 'di tempo e non possiamo passare da un'immagine a velocità interattiva.

Soluzione 2 (troppo intensivo di memoria)

mantenere due pile di immagini, una per OpenCV e uno per Qt. Utilizzare lo appropriato al momento opportuno.

Ho accesso diretto ai dati di pixel OpenCV. Conosco la larghezza e l'altezza dell'immagine e so che i pixel sono valori RGB a 3 byte. Sembra che dovrebbe essere possibile disegnare l'immagine OpenCV rapidamente senza copiarlo in un contenitore QImage che (per quanto posso dire) contiene solo un duplicato dei dati.

Dove devo cercare di ottenere questo tipo di funzionalità da Qt?

risposta

5

È possibile condividere i dati tra QImage e openCV: entrambi hanno un operatore che utilizza i dati esistenti, forniti da un puntatore.

cv::Mat(int _rows, int _cols, int _type, void* _data, size_t _step=AUTO_STEP)
QImage (uchar * data, int width, int height, int bytesPerLine, Format format)

Ci potrebbe essere un problema con l'imbottitura se le righe non finiscono per essere multipli di 4bytes ma mi aspetto l'imbottitura di allineare con entrambi i tipi con la stessa dimensione di pixel - a almeno sullo stesso hardware

Un problema è che openCV utilizza BGR di default che non è molto ottimale per QImage (o qualsiasi altro display). Anche se non sono sicuro che QImage :: Format_ARGB32_Premultiplied sia necessariamente molto più veloce su Qt che usa openGL accelerato per il rendering di QImage.

Un'alternativa è utilizzare opencv quindi copiare i dati risultanti direttamente in una trama openGL e quindi utilizzare QGlWidget per visualizzare l'immagine senza un'altra copia.

+0

La cosa BGR è sicuramente fastidiosa; lo stiamo facendo ora chiedendo a OpenCV di memorizzare immagini in formato BGR (che è equivalente a Qt RGB, purtroppo Qt non ha un formato BGR). Ciò significa che dobbiamo fare attenzione con alcune delle routine di OpenCV, ma non dovrebbe essere un problema. Cercherò anche l'opzione texture OpenGL. Grazie! – Calvin

+0

FWIW, poiché non so se sia efficiente: metodo QImage :: rgbSwapped converte RGB in BGR, vedi http://qt-project.org/doc/qt-5.0/qtgui/qimage.html#rgbSwapped. Ho imparato questo dal codice sorgente di questo progetto: http://code.google.com/p/qt-opencv-multithreaded/ –

+0

@JongBorLeem non è l'RGB/BGR che è il problema è che le API di visualizzazione tendono a utilizzare BGRA (incluso QImage) mentre le API di imageprocessing utilizzano BGR - quindi è necessario scorrere l'intera immagine e copiarla estrapolando il byte extra "A" –

8

Non so se questo potrebbe essere utile a voi ora dopo 3 mesi. Ma sto avendo lo stesso tipo di applicazione in cui devo manipolare un flusso di immagini usando OpenCV e visualizzarlo su un'interfaccia QT. Dopo aver cercato su Google un po ', mi sono imbattuto in una soluzione molto lucida. Usa opengl's glDrawPixels per disegnare i dati grezzi dell'immagine direttamente sull'interfaccia Qt. La parte migliore, non devi scrivere alcun codice di conversione extra. Solo il codice di base per opengl per l'impostazione di una finestra e coordinate. Controlla il codice che ha una funzione che prende un puntatore IplImage * e usa quei dati per disegnare l'immagine. Potrebbe essere necessario modificare leggermente i parametri (in particolare le variabili WIDTH e HEIGHT) per visualizzare un'immagine con una dimensione specifica. E sì, non so quale sistema di generazione stai usando. Ho usato cmake e ho dovuto impostare le dipendenze per opengl anche se sto usando le librerie opengl di Qt.

Ho implementato una classe QIplImage che deriva da QGLWidget e sovrascrive il suo metodo paintGL per disegnare i dati dei pixel sul frame.

//File qiplimage.h 
class QIplImage : public QGLWidget 
{ 
    Q_OBJECT 

public: 
    QIplImage(QWidget *parent = 0,char *name=0); 
    ~QIplImage(); 
    void paintGL(); 
    void initializeGL(); 
    void resizeGL(int,int); 
    bool drawing; 

public slots: 
    void setImage(IplImage); 

private: 
    Ui::QIplImage ui; 
    IplImage* original; 
    GLenum format; 
    GLuint texture; 
    QColor bgColor; 
    char* name; 
    bool hidden; 
    int startX,startY,endX,endY; 
    QList<QPointF*> slopes; 
    QWidget* parent; 
    int mouseX,mouseY; 

}; 
//End of file qiplimage.h 

//file qiplimage.cpp 
#include "qiplimage.h" 
#include <Globals.h> 

QIplImage::QIplImage(QWidget *parent) : 
    QGLWidget(parent) 
{ 

} 
QIplImage::QIplImage(QWidget *parent,char* name): QGLWidget(parent) 
{ 
    ui.setupUi(this); 
    //This is required if you need to transmit IplImage over 
    // signals and slots.(That's what I am doing in my application 
    qRegisterMetaType<IplImage>("IplImage"); 
    resize(384,288); 
    this->name=name; 
    this->parent=parent; 
    hidden=false; 
    bgColor= QColor::fromRgb(0xe0,0xdf,0xe0); 

    original=cvCreateImage(cvSize(this->width(),this->height()),IPL_DEPTH_8U,3); 
    cvZero(original); 
    switch(original->nChannels) { 
     case 1: 
      format = GL_LUMINANCE; 
      break; 
     case 2: 
      format = GL_LUMINANCE_ALPHA; 
      break; 
     case 3: 
      format = GL_BGR; 
      break; 
     default: 
      return; 
} 
    drawing=false; 
    setMouseTracking(true); 
    mouseX=0;mouseY=0; 
    initializeGL(); 

} 
void QIplImage::initializeGL() 
{ 
    qglClearColor(bgColor); 
    //glClearColor(0.5f, 0.5f, 0.5f, 1.0f);    
    glDisable(GL_DEPTH_TEST); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
     glOrtho(0,this->width(),this->height(),0.0f,0.0f,1.0f); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    glEnable(GL_TEXTURE_2D); 
    glGenTextures(3,&texture); 
    glBindTexture(GL_TEXTURE_2D,texture); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
    glBindTexture(GL_TEXTURE_2D,texture);    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,this->width(),this->height(),0,GL_BGR,GL_UNSIGNED_BYTE,NULL); 
    glDisable(GL_TEXTURE_2D); 


} 
void QIplImage::setImage(IplImage image){ 
original=&image; 
//cvShowImage(name,original); 

updateGL(); 
} 

void QIplImage::paintGL(){ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glDisable(GL_DEPTH_TEST); 
if(!hidden){ 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
      glOrtho(0.0f,this->width(),this->height(),0.0f,0.0f,1.0f); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glEnable(GL_TEXTURE_2D); 
      glBindTexture(GL_TEXTURE_2D,texture); 
      glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,original->width,original->height,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,original->imageData); 
    glBegin(GL_QUADS); 
      glTexCoord2i(0,1); glVertex2i(0,this->height()); 
    glTexCoord2i(0,0); glVertex2i(0,0); 
      glTexCoord2i(1,0); glVertex2i(this->width(),0); 
      glTexCoord2i(1,1); glVertex2i(this->width(),this->height()); 
    glEnd(); 
    glFlush(); 
    } 

} 


void QIplImage::resizeGL(int width,int height){ 

    glViewport(0,0,this->width(),this->height()); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity();  
    glOrtho(0.0f,this->width(),this->height(),0.0f,0.0f,1.0f); 
    glMatrixMode(GL_MODELVIEW);   
    glLoadIdentity(); 
} 

Spero che questo aiuti.

+1

Abbiamo alcune sovrapposizioni che vengono disegnate sopra le immagini (non sulle immagini stesse, ma sopra di esse sullo schermo) nell'applicazione. Le viste OpenGL tendono ad essere un po 'strane riguardo a questo genere di cose; Mi piace questo approccio ma (penso) vuol dire che dobbiamo portare alcuni dei nostri codici dalle routine di disegno Qt alle routine di disegno OpenGL. +1 per il grande esempio di codice però. – Calvin

+0

Solo un aggiornamento a questo, glDrawPixels era lento e buggato. Ho usato quads strutturati invece..Performance è ottimo senza perdite di memoria o altri bug. –

+0

@RichardMacwan Puoi condividere la tua versione 'quadellata' invece di questa versione 'glDrawPixels'? – klefevre