2015-03-24 16 views
6

Modifica: RISOLTO! Si prega di vedere la mia risposta in basso per i dettagli. Non sono riuscito a trovare una risposta alla domanda originale ma ho trovato una soluzione alternativaConversione dell'immagine in C#

Questa domanda può essere chiesta da qualche altra parte ma ho cercato per giorni e non riesco a trovare nulla che aiuti.

Domanda: Ho bisogno di convertire "Stream" a "immagine (BGR, byte)" in un colpo solo, c'è un comando/modo per convertire direttamente da System.Drawing.Image.FromStream a Emgu. CV.Image (BGR, byte) senza la conversione da flusso-immagine-bitmap-immagine (BGR, byte)?

Informazioni: sto codifica in C# in Visual Studio 2010 come parte del mio progetto di tesi. Sto acquisendo un flusso di immagini da una telecamera IP su una rete e applicando molti algoritmi per rilevare i volti/estrarre le caratteristiche facciali e riconoscere un volto di individui. Sulla mia fotocamera locale con i laptop posso ottenere FPS di circa 25 ~ (dare o prendere) inclusi gli algoritmi perché non devo convertire l'immagine. Per un flusso di telecamere IP ho bisogno di convertirlo più volte per ottenere il formato desiderato e il risultato è di circa 5-8 fps.

(So che il mio metodo attuale è estremamente inefficiente ed è per questo che sono qui, in realtà sto convertendo un'immagine 5 volte totale (anche in grigio), in realtà usando solo metà della memoria dei miei processori (i7, 8gb RAM)). Deve essere l'immagine (bgr, byte) poiché questo è l'unico formato con cui gli algoritmi funzioneranno.

Il codice che sto usando per ottenere l'immagine:

//headers 
using System.IO 
using System.Threading; 
using System.Net; 
//request a connection 
req = (HttpWebRequest)HttpWebRequest.Create(cameraUrl); 
//gives chance for timeout for errors to occur or loss of connection 
req.AllowWriteStreamBuffering = true; 
req.Timeout = 20000; 
//retrieve response (if successfull) 
res = req.GetResponse(); 
//image returned 
stream = res.GetResponseStream(); 

Ho un sacco di roba in background gestione delle connessioni, dati, sicurezza, ecc che ho accorciato al codice di cui sopra. Il mio codice corrente per convertire l'immagine per l'output desiderato:

//Convert stream to image then to bitmap 
Bitmap bmpImage = new Bitmap(System.Drawing.Image.FromStream(stream));      
//Convert to emgu image (desired goal) 
currentFrame = new Emgu.CV.Image<Bgr, Byte>(bmpImage); 
//gray scale for other uses 
gray = currentFrame.Convert<Gray, Byte>(); 

Capisco che ci sia un metodo per salvare un'immagine in locale temporaneamente, ma avrei bisogno di evitare che per motivi di sicurezza. Sto cercando una conversione diretta per risparmiare energia di elaborazione. Sto trascurando qualcosa? Tutto l'aiuto è apprezzato.

Grazie per la lettura. (Aggiornerò questo se qualcuno richiede ulteriori dettagli) -Dave

+0

È possibile utilizzare la classe Cronometro per misurare le prestazioni di ogni linea? (per le ultime 3 righe) –

+0

Non l'ho usato per misurare le prestazioni, ma se mi dai un po 'di tempo darò uno schiaffo a qualcosa e commenterò. Le ultime 3 righe sono ciò che rallenta quando esegue 5 conversioni, attingendo a una imagebox e restituendo gli output dell'algoritmo mentre prepara il prossimo frame – Hughsie28

+0

@VanoMaisuradze La classe cronometro indica che è stato necessario 00: 00: 00: 0343616 per completare l'operazione per quelle 3 righe in particolare (penso che sia in millisecondi). – Hughsie28

risposta

3

Credo di aver trovato la risposta al mio problema. Mi sono dilettato usando l'idea di elaborazione in memoria di Vano Maisuradze che ha migliorato il fps di un piccolo margine (non immediatamente notevole senza test). E anche grazie a Plinths risposta Ho una comprensione di multi-threading e posso ottimizzare questo come progredisco in quanto posso dividere gli algoritmi fino a lavorare in parallelo.

Quello che penso sia la mia causa è la velocità di rete! non il ritardo dell'algoritmo attuale. Come sottolineato da Vano con il cronometro per trovare la velocità, gli algoritmi in realtà non consumavano molto. Quindi, con e senza gli algoritmi, la velocità è all'incirca uguale se ottimizzo l'utilizzo del threading in modo da raccogliere il frame successivo mentre quello precedente termina l'elaborazione.

Ho eseguito alcuni test su alcuni router fisici Cisco e ho ottenuto lo stesso risultato se un po 'più lento con le velocità di clock e le larghezze di banda che erano evidenti. Quindi ho bisogno di trovare un modo per recuperare i frame sulle reti più velocemente, molto grande grazie a tutti quelli che hanno risposto a chi mi ha aiutato a capire meglio!

Conclusione:

  • Multi-threading per ottimizzare
  • Elaborazione in memoria invece di convertire costantemente
  • soluzioni di rete migliore (maggiore larghezza di banda e velocità)

Edit: Il codice per recuperare un'immagine e il processo in memoria per chi trova questo in cerca di aiuto

public void getFrames(object sender, EventArgs e) 
{//Gets a frame from the IP cam 
    //Replace "IPADDRESS", "USERNAME", "PASSWORD" 
    //with respective data for your camera 
    string sourceURL = "http://IPADDRESS/snapshot.cgi?user=USERNAME&pwd=PASSWORD"; 
    //used to store the image retrieved in memory 
    byte[] buffer = new byte[640 * 480]; 
    int read, total = 0; 

    //Send a request to the peripheral via HTTP 
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(sourceURL); 
    WebResponse resp = req.GetResponse(); 

    //Get the image capture after recieving a request 
    //Note: just a screenshot not a steady stream 
    Stream stream = resp.GetResponseStream(); 
    while ((read = stream.Read(buffer, total, 1000)) != 0) 
    { 
     total += read; 
    }//While End 

    //Convert memory (byte) to bitmap and store in a picturebox  
    pictureBox1.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(buffer, 0, total)); 
}//getFrames End 

private void button1_Click(object sender, EventArgs e) 
{//Trigger an event to start running the function when possible 
    Application.Idle += new EventHandler(getFrames); 
}//Button1_Click End 
2

È possibile salvare più immagini in memoria (buffer) e quindi avviare l'elaborazione dal buffer.

Qualcosa di simile a questo:

//Convert stream to image then to bitmap 
Bitmap bmpImage = new Bitmap(System.Drawing.Image.FromStream(stream));      
//Convert to emgu image (desired goal) 
currentFrame = new Emgu.CV.Image<Bgr, Byte>(bmpImage); 

//gray scale for later use 
gray = currentFrame.Convert<Gray, Byte>(); 
SaveToBuffer(gray); 

Queue<Emgu.CV.Image<Gray, Byte>> buffer = new Queue<Emgu.CV.Image<Gray, Byte>>(); 
bool canProcess = false; 

// ... 

private void SaveToBuffer(Emgu.CV.Image<Gray, Byte> img) 
{ 
    buffer.Enqueue(img); 
    canProcess = buffer.Count > 100; 
} 

private void Process() 
{ 
    if(canProcess) 
    { 
     buffer.Dequeue(); 
     // Processing logic goes here... 
    } 
    else 
    { 
     // Buffer is still loading... 
    } 
} 

Ma si noti che è necessario abbastanza RAM per memorizzare le immagini nella memoria e inoltre si dovrebbe regolare la dimensione del buffer di carne vostre esigenze.

+0

Questa è una buona idea, cercherò i metodi di conversione della memoria. Ho alcune buone specifiche RAM quindi dovrei essere in grado di provare questo metodo. – Hughsie28

3

Hai un paio di colli di bottiglia potenziali, non ultimo dei quali è che probabilmente stai decodificando il flusso di jpeg in un'immagine e poi convertendola in una bitmap e poi in un'immagine openCV.

Uno dei modi per aggirare completamente l'imaging .NET. Ciò comporterebbe il tentativo di usare direttamente libjpeg. C'è un free port of it here in C#, e IIRC puoi collegarti ad esso per essere richiamato su una base per-scanline per riempire un buffer.

Lo svantaggio è che si stanno decodificando i dati JPEG nel codice gestito che verrà eseguito almeno 1,5 volte più lento del C equivalente, anche se francamente mi aspetterei che la velocità della rete ridurrebbe immensamente questo.

OpenCV dovrebbe essere in grado di leggere le immagini jpeg direttamente (voglio indovinare cosa usano sotto il cofano? Sondaggio dice: libjpeg), il che significa che è possibile bufferizzare l'intero flusso e consegnarlo a OpenCV e bypassare il livello .NET interamente.