2015-08-27 1285 views
8

我正在使用EmguCV 3.0.0包装到OpenCV 3.0库。我在几个地方使用Mat课程。这里的一个单个信道的一个例子,8×8图像制成double值:如何获取并设置EmguCV Mat图像的像素值?

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

Image<>类提供reasonable means for getting and setting pixel values,并且该方法是用于Matrix<>类是相同的,但是它似乎没有对Mat类那样明显。我已经想通了如何设置单个像素的唯一方法是使用面膜:

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

这是感觉像它应该是两条线,不是6,所以我觉得我失去了一些东西。当Mat多于一个通道时,事情变得更加复杂,因为Matrix<>只是2D,因此必须使用掩码设置每个通道上的像素。

我无法承担这样设置像素的时间或内存。 如何使用单个方法调用设置像素?

+0

图像[0,0] = 9;应该这样做 – Miki

+0

这也是我的预期。但它不起作用。这里是错误:*“不能用[]对'Emgu.CV.Mat'类型的表达式应用索引'”* – kdbanman

回答

9

您可以通过使用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); 

试验用2亿个操作示出了动态型版本可以比静态速度慢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); 
    } 
+0

有趣的使用'动态',看起来*很好用!我唯一的问题是'dynamic'可能比静态类型的替代品慢10倍〜100倍。 (请参阅[这里](http://stackoverflow.com/a/7478557/3367144)和[这里](http://stackoverflow.com/a/13193865/3367144)。)你的扩展方法应该在快速结束因为'动态'接收类型很少会改变。 – kdbanman

+0

尽管如此,应该可以安全地返回/接收'double',因为有一个[安全自动转换](https://msdn.microsoft.com/en-us/library/),因此优化的'Get/SetValue y5b434w4.aspx?f = 255&MSPPError = -2147217396)从任何Emgu支持的'DepthType'转换为'double'。 – kdbanman

+0

谢谢!我并不期待这一点。如果EmguCV维护人员没有得到更好的支持,我会很快包含一个像你一样的扩展方法。 – kdbanman

1

基础上巴尔托什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(); 
     } 
    } 
+1

谢谢你的努力,但我不认为这属于这里。 OpenCvSharp是一个完全不同的库,而不是我所问的。如果在OpenCvSharp上没有可以移动的问题,请考虑询问并回答您自己的问题。 – kdbanman

+2

两者都是OpenCV封装,与您看到的并不完全不同。当我需要关于某些东西的知识时,我不仅查找OpenCvSharp线程。 EMGU,Cpp甚至Phton的例子都给了我很大的帮助。一个新问题会浪费我想的时间。这是同样的问题,并且代码几乎相同。任何像我这样搜索的人都可以使用它。此外,你对动态的讨论是一个很好的阅读,任何会使用它的人也应该阅读它们。谢谢。 – Koray