shimat / opencvsharp

OpenCV wrapper for .NET
Apache License 2.0
5.41k stars 1.15k forks source link

Mat.AsSpan() doesn't get correct length #1698

Closed truebigsand closed 1 week ago

truebigsand commented 2 months ago

Summary of your issue

I'm currently working on converting Mat to Microsoft.ML.OnnxRuntime.Tensors.Tensor\<T>. To be efficient, I used mat.AsSpan() to manually access the data in a CV_8UC3 image. However, it always comes OutOfRange. Referring to the source code below: https://github.com/shimat/opencvsharp/blob/ca1f60877aff090de5e3e456c06c7827f33f364d/src/OpenCvSharp/Modules/core/Mat/Mat.cs#L4159-L4165 Maybe it should consider the size of T and gets the length like

public unsafe Span<T> AsSpan<T>() where T : unmanaged  
     => IsContinuous() ? new Span<T>(DataPointer, (int)Total() * ElemSize() / sizeof(T)) : []; 

Environment

What did you do when you faced the problem?

Accessing from mat.DataPointer directly just works.

Example code:

Output:

What did you intend to be?

GuaiGuaiOnMyComputer commented 1 month ago

Having the same issue. Here's a minimal reproducible example using 3-channel Mats. The length of the returned Span is only Width x Height instead of 3 x Width x Height.

    static void ReproduceIndexOutOfRange()
    {
        // Read a jpeg image of format 3-channel 10x20 pixels
        Mat testImage8u = new(10, 20, MatType.CV_8UC3);
        Span<byte> testImageData = testImage8u.AsSpan<byte>();

        for (int i = 0; i < testImage8u.Channels() * testImage8u.Rows * testImage8u.Cols; i++)
            testImageData[i] = 255; // IndexOutOfRangeException at i = 200

        Cv2.ImShow("testImage8u", testImage8u);
        Cv2.WaitKey(0);
    }

But it's not like the span points to a single channel of the image. If I set the bound of the loop to testImage8u.Rows * testImage8u.Cols instead of three times of that to avoid IndexOutOfRangeException like so:

    static void ReproduceIndexOutOfRange()
    {
        // Read a jpeg image of format 3-channel 10x20 pixels
        Mat testImage8u = new(10, 20, MatType.CV_8UC3);
        Span<byte> testImageData = testImage8u.AsSpan<byte>();

        for (int i = 0; i < testImage8u.Rows * testImage8u.Cols; i++)
            testImageData[i] = 255; 

        Cv2.ImShow("testImage8u", testImage8u);
        Cv2.WaitKey(0);
    }

The resulting image looks like this testImage8u_screenshot_12 09 2024

OpenCvSharp version: 4.9.0.20240103 Os: Linux .NET version: 8.0.108