如何获取和设置EmguCV Mat图像的像素值?

我正在使用EmguCV 3.0.0包装器来访问OpenCV 3.0库。 我在几个地方使用Mat类。 以下是单个通道的示例,8×8图像由double值组成:

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

Image类提供了获取和设置像素值的合理方法 ,并且该方法对于Matrix类是相同的,但对于Mat类来说它似乎并不明显。 我弄清楚如何设置单个像素的唯一方法是使用掩码:

 // set two pixel values, (0,0) to 9.0, (2, 3) to 42.0 Matrix mask = new Matrix(8,8); mask.Data[0, 0] = 1; image.SetTo(new MCvScalar(9.0), mask); mask = new Matrix(8,8); mask.Data[2, 3] = 1; image.SetTo(new MCvScalar(42.0), mask); 

感觉它应该是两行,而不是六行,所以我觉得我错过了一些东西。 当Mat不止一个通道时,事情变得更加复杂,因为Matrix只是2D,因此必须使用掩码来设置每个通道上的像素。

我无法承受以这种方式设置像素的时间或内存。 如何通过单个方法调用设置像素?

您可以通过使用DataPointer复制非托管内存块并将托管转换为非托管类型来从Mat获取元素。 设定值是相反方向的编组。

例如,您可以使用此类扩展类

 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]; } } 

然后通过单个方法调用获得并设置值

 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); 

具有200000000次操作的测试表明,动态类型版本可以比静态版本慢〜2.5倍。

  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); } 

基于Bartosz Rachwal的出色答案,我试图为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(); } }