【问题标题】:Rewriting OpenCV C++ to EmguCV C# - how to work with pointers?将 OpenCV C++ 重写为 EmguCV C# - 如何使用指针?
【发布时间】:2020-11-03 23:53:04
【问题描述】:

我正在尝试将 OpenCV 2.x 编写的 C++ 代码转换为 C# 中的 Emgu.CV。

我有一个 C++ 函数:

cv::Mat computeMatXGradient(const cv::Mat &mat) {
    cv::Mat out(mat.rows, mat.cols, CV_64F);
    for (int y = 0; y < mat.rows; ++y) {
        const uchar* Mr = mat.ptr<uchar>(y);
        double* Or = out.ptr<double>(y);
        Or[0] = Mr[1] - Mr[0];
        for (int x = 1; x < mat.cols - 1; ++x) {
            Or[x] = (Mr[x + 1] - Mr[x - 1]) / 2.0;
        }
        Or[mat.cols - 1] = Mr[mat.cols - 1] - Mr[mat.cols - 2];
    }
    return out;
}

如何在 C# 中使用 EmguCV 高效地做同样的事情?

到目前为止 - 我有这个 C# 代码: (我无法测试它,因为缺少很多代码)

Mat computeMatXGradient(Mat inMat)
{
    Mat outMat = new Mat(inMat.Rows, inMat.Cols, DepthType.Cv64F, inMat.NumberOfChannels);
    for (int y = 0; y < inMat.Rows; ++y)
    {
        // unsafe is required if I'm using pointers
        unsafe {
            byte* Mr = (byte*) inMat.DataPointer;
            double* Or = (double*) outMat.DataPointer;
            Or[0] = Mr[1] - Mr[0];
            for (int x = 1; x < inMat.Cols - 1; ++x)
            {
               Or[x] = (Mr[x + 1] - Mr[x - 1]) / 2.0;
            }
            Or[inMat.Cols - 1] = Mr[inMat.Cols - 1] - Mr[inMat.Cols - 2];
        }
    }
    return outMat;
}

问题:

  1. 我的 C# 代码正确吗?

  2. 有没有更好/更有效的方法?

【问题讨论】:

    标签: c# c++ opencv emgucv


    【解决方案1】:

    这里是保存代码来做等效。没有测试。我检查了 OpenCV 库以获取 Mat 的结构。 OpenCV 中的真实结构有一个指向数据的指针。相反,我制作了一个字节数组。因此,如果您正在加载/编写 OpenCV 结构,则需要一个接口进行转换。输出矩阵是输入的八倍,因为输入是字节数组,输出是双精度数组。

    如果有输入字节[][]和输出双精度[][],代码会更好。

    public class Mat
    {
        public int flags;
        //! the array dimensionality, >= 2
        public int dims;
        //! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions
        public int rows;
        public int cols;
        //! pointer to the data
        public byte[] data;
        //! pointer to the reference counter;
        // when array points to user-allocated data, the pointer is NULL
        public Mat[] refcount;
        // other members
        public Mat computeMatXGradient(Mat inMat)
        {
            Mat outMat = new Mat();
            outMat.rows = inMat.rows;
            outMat.cols = inMat.cols;
            outMat.flags = inMat.flags;  //include depthType and NumberofChannels
            outMat.dims = inMat.dims;
            outMat.data = new byte[inMat.rows * inMat.cols * sizeof(Double)];
            int outIndex = 0;
            byte[] d = new byte[sizeof(double)];
            for (int y = 0; y < inMat.rows; ++y)
            {
                int inRowIndex = y * inMat.cols;
                d = BitConverter.GetBytes((double)(inMat.data[inRowIndex + 1] - inMat.data[inRowIndex]));
                Array.Copy(d, 0, outMat.data, outIndex, sizeof(double));
                outIndex += sizeof(double);
                for (int x = 1; x < inMat.cols - 1; ++x)
                {
                    d = BitConverter.GetBytes((double)(inMat.data[inRowIndex + x + 1] - inMat.data[inRowIndex + x - 1]) / 2.0);
                    Array.Copy(d, 0, outMat.data, outIndex,sizeof(double));
                    outIndex += sizeof(double);
                }
                d = BitConverter.GetBytes((double)(inMat.data[inRowIndex + inMat.cols - 1] - inMat.data[inRowIndex - inMat.cols - 2]));
                Array.Copy(d, 0, outMat.data, outIndex, sizeof(double));
            }
            return outMat;
        }
    }
    

    【讨论】:

    • 它不起作用有几个原因。您不能分配 outMat.data,因为它是只读的。
    • 您有什么要求?具有与原代码相同的界面和功能;还是具有相同的功能? OpenCV 有一个通用的矩阵结构。如果您在 c# 中实现,是否需要通用结构?我对可以修改的原始代码进行了两项更改 1)创建了一个类而不是结构 2)更改为指向数组的数据的指针以避免内存泄漏。我可以将数据更改为 IntPtr,然后为数据分配内存以与 CV 相同。但是分配内存会导致内存泄漏。
    • 我的老师和同事总是说代码应该有边距,以便于阅读并在调试时添加注释。删除空间肯定不会使它看起来更好。只是更难阅读。
    • 不需要定义自己的 Mat 类型,因为 EmguCV(c# opencv wrapper)已经提供了这种类型。此解决方案将不兼容。请检查标签。
    【解决方案2】:

    您可以尝试将inMat转换为数组inM,然后在另一个数组Or中计算您需要的值,最后将后一个数组转换为输出MatoutMat

    注意:我认为 NumberOfChannels 为 1,因为我认为这将永远是这种情况。

    Mat computeMatXGradient(Mat inMat)
    {
        int x, y;
        byte[] inM, Mr;
        double[] Or;
        inM = new byte[(int)inMat.Total];
        inMat.CopyTo(inM);
        Mr = new byte[inMat.Cols];
        Or = new double[inMat.Rows * inMat.Cols];
        for (y = 0; y < inMat.Rows; y++)
        {
            Array.Copy(inM, y * inMat.Cols, Mr, 0, inMat.Cols);
            Or[y * inMat.Cols] = Mr[1] - Mr[0];
            for (x = 1; x < inMat.Cols - 1; x++)
               Or[y * inMat.Cols + x] = (Mr[x + 1] - Mr[x - 1]) / 2.0;
            Or[y * inMat.Cols + inMat.Cols - 1] = Mr[inMat.Cols - 1] - Mr[inMat.Cols - 2];
        }
        Mat outMat = new Mat(inMat.Rows, inMat.Cols, DepthType.Cv64F, 1);
        Marshal.Copy(Or, 0, outMat.DataPointer, inMat.Rows * inMat.Cols);
        return outMat;
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2020-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多