How can I get and set pixel values of an EmguCV Mat image?

前端 未结 2 1705
感动是毒
感动是毒 2020-12-06 17:45

I\'m using the EmguCV 3.0.0 wrapper to the OpenCV 3.0 library. I\'m using the Mat class in a few places. Here\'s an example of a single channel, 8x8 image mad

相关标签:
2条回答
  • 2020-12-06 17:46

    You can get elements from Mat by copying unmanaged memory blocks using DataPointer and converting managed to unmanaged types. Setting values is marshaling in the opposite direction.

    For an example you can use such an extension class

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

    Then getting and setting value is possible by single method call

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

    Tests with 200000000 operations shows that dynamic type version can be up to ~2.5x slower than static.

        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 讨论(0)
  • 2020-12-06 17:52

    Based on the Bartosz Rachwal's great answer, I've tried to write it for 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();
            }
        }
    
    0 讨论(0)
提交回复
热议问题