Italiano - English

Lettura da file e accesso veloce ai pixel di una immagine con C#

In questa pagina viene descritto come utilizzare classe Image::FromFile per leggere una immagine da un file e come accedere velocemente ai pixel utilizzando Bitmap::LockBits, con C#.  Vengono presentati esempi di codice e test di velocità dei vari metodi. Infine le prestazioni vengono confrontate con una classe CBitmap in C++ nativo, per eseguire le stesse operazioni su file bitmap (.bmp).

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;
 //creo un file stream sul file dell'immagine 
FileStream^ fs = gcnew FileStream("Test.bmp",FileMode::Open,FileAccess::Read);
 
//Leggo immagine dallo stream
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.

FIX: Slow performance when you call System.Drawing.Image.FromStream to load a bitmap image: http://support.microsoft.com/kb/831419

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.

 
// Selezione del formato desiderato 
Imaging::PixelFormat pxf =Imaging::PixelFormat::Format24bppRgb;
 
// Selezione Region Of Interest (ROI), ad esempio intera immagine
Drawing::Rectangle rect = Drawing::Rectangle(0, 0, bmp->Width, bmp->Height);
 
// Creazione oggetto BitmapData 
Imaging::BitmapData^ bmpData  =  
    bmp->LockBits(rect, Imaging::ImageLockMode::ReadOnly,pxf);
 
// Puntatore al primo pixel nella ROI selezionata  
unsigned char * imgdata = (unsigned char*)bmpData->Scan0.ToPointer();
 
...operazioni sull'immagine... 
 
// IMPORTANTE Unlock al termine delle operazioni
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 quindi, 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 ecc...
 BitmapData Memory Organization

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

Read Bitmap Methods Performances

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 bitmap.h 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.

Vedi anche:

PkCBitmap: Windows Bitmap File Loader C++ class

14-01-2010 705

Viene presentata una classe la lettura ultra veloce di un file bitmap in C++. La versione originale a cura di Benjamin Kalytta è stata modificata da PkLab introducendo, tra l'altro, il riutilizzo della memoria.

Vota questa pagina:

0 Commenti:

Lascia il tuo commento:

Note:
  • La tua email non è obligatoria e non sarà visibile in alcun modo
  • Si prega di inviare solo commenti relativi a questa pagina
  • Commenti inappropriati o offensivi saranno modificati o eliminati
  • Codici HTML non sono consentiti. Prego usare i BB code:
    [b]bold[/b], [u]underline[/u], [i]italic[/i], [code]code[/code]
Il codice, le illustrazioni e gli esempi riportati in questa pagina sono solo a scopo illustrativo. L'autore non prende alcuna responsabilità per il loro utilizzo da parte dell'utente finale.
Questo materiale è di proprietà di Pk Lab ed è utilizzabile liberamente a condizione di citarne la fonte.