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

kdb*_*man 9 c# image-processing emgucv mat

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

Mat image = new Mat(8, 8, DepthType.Cv64F, 1);
Run Code Online (Sandbox Code Playgroud)

Image<>类提供用于获取和设置的像素值合理的手段,并且该方法是对相同的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);
Run Code Online (Sandbox Code Playgroud)

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

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

Bar*_*wal 13

您可以通过使用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];
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)

具有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);
    }
Run Code Online (Sandbox Code Playgroud)


Kor*_*ray 5

基于 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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 两者都是 OpenCV 包装器,如您所见并没有太大不同。当我需要了解某些知识时,我不仅仅寻找 OpenCvSharp 线程。EMGU、Cpp 甚至 Phton 的例子都给了我很大的帮助。我认为新问题会浪费时间。这是同样的问题,并且代码几乎相同。任何像我一样搜索的人都可能会利用它。另外,您关于动态的讨论值得一读,任何会使用它的人也应该阅读它们。谢谢。 (4认同)