-1

I'd like to return a Mat object to Unity from c++ code. However i get access violation error at c++ part like that

Unity Editor [version: Unity 2017.3.0f3_a9f86dcd79df]

SaliencyCV.dll caused an Access Violation (0xc0000005)
in module SaliencyCV.dll at 0033:270027f0.

Error occurred at 2018-03-06_235212.
C:\Program Files\Unity\Editor\Unity.exe, run by Dilara.
43% memory in use.
16266 MB physical memory [9199 MB free].
18698 MB paging file [9861 MB free].
134217728 MB user address space [134185466 MB free].
Read from location 990d0000 caused an access violation.

Here is c++ code:

uchar* cppMethod(uchar* frameData, int WIDTH, int HEIGHT, int* rows, int* cols)
{
    Mat img(HEIGHT, WIDTH, CV_8UC3);
    img.data = frameData;

    flip(img, img, 0);

    Mat result = calculateSaliency(img);

    *rows = result.rows;
    *cols = result.cols;

    int length = result.rows * result.cols * 3;

    uchar* tmpArr = result.data;

    uchar* resultArray = new uchar[length];

    for (int i = 0; i < length; i++)
    {
        resultArray[i] = tmpArr[i]; 
    }

    return resultArray;
}

Can someone help me?

Arda Aytekin
  • 1,231
  • 14
  • 24
Dilara Albayrak
  • 314
  • 1
  • 3
  • 23

1 Answers1

2

You should call the correct Mat constructor, which accepts external data pointer, to make the object not release/destruct the corresponding memory location data points to. You can read about this behaviour in Mat::release().

The problem with your code is that

  1. Mat img(HEIGHT, WIDTH, CV_8UC3) allocates a memory block of type CV_8UC3 of size HEIGHT*WIDTH, which is not used (because you are changing the data member variable to point to a different memory location, anyways),
  2. At function exit, img is destructed, which results in a call to release(), which in turn destructs frameData, which is not the intended behaviour.

Change your first two lines to read

Mat img(HEIGHT, WIDTH, CV_8UC3, frameData);

And if you are passing resultArray to C#, where you are most likely not managing the pointed-to-memory's lifetime, you would be most likely having memory leaks. @Programmer has already suggested in his answer to your previous question that you should allocate the memory in C#, pass it to C++, and write in-place in the C++ side.

In short, you should have something like:

#include <algorithm>

void cppMethod(uchar *frameData, uchar *out, const int WIDTH, const int HEIGHT,
               int *rows, int *cols) {
  /* this constructor will not manage frameData's lifetime */
  Mat img(HEIGHT, WIDTH, CV_8UC3, frameData);

  /* in-place operation */
  flip(img, img, 0);

  /* local variable --- it will be destructed properly */
  Mat result = calculateSaliency(img);

  /* well-defined if rows and cols are scalars passed by reference */
  *rows = result.rows;
  *cols = result.cols;

  /* make sure length will not overflow */
  int length = result.rows * result.cols * 3;

  /* you don't need this */
  // uchar *tmpArr = result.data;

  /* you sholuld NOT do this */
  // uchar *resultArray = new uchar[length];

  // use std::copy from <algorithm>
  // for (int i = 0; i < length; i++) {
  //   resultArray[i] = tmpArr[i];
  // }

  std::copy(result.data, result.data + length, out);

  // return resultArray;
}
Arda Aytekin
  • 1,231
  • 14
  • 24
  • You're welcome! But make sure you do the in-place version, in that you pre-allocate memory in C# and pass it to C++ to be modified directly. Otherwise, you are leaking memory in each frame when you call `cppMethod`. This is a more serious problem itself than fixing the constructor bug in your code. – Arda Aytekin Mar 06 '18 at 23:16
  • I think that OP will still do it her way due to OP's last few questions. @DilaraAlbayrak If you still want to do it this way then write a function to de-allocate the allocated `resultArray` variable like [here](https://stackoverflow.com/questions/49140381/pass-mat-object-c-to-unity#49141288). If you don't do this now, you will end up with many issues as Arda has warned you. – Programmer Mar 06 '18 at 23:24
  • 1
    @Programmer, I think you have given the wrong link in your comment, or? I did not want to share my suggestion first, as I have already read your detailed response to her previous question, but I couldn't help --- that leak is nasty. – Arda Aytekin Mar 06 '18 at 23:29
  • 2
    Lol I don't even know how this happened. [This](https://stackoverflow.com/questions/43630063/passing-byte-array-from-c-unmanaged-dll-to-c-sharp-unity/43632320#43632320) link I meant. – Programmer Mar 06 '18 at 23:34