2015-08-27 36 views
8

Sto utilizzando il wrapper EmguCV 3.0.0 alla libreria OpenCV 3.0. Sto utilizzando la classe Mat in alcuni punti. Ecco un esempio di un singolo canale, immagine 8x8 realizzato double valori:Come posso ottenere e impostare i valori dei pixel di un'immagine EmguCV Mat?

Mat image = new Mat(8, 8, DepthType.Cv64F, 1); 

La classe Image<> fornisce reasonable means for getting and setting pixel values, e il metodo è identico per la classe Matrix<>, ma non sembra così evidente per la classe Mat . L'unico modo che ho capito come impostare singolo pixel sta usando una maschera:

// set two pixel values, (0,0) to 9.0, (2, 3) to 42.0 

Matrix<byte> mask = new Matrix<byte>(8,8); 
mask.Data[0, 0] = 1; 
image.SetTo(new MCvScalar(9.0), mask); 

mask = new Matrix<byte>(8,8); 
mask.Data[2, 3] = 1; 
image.SetTo(new MCvScalar(42.0), mask); 

Questo è sente come dovrebbe essere due linee, non sei, così mi sento come mi manca qualcosa. Le cose si complicano ulteriormente quando lo Mat è più di un canale, perché Matrix<> è solo 2D, quindi la maschera deve essere utilizzata per impostare il pixel su ciascun canale.

Non posso permettermi il tempo o la memoria per impostare i pixel in questo modo. Come posso impostare i pixel con una singola chiamata di metodo?

+0

immagine [0,0] = 9; dovrebbe farlo – Miki

+0

Questo è quello che mi aspettavo pure. Ma non funziona. Ecco l'errore: * "Impossibile applicare l'indicizzazione con [] a un'espressione di tipo 'Emgu.CV.Mat'" * – kdbanman

risposta

9

È possibile ottenere elementi da Mat copiando blocchi di memoria non gestiti utilizzando DataPointer e convertendo i tipi gestiti in non gestiti. L'impostazione dei valori è il marshalling nella direzione opposta.

Ad esempio è possibile utilizzare tale classe di estensione

public static class MatExtension 
{ 
    public static dynamic GetValue(this Mat mat, int row, int col) 
    { 
     var value = CreateElement(mat.Depth); 
     Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 1); 
     return value[0]; 
    } 

    public static void SetValue(this Mat mat, int row, int col, dynamic value) 
    { 
     var target = CreateElement(mat.Depth, value); 
     Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 1); 
    } 
    private static dynamic CreateElement(DepthType depthType, dynamic value) 
    { 
     var element = CreateElement(depthType); 
     element[0] = value; 
     return element; 
    } 

    private static dynamic CreateElement(DepthType depthType) 
    { 
     if (depthType == DepthType.Cv8S) 
     { 
      return new sbyte[1]; 
     } 
     if (depthType == DepthType.Cv8U) 
     { 
      return new byte[1]; 
     } 
     if (depthType == DepthType.Cv16S) 
     { 
      return new short[1]; 
     } 
     if (depthType == DepthType.Cv16U) 
     { 
      return new ushort[1]; 
     } 
     if (depthType == DepthType.Cv32S) 
     { 
      return new int[1]; 
     } 
     if (depthType == DepthType.Cv32F) 
     { 
      return new float[1]; 
     } 
     if (depthType == DepthType.Cv64F) 
     { 
      return new double[1]; 
     } 
     return new float[1]; 
    } 
} 

Poi sempre e valore di impostazione è possibile per singola chiamata di metodo

var row = 2; 
var col = 1; 
var mat = new Mat(3, 3, DepthType.Cv64F, 3); 
mat.SetValue(row, col, 3.14); 
var value = mat.GetValue(row, col); 

Prove con 200.000.000 operazioni mostra che versione tipo dinamico può essere fino a ~ 2,5 volte più lento di statico.

public static double GetDoubleValue(this Mat mat, int row, int col) 
    { 
     var value = new double[1]; 
     Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 1); 
     return value[0]; 
    } 

    public static void SetDoubleValue(this Mat mat, int row, int col, double value) 
    { 
     var target = new[] { value }; 
     Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 1); 
    } 
+0

Uso interessante di 'dynamic', che sembra * molto * bello da usare! Il mio unico problema è che 'dynamic' può essere da ~ 10x a ~ 100x più lento rispetto alle alternative tipizzate staticamente. (vedere [qui] (http://stackoverflow.com/a/7478557/3367144) e [qui] (http://stackoverflow.com/a/13193865/3367144). I metodi di estensione dovrebbero essere sulla parte veloce di quello spettro perché il tipo di ricezione 'dinamico' cambierà raramente. – kdbanman

+0

Anche così, i metodi ottimizzati 'Get/SetValue()' che restituiscono/ricevono in modo sicuro 'double' dovrebbero essere possibili, perché c'è una [conversione automatica sicura] (https://msdn.microsoft.com/en-us/library/ y5b434w4.aspx? f = 255 & MSPPError = -2147217396) da qualsiasi Emgu supportato 'DepthType' a' double'. – kdbanman

+0

Grazie! Non me l'aspettavo. Se il manutentore di EmguCV non riesce a supportarlo meglio, includerò presto un metodo di estensione come il tuo. – kdbanman

1

Basato sul grande risposta del Bartosz Rachwal, ho provato a scrivere per OpenCvSharp:

public static dynamic GetValue(this Mat mat, int row, int col) 
    { 
     var value = CreateElement(mat.Type()); 
     Marshal.Copy(mat.Data + (row * mat.Cols + col) * mat.ElemSize(), value, 0, 1); 
     return value[0]; 
    } 
    public static void SetValue(this Mat mat, int row, int col, dynamic value) 
    { 
     var target = CreateElement(mat.Type(), value); 
     Marshal.Copy(target, 0, mat.Data + (row * mat.Cols + col) * mat.ElemSize(), 1); 
    } 
    private static dynamic CreateElement(MatType depthType, dynamic value) 
    { 
     var element = CreateElement(depthType); 
     element[0] = value; 
     return element; 
    } 
    private static dynamic CreateElement(MatType depthType) 
    { 
     switch (depthType) 
     { 
      case MatType.CV_8S: 
       return new sbyte[1]; 
      case MatType.CV_8U: 
       return new byte[1]; 
      case MatType.CV_16S: 
       return new short[1]; 
      case MatType.CV_16U: 
       return new ushort[1]; 
      case MatType.CV_32S: 
       return new int[1]; 
      case MatType.CV_32F: 
       return new float[1]; 
      case MatType.CV_64F: 
       return new double[1]; 
      default: 
       throw new NotImplementedException(); 
     } 
    } 
+1

Grazie per lo sforzo, ma non penso che questo appartiene a questo. OpenCvSharp è una libreria completamente diversa da quella che sto chiedendo. Se non esiste una domanda esistente su OpenCvSharp su cui puoi spostarla, valuta la possibilità di chiedere e rispondere alla tua stessa domanda. – kdbanman

+2

Entrambi sono wrapper OpenCV, non molto diversi come si vede. Quando richiedo una conoscenza di qualcosa, non cerco solo i thread OpenCvSharp. EMGU, Cpp anche gli esempi di Phton mi danno un grande aiuto. Una nuova domanda sarebbe una perdita di tempo, penso.Questo è lo stesso problema e quasi lo stesso codice. Qualcuno alla ricerca come me potrebbe farne uso. Anche le tue discussioni sulla dinamica sono una buona lettura, chiunque dovrebbe usarle dovrebbe leggerle. Grazie. – Koray