2012-11-26 27 views
5

Jestem całkiem nowy w C++/Qt i próbuję stworzyć aplikację z Visual Studio C++ i Qt (4.8.3). Aplikacja wyświetla obrazy przy użyciu QGraphicsView, potrzebuję zmienić obrazy na poziomie pikseli.Problemy z dużym QImage

Kod zasadowy (uproszczony):

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); 

Działa to dobrze dla zdjęć do około 12000x6000 piksela. Dziwna rzecz dzieje się poza tym rozmiarem. Po ustawieniu na przykład img_width=16000 i img_height=8000, linia img = new QImage(...) zwraca pusty obraz. Dane obrazu powinny wynosić około 512 000 000 bajtów, więc nie powinny być zbyt duże, nawet w systemie 32-bitowym. Ponadto mój komputer (Win 7 64bit, 8 GB RAM) powinien być zdolny do przechowywania danych.

Ja również próbowałem tej wersji:

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

na początku, to działa. Wskaźnik img jest prawidłowy i wywołanie na przykład img->width() zwraca poprawną szerokość obrazu (zamiast 0, na wypadek, gdyby wskaźnik obrazu był pusty). Ale gdy zadzwonię pod numer img->setPixel(), wskaźnik stanie się pusty i img->width() zwróci 0.

Co więc robię źle? Czy istnieje lepszy sposób modyfikowania dużych obrazów na poziomie pikseli?

Pozdrowienia, David

+0

Spróbuj ręcznie wyzerować pamięć malloc'd, aby sprawdzić, czy alokacja rzeczywiście działa. –

+0

Spójrz na to: [Qt Project Wiki: ładowanie dużych obrazów] (http://qt-project.org/wiki/LoadingLargeImages) – dschulz

+0

Pamiętaj, że w 32-bitowej aplikacji Windows domyślna największa alokacja może być wynikiem Fragmentacja przestrzeni adresowej będzie wynosić około 1,2 GB (przestrzeni adresowej aplikacji o pojemności 2 GB) bez użycia flagi/LARGEADDRESSAWARE i/lub do zmiany bibliotek dll używanych przez aplikację w celu zmniejszenia fragmentacji. – drescherjm

Odpowiedz

1

Twoje drugie podejście to właściwa droga. Problem z tym związany polega na tym, że wywołanie setPixel(), QImage powoduje utworzenie kopii zewnętrznego bufora i wyczerpanie pamięci dla niego.

Spróbuj zmienić wartość piksela bezpośrednio w dostarczonym buforze. Możesz użyć scanLine(), aby uzyskać wskaźnik do bufora linii. I tak nie użyłbym setPixel(), ponieważ jest bardzo powolny.

+0

Ok, dzięki. Spojrzę na scanLine(). –

4

QImage obsługuje maksymalnie 32768x32768 px Zdjęcia (podpisane krótki). Wynika to z warunku: szerokość * wysokość * colordepth < INT_MAX (4 miliardy) -> 32768 * 32768 * 4 = 4 miliardy. Drugim warunkiem jest oczywiście to, że malloc jest w stanie przydzielić żądaną pamięć.

Jeśli naprawdę potrzebujesz większych zdjęć, będziesz musiał użyć innego opakowania lub podzielić na wiele obrazów QImage.

2

Wyśledziłem problem. Właśnie zapomniałem dodać flagę /LARGEADDRESSAWARE do opcji Linkera.

Naprawdę doceniam również odpowiedź Stephena Chu za pomocą wskazówki scanLine(). Najpierw oszczędza trochę pamięci, po drugie jest znacznie szybciej.

Teraz mogę bezpiecznie tworzyć obrazy o rozdzielczości do 32000x16000 pikseli, co było moim pożądanym celem.