2012-11-26 2 views
5

저는 C++/Qt에 익숙하지 않아 Visual Studio C++ 및 Qt (4.8.3)로 응용 프로그램을 만들려고합니다. 응용 프로그램은 QGraphicsView를 사용하여 이미지를 표시하므로 픽셀 단위로 이미지를 변경해야합니다.큰 QImage 문제

기본 코드 (간체)된다 이

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

이 주위에 12000x6000 픽셀까지의 이미지에 적합합니다. 이상한 일은이 크기를 넘어서 발생합니다. 예를 들어, img_width=16000img_height=8000을 설정하면 img = new QImage(...) 줄이 null 이미지를 반환합니다. 이미지 데이터는 약 512,000,000 바이트 여야하므로 32 비트 시스템에서도 너무 커야합니다. 또한 내 컴퓨터 (Win 7 64 비트, 8GB RAM)는 데이터를 보유 할 수 있어야합니다.

나는이 버전을 시도했다 : 처음에는

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

을이 작동합니다. img 포인터가 유효하고 예를 들어 img->width()을 호출하면 올바른 이미지 너비가 반환됩니다 (이미지 포인터가 null 인 경우 0 대신). 그러나 을 호출하자마자 포인터는 null이되며 img->width()은 0을 반환합니다.

그래서 내가 뭘 잘못하고 있니? 또는 픽셀 단위로 큰 이미지를 수정하는 더 좋은 방법이 있습니까?

안부, 데이비드

+0

할당이 실제로 작동하는지 확인하기 위해 먼저 malloc'd 메모리를 수동으로 0으로 설정하십시오. –

+0

다음을보십시오 : [Qt 프로젝트 위키 : 큰 이미지로드] (http://qt-project.org/wiki/LoadingLargeImages) – dschulz

+0

32 비트 Windows 응용 프로그램에서 기본 가장 큰 할당은 결과를 만들 수 있음을 기억하십시오./LARGEADDRESSAWARE 링커 플래그를 사용하거나 응용 프로그램에서 조각화를 줄이기 위해 사용하는 DLL을 리베이스하지 않고 주소 공간 조각화는 약 1.2GB (2GB 응용 프로그램 주소 공간)가됩니다. – drescherjm

답변

1

두 번째 방법은 올바른 방법입니다. 당신이 가지고있는 문제는 setPixel()로 전화 할 때, QImage은 당신이 제공 한 외부 버퍼의 복사본을 만들어 그것을위한 메모리가 부족합니다.

제공된 버퍼에서 픽셀 값을 직접 변경해보십시오. scanLine()을 사용하여 행의 버퍼에 대한 포인터를 가져올 수 있습니다. 정말 느린 이후로 나는 setPixel()을 사용하지 않을 것입니다.

+0

알겠습니다. 감사합니다. scanLine()을 살펴볼 것입니다. –

4

QImage는 32768x32768 픽셀 이미지 (짧은 서명)의 최대를 지원합니다. 이것은 다음 조건에서옵니다 : width * height * colordepth < INT_MAX (40 억) -> 32768 * 32768 * 4 = 40 억. 물론 두 번째 조건은 malloc이 요청 된 메모리를 할당 할 수 있다는 것입니다.

큰 이미지가 필요한 경우 다른 래퍼를 사용하거나 여러 개의 QImage로 분할해야합니다.

2

문제를 추적했습니다. 링커 옵션에 /LARGEADDRESSAWARE 플래그를 추가하는 것을 잊어 버렸습니다.

나는 scanLine() 힌트를 사용하여 Stephen Chu의 대답에 정말 감사했다. 처음에는 메모리를 절약하고 초는 훨씬 빠릅니다.

이제 원하는 목표 인 최대 32000x16000 픽셀의 이미지를 안전하게 만들 수 있습니다.