Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何获取和设置EmguCV Mat图像的像素值?_C#_Image Processing_Mat_Emgucv - Fatal编程技术网

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

C# 如何获取和设置EmguCV Mat图像的像素值?,c#,image-processing,mat,emgucv,C#,Image Processing,Mat,Emgucv,我正在使用EmguCV 3.0.0包装器来访问OpenCV 3.0库。我在一些地方使用Mat类。以下是一个由双值构成的单通道8x8图像示例: Mat image = new Mat(8, 8, DepthType.Cv64F, 1); 该类提供了,并且该方法对于该类是相同的,但对于该类来说似乎不那么明显。我知道如何设置单个像素的唯一方法是使用遮罩: // set two pixel values, (0,0) to 9.0, (2, 3) to 42.0 Matrix<byte>

我正在使用EmguCV 3.0.0包装器来访问OpenCV 3.0库。我在一些地方使用
Mat
类。以下是一个由
双值构成的单通道8x8图像示例:

Mat image = new Mat(8, 8, DepthType.Cv64F, 1);
该类提供了,并且该方法对于该类是相同的,但对于该类来说似乎不那么明显。我知道如何设置单个像素的唯一方法是使用遮罩:

// 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);
//将两个像素值(0,0)设置为9.0,(2,3)设置为42.0
矩阵掩码=新矩阵(8,8);
掩码数据[0,0]=1;
image.SetTo(新的MCvScalar(9.0),掩码);
掩模=新矩阵(8,8);
掩码数据[2,3]=1;
image.SetTo(新的MCvScalar(42.0),掩码);
这感觉应该是两行,而不是六行,所以我觉得我遗漏了什么。当
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);
对20000000次操作的测试表明,动态类型版本比静态版本慢约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();
        }
    }
此解决方案适用于用户要求的三种颜色通道:


起初,很好的回答对我帮助很大。但我不明白这种方法如何处理多个通道。在您的示例中,您编写了var mat=new mat(3,3,DepthType.Cv64F,3);它是否应该返回一个大小为3的双[]值,每个通道包含一个值19年11月18日22:30在Quergo


图像[0,0]=9;应该这样做,这也是我所期望的。但它不起作用。这里有一个错误:“无法将带[]的索引应用于'Emgu.CV.Mat'类型的表达式”使用
dynamic
,看起来非常好用!我唯一的问题是
动态
可能比静态类型的备选方案慢10到100倍。(请参阅和。)您的扩展方法应该处于该频谱的快速端,因为
动态
接收类型很少会改变。即使如此,优化的
Get/SetValue()
方法也应该可以安全返回/接收
double
,因为有一个从任何Emgu支持的
DepthType
double
,谢谢!我没想到。如果EmguCV的维护人员不能更好地支持这一点,我将很快包括一个像您这样的扩展方法。Bartosz,很好的答案。只有一件事,而不是(row*mat.Cols+col)*mat ElementSize,我会使用((row*mat.Step)+(col*mat.ElementSize)),因为row Step可能不等于row*mat.ColumnsAt首先,很好的答案,对我帮助很大。但我不明白这种方法如何处理多个通道。在您的示例中,您编写了
var mat=new mat(3,3,DepthType.Cv64F,3)它不应该返回一个大小为3的双[]值,每个通道包含一个值吗?谢谢你的努力,但我认为这不属于这里。OpenCvSharp是一个与我所问的完全不同的库。如果OpenCV夏普上没有一个现有的问题,你可以把它移到,考虑问和回答你自己的问题。两个都是OpenCV包装器,不像你看到的那么大。当我需要某方面的知识时,我不会只寻找OpenCvSharp线程。EMGU、Cpp甚至Phton的例子都给了我很大的帮助。我认为一个新问题是浪费时间。这是相同的问题,几乎是相同的代码。任何像我这样搜索的人都可以利用它。另外,您关于dynamic的讨论也是一本好书,任何使用它的人都应该阅读。谢谢。使用OpenCvSharp,您可以使用
Mat::Set(x,y,val)
方法将
(x,y)
处的元素设置为
val
的值。在Emgu包装中没有这样的访问器。你只是为同一个问题链接了另一个答案吗?我们赞赏扩展的解决方案,但有3个颜色通道对原始问题并不重要。引用另一个答案:“起初,不错的答案,对我帮助很大。但我不明白这种方法如何处理多个通道。在您的示例中,您编写了var mat=new mat(3,3,DepthType.Cv64F,3);它不应该返回一个双[]大小为3,每个频道都有一个值?–Quergo 11月18日19日22:30“所以肯定有人对3个彩色频道感兴趣,而最上面的答案中有一个三色图像,这在本例中是错误的。您好,英语3LS,从您的回答中不清楚您是在回答另一个用户的评论。我建议更新您的答案来解释这一点。注意:对某个内容投票的用户在第二天不能更改投票,除非该帖子被编辑。我编辑了我的解决方案,提到我正在处理另一个用户的评论。因为我没有足够的声誉来评论顶级解决方案,你能在那里写一篇评论吗,Quergo的问题已经得到了回答。。。它已经2年了,所以我认为这并不重要,但你永远不知道。然而,用户PeterBence去年也提出了同样的问题。
public static class MatExtension
{
    public static dynamic GetValues(this Mat mat, int row, int col)
    {
        var value = CreateElement3Channels(mat.Depth);
        Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 3);
        return value;
    }

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

    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 SetValues(this Mat mat, int row, int col, dynamic value)
    {
        Marshal.Copy(value, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 3);
    }

    public static void SetValue(this Mat mat, int channel, int row, int col, dynamic value)
    {
        var element = GetValues(mat, row, col);
        var target = CreateElement(element, value, channel);
        Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 3);
    }

    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(dynamic element, dynamic value, int channel)
    {
        element[channel] = value;
        return element;
    }

    private static dynamic CreateElement(DepthType depthType, dynamic value)
    {
        var element = CreateElement(depthType);
        element[0] = value;
        return element;
    }

    private static dynamic CreateElement3Channels(DepthType depthType)
    {
        if (depthType == DepthType.Cv8S)
        {
            return new sbyte[3];
        }

        if (depthType == DepthType.Cv8U)
        {
            return new byte[3];
        }

        if (depthType == DepthType.Cv16S)
        {
            return new short[3];
        }

        if (depthType == DepthType.Cv16U)
        {
            return new ushort[3];
        }

        if (depthType == DepthType.Cv32S)
        {
            return new int[3];
        }

        if (depthType == DepthType.Cv32F)
        {
            return new float[3];
        }

        if (depthType == DepthType.Cv64F)
        {
            return new double[3];
        }

        return new float[3];
    }

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