2014-06-05 21 views
6

Ho una MVC applicazione in cui uno dei miei controllori riceve un file caricato (immagine) come oggetto HttpPostedFileBase.C#/EmguCV - Convertire un caricato HttpPostedFileBase ad un Emgu.CV.Mat

Sto cercando di elaborare l'immagine utilizzando EmguCV, ma sto avendo difficoltà a convertire il mio HttpPostedFileBase all'oggetto EmguCV matrice Emgu.CV.Mat (che è solo un C# implementazione di un oggetto cv::Mat).

C'è un costruttore per Mat che assomiglia:

public Mat(int rows, int cols, DepthType type, int channels, IntPtr data, int step); 

ma non sono sicuro di come ottenere il type, data e step dalla mia partenza HttpPostedFileBase oggetto. È possibile?

vedo here, che posso convertire un HttpPostedFileBase a un Image oggetto (credo che sia nel System.Drawing spazio dei nomi), che mi permette di vedere l'altezza e la larghezza. Ma come posso utilizzare queste informazioni per ottenere il resto dei parametri richiesti per inviare il costruttore Mat()?

+0

Hai fatto? O stai ancora provando? Hai bisogno di più aiuto su questo? –

risposta

5

In base alla specifica Emgu quei parametri significa:

/// <param name="type">Mat element type 

    /// <param name="channels">Number of channels 

    /// <param name="data"> 
    /// Pointer to the user data. Matrix constructors that take data and step parameters do not 
    /// allocate matrix data. Instead, they just initialize the matrix header that points to the 
    /// specified data, which means that no data is copied. This operation is very efficient and 
    /// can be used to process external data using OpenCV functions. The external data is not 
    /// automatically deallocated, so you should take care of it. 

    /// <param name="step"> 
    /// Number of bytes each matrix row occupies. 
    /// The value should include the padding bytes at the end of each row, if any. 
  • type è del tipo CvEnum.DepthType, che è la profondità dell'immagine, è possibile passare CvEnum.DepthType.Cv32F che sta per immagini di profondità a 32 bit , altri possibili valori sono nella forma CvEnum.DepthType.Cv{x}{t}, dove {x} è qualsiasi valore del set {8,16,32,64} e {t} può essere S per Single o F per Float.

  • channels, dipende dal tipo di immagine ma penso che sia possibile utilizzare 4 da ARGB.

Per gli altri 2 parametri, se non è necessario la parte di ottimizzazione, si può semplicemente utilizzare questo costruttore della classe Mat:

public Mat(int rows, int cols, DepthType type, int channels) 

Se davvero si vuole utilizzare la versione ottimizzata , poi (continua):

  • data, è possibile passare il Bitmap.GetHbitmap(), che restituisce un IntPtr ai dati utente.

  • step, per questo ragazzo, io ti do un'ipotesi informata, se per ogni pixel si dispone di 4 canali, e ciascun intervallo di canale da 0 a 255 (8 bit), 8*4 = 32, così per ogni larghezza di unità che si bisogno di 32 bit. Supponendo che sia corretto, ogni riga ha 32*width bit, convertendolo in byte ((8*4)*width)/8 = 4*width, che è il numero di canali, moltiplicato per la larghezza dell'immagine.

UPDATE

Altro modo per ottenere il data e step è da BitmapData di classe, come questo (estratto dalla risorsa MSDN):

Bitmap bmp = new Bitmap(Image.FromStream(httpPostedFileBase.InputStream, true, true)); 

// Lock the bitmap's bits. 
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 

System.Drawing.Imaging.BitmapData bmpData = 
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, 
     bmp.PixelFormat); 

// data = scan0 is a pointer to our memory block. 
IntPtr data = bmpData.Scan0; 

// step = stride = amount of bytes for a single line of the image 
int step = bmpData.Stride; 

// So you can try to get you Mat instance like this: 
Mat mat = new Mat(bmp.Height, bmp.Width, CvEnum.DepthType.Cv32F, 4, data, step); 

// Unlock the bits. 
bmp.UnlockBits(bmpData); 

non ho ancora testato questa soluzione, ma puoi provarlo. La mia risposta è stata basata sul codice Emguhere., Bitmap IntPtrhere e anche su questo post che mi aiuti acquisire anche una maggiore comprensione su questo.

ho visto altri modi per farlo anche, e se non si ha realmente bisogno di chiamare quel costruttore completo, vorrei provare questo approccio, sembra più pulito:

HttpPostedFileBase file //your file must be available is this context. 

if (file.ContentLength > 0) 
{ 
    string filename = Path.GetFileName(file.FileName); 

    // your so wanted Mat! 
    Mat img = imread(filename, CV_LOAD_IMAGE_COLOR); 
} 

NOTA

Ci sono ottimi tutorial nel OpenCV documentation. Basta dare un'occhiata alle esercitazioni disponibili per il modulo principale. In particolare, questo one.

+1

Ciao, come posso creare un tappetino da un'immagine ? Provare molti modi con EmguCV ma ognuno fallisce –

3

Penso che il modo più semplice per fare quello che vuoi è quello di creare un Bitmap da l'immagine che si ottiene seguendo il tuo link su come convertire un HttpPostedFileBase-Bitmap. La classe Bitmap ha un costruttore con un parametro Image. È quindi possibile creare un Emgu.CV.Image utilizzando questo Bitmap, di nuovo la classe Image può prendere un Bitmap nel costruttore. Lo svantaggio di questo metodo è che si otterrà un Image e non uno Mat.

Ora, è stato chiesto come creare un oggetto Mat e non sono sicuro di cosa si stia parlando perché non sono riuscito a trovare questa classe in EmguCV (2.4.9). Esiste una classe Matrix ma il suo costruttore non assomiglia a quello della tua domanda. Quindi, per darti maggiori informazioni sui parametri type, data e step, sappi che lo type dipende dalla proprietà PixelFormat dell'immagine. È un enum che può avere circa 20 valori diversi. Nel mio test l'immagine aveva un valore PixelFormat.Format24bppRgb, il che significa che si tratta di immagini a 3 canali in cui ogni canale è 8 bit, quindi in questo caso il tipo dovrebbe essere byte. Vorrei suggerire di seguire il link this su come ottenere la profondità di bit per un PixelFormat specificato.

Per il parametro dei dati, è necessario ottenere il BitmapData dal Bitmap e ottenere la proprietà Scan0 come viene spiegato here.

Per il parametro fase, sarà di nuovo necessario l'BitmapData ma questa volta è il parametro Stride che rappresenta il passo.