Lettura di una immagine in un buffer di memoria usando librerie standard C++
La lettura di una immagine in memoria è una operazione molto semplice con Visual C++. Infatti è disponibile la classe System::Drawing::Image che dispone di tutte le funzioni necessarie tra cui i metodi FromFile o FromStream che restituiscono un oggetto Bitmap.
Benché i due metodi operino in modo simile, il metodo FromStream è estremamente più veloce di FromFile. In entrambi i casi si tratta di operazioni molto semplici, segue il codice di esempio.
Lettura di una immagine con FromFile
using namespace System::Drawing;
// dichiaro un oggetto bitmap
Bitmap^ bmp;
// Leggo l'immagine dal file
bmp = (Bitmap^)Image::FromFile("Test.bmp");
Lettura di una immagine con FromStream
using namespace System::IO;
using namespace System::Drawing;
FileStream^ fs = gcnew FileStream("Test.bmp",FileMode::Open,FileAccess::Read);
bmp = (Bitmap^)Image::FromStream(fs,true,false);
La differenza di prestazioni è dovuta alla convalida dei dati dell'immagine operata automaticamente dal metodo FromFile e opzionale per il metodo FromStream (3^ parametro validateImageData:false).
Non è chiaro che tipo di validazione venga eseguita e pare che si tratti di un un bug di sulla funzione di validazione in MS Visual Studio .NET 2003.
Accesso ai Pixel di una immagine
Per accedere ai singoli pixel dell'immagine, il metodo Bitmap::GetPixel(col,row) è estremamente lento e per un accesso diretto e rapido alla memoria della immagine è consigliabile utilizzare la tecnica LockBits.
Accesso alla memoria di una immagine con LockBits
Lo scopo è ottenere un puntatore ad una matrice di memoria che contiene le informazioni sui pixel dell'immagine.
Il metodo Bitmap::LockBits ritorna on oggetto tipo Imaging::BitmapData che specifica gli attributi di un'immagine bitmap e permette l'accesso diretto alla memoria della immagine stessa. Quindi il metodo Imaging::BitmapData::Scan0 ritorna un puntatore al primo pixel selezionato con LockBits.
Imaging::PixelFormat pxf =Imaging::PixelFormat::Format24bppRgb;
Drawing::Rectangle rect = Drawing::Rectangle(0, 0, bmp->Width, bmp->Height);
Imaging::BitmapData^ bmpData =
bmp->LockBits(rect, Imaging::ImageLockMode::ReadOnly,pxf);
unsigned char * imgdata = (unsigned char*)bmpData->Scan0.ToPointer();
...operazioni sull'immagine...
bmp->UnlockBits(bmpData);
Organizzazione di una immagine RGB in memoria ottenuta con LockBits
Ottenuto il puntatore, l'accesso alla memoria dell'immagine è molto semplice e può essere fatto con le normali operazioni di accesso ad array, tenendo presente che:
-
I pixel sono organizzati in sequenza BGR in caso di formato 24bit o BGRA in caso di formato 32bit. Ogni canale richiede 1 byte
-
La memoria è allineata a 4 byte: questo vuol dire che la matrice di memoria ha un numero di colonne multiplo di 4. La proprietà
Stride fornisce la larghezza della matrice. La larghezza della matrice è sempre maggiore o uguale a quella strettamente necessaria.
-
Il segno di
Stride indica il verso dell'immagine.
-
Stride > 0: L'immagine in memoria corrisponde all'originale quinidi, la prima riga della matrice è la prima riga dell'immagine ecc..
-
Stride < 0: L'immagine in memoria è ribaltata rispetto all'originale, l'ultima riga della matrice è la prima riga dell'immagine, la penultima riga della matrice è la seconda riga dell'immagine ec...

Tempi di esecuzione a confronto
PkLab ha condotto un test per misurare le prestazioni in termini di velocità nella lettura e trasferimento dei dati dell'immagine in un buffer di memoria. Il test è stato eseguito su 1000 file bitmap a da 288x288 a 32bit (RGB)
Vengono messi a confronto i due metodi sopra descritti e le prestazioni offerte dalla classe CBitmap

Il grafico suggerisce chiaramente che
-
La classe
CBitmap è performante.
-
Per la sola operazione di lettura da file, il metodo
Image::FromStream è molto più veloce del metodo Image::FromFile
-
La copia dell'immagine in un buffer di memoria (con
LockBits) penalizza decisamente il metodo Image::FromStream e l'operazione Open+Copy ha prestazioni equivalenti per i due metodi della classe Image. Questo comportamento suggerisce che FromStream posticipa alcune operazioni dall'operazione di lettura da file, verso fasi successive del trattamento dell'immagine.
-
La classe
CBitmap offre una funzione di trasferimento verso un buffer di memoria molto veloce.
La classe CBitmap
La classe CBitmap è inclusa nelle GDI+ di MFC. Tuttavia ne esistono numerose versioni e varianti su internet. Per i test di questa pagina si utilizza la versione sviluppata da Benjamin Kalytta (http://www.kalytta.com/bitmap.h).
La classe è compatibile con i soli file bitmap e non con tutte le immagini come per la classe Image.
Comments
0 comments (Send your comment)