Переписывание OpenCV C ++ на EmguCV C# - как работать с указателями? - PullRequest
1 голос
/ 14 июля 2020

Я пытаюсь преобразовать код C ++, написанный OpenCV 2.x, в Emgu.CV в C#.

У меня есть функция на 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. Есть ли способ лучше / эффективнее?

Ответы [ 2 ]

1 голос
/ 22 июля 2020

Вы можете попробовать преобразовать inMat в массив inM, затем вычислить нужные вам значения в другом массиве Or и, наконец, преобразовать последний массив в выходной Mat outMat.

Примечание: Я считал 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;
}
0 голосов
/ 14 июля 2020

Вот код сохранения, чтобы сделать эквивалент. Не тестировал. Я проверил библиотеку OpenCV, чтобы получить структуру Mat. Реальная структура в OpenCV имеет указатель на данные. Вместо этого я сделал массив байтов. Итак, если вы загружали / писали структуру OpenCV, вам понадобится интерфейс для преобразования. Выходная матрица в восемь раз больше входной, поскольку входные данные представляют собой массив байтов, а выходные данные - массивы типа double.

Код был бы лучше, если бы были входные байты [] [] и выходные двойные [] [ ].

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