2012-11-26 27 views
5

Sono abbastanza nuovo in C++/Qt e sto provando a creare un'applicazione con Visual Studio C++ e Qt (4.8.3). L'applicazione visualizza le immagini utilizzando un QGraphicsView, ho bisogno di cambiare le immagini a livello di pixel.Problemi con QImage di grandi dimensioni

Il codice di base è (semplificato):

QImage* img = new QImage(img_width,img_height,QImage::Format_RGB32); 
while(do_some_stuff) { 
    img->setPixel(x,y,color); 
} 
QGraphicsPixmapItem* pm = new QGraphicsPixmapItem(QPixmap::fromImage(*img)); 
QGraphicsScene* sc = new QGraphicsScene; 
sc->setSceneRect(0,0,img->width(),img->height()); 
sc->addItem(pm); 
ui.graphicsView->setScene(sc); 

Questo funziona bene per le immagini fino a circa 12000x6000 pixel. La cosa strana accade oltre questa dimensione. Quando imposto img_width=16000 e img_height=8000, ad esempio, la riga img = new QImage(...) restituisce un'immagine nulla. I dati dell'immagine dovrebbero essere intorno a 512.000.000 byte, quindi non dovrebbe essere troppo grande, anche su un sistema a 32 bit. Inoltre, la mia macchina (Win 7 64 bit, 8 GB RAM) dovrebbe essere in grado di contenere i dati.

Ho anche provato questa versione:

uchar* imgbuf = (uchar*) malloc(img_width*img_height*4); 
QImage* img = new QImage(imgbuf,img_width,img_height,QImage::Format_RGB32); 

In un primo momento, questo funziona. Il puntatore img è valido e chiamando img->width() per esempio restituisce la larghezza dell'immagine corretta (invece di 0, nel caso in cui il puntatore dell'immagine sia nullo). Ma non appena chiamo img->setPixel(), il puntatore diventa nullo e img->width() restituisce 0.

Quindi cosa sto facendo di sbagliato? O c'è un modo migliore di modificare le immagini di grandi dimensioni a livello di pixel?

saluti, David

+0

Provare a azzerare manualmente la memoria del malloc'd per verificare se l'allocazione funziona effettivamente. –

+0

Dai un'occhiata a questo: [Qt Project Wiki: caricamento di immagini grandi] (http://qt-project.org/wiki/LoadingLargeImages) – dschulz

+0

Ricorda che su un'applicazione Windows a 32 bit l'allocazione più grande di default è possibile ottenere come risultato di la frammentazione dello spazio degli indirizzi sarà di circa 1,2 GB (dello spazio di indirizzamento dell'applicazione da 2 GB) senza utilizzare il flag del linker/LARGEADDRESSAWARE e/o la ridefinizione delle DLL che l'applicazione utilizza per ridurre la frammentazione. – drescherjm

risposta

1

Il tuo secondo approccio è la giusta strada da percorrere. Il problema che stai riscontrando è quando chiami setPixel(), QImage crea una copia del buffer esterno che hai fornito e esaurisce la memoria per esso.

Provare a modificare il valore del pixel direttamente nel buffer fornito. È possibile utilizzare scanLine() per ottenere il puntatore al buffer di una riga. Non userei comunque setPixel() poiché è molto lento.

+0

Ok, grazie. Darò un'occhiata a scanLine(). –

4

QImage supporta un massimo di 32768x32768 immagini px (firmato a breve). Questo segue dalla condizione: larghezza * altezza * colore < INT_MAX (4 miliardi) -> 32768 * 32768 * 4 = 4 miliardi. La seconda condizione è ovviamente che malloc è in grado di allocare la memoria richiesta.

Se hai davvero bisogno di immagini più grandi dovrai utilizzare un altro wrapper o dividerlo in più QImage.

2

Ho rintracciato il problema. Ho appena dimenticato di aggiungere il flag /LARGEADDRESSAWARE alle opzioni del linker.

Ho anche apprezzato molto la risposta di Stephen Chu con il suggerimento scanLine(). Per prima cosa risparmia un po 'di memoria, in secondo luogo è molto più veloce.

Ora posso creare in modo sicuro immagini fino a 32000x16000 pixel, che era il mio obiettivo desiderato.