1
1
// C++ headers
2
2
#include " opencv2/core.hpp"
3
+ #include " opencv2/imgcodecs.hpp"
3
4
#include " convert.h"
4
5
#include " numpy.h"
5
6
@@ -11,46 +12,46 @@ extern "C" {
11
12
12
13
using namespace cv ;
13
14
14
- // Fix for https://github.com/sparkfun/micropython-opencv/issues/13
15
+ // The function below is a workaround for memory management issues between
16
+ // OpenCV and the MicroPython GC. OpenCV allocates some objects on the heap,
17
+ // whenever the first function that needs the objects happen to be called. That
18
+ // only happens from the user's code after the GC has been initialized, meaning
19
+ // they get allocated on the GC heap (see `__wrap_malloc()`). If a soft reset
20
+ // occurs, the GC gets reset and the memory locations get overwritten, but the
21
+ // same memory locations are still referenced for the objects, resulting in bad
22
+ // values and problems (crashes and freezes, `CV_Assert()` calls fail, etc.).
15
23
//
16
- // TLDR; The CoreTLSData object gets allocated once, whenever the first OpenCV
17
- // function that needs it happens to be called. That will only happen from the
18
- // user's code, after the GC has been initialized, meaning it gets allocated on
19
- // the GC heap (see `__wrap_malloc()`). If a soft reset occurs, the GC gets
20
- // reset and overwrites the memory location, but the same memory location is
21
- // still referenced for the CoreTLSData object, resulting in bogus values and
22
- // subsequent `CV_Assert()` calls fail
24
+ // The solution here is to ensure those objects are allocated in the C heap
25
+ // instead of the GC heap. The function below calls various OpenCV functions
26
+ // that subsequently allocate the problematic objects. To ensure they are
27
+ // allocated on the C heap, this needs to happen before the GC is initialized
28
+ // (before `main()` is called), so __wrap_malloc() will use __real_malloc()
29
+ // instead of the GC.
23
30
//
24
- // The solution here is to create a global variable that subsequently calls
25
- // `getCoreTlsData()` to allocate the CoreTLSData object before the GC has
26
- // been initialized, so it gets allocated on the C heap and persists through
27
- // soft resets. `getCoreTlsData()` is not publicly exposed, but `theRNG()` is
28
- // exposed, which just runs `return getCoreTlsData().rng`
29
- volatile RNG rng = theRNG();
30
-
31
- // Fix for https://github.com/sparkfun/micropython-opencv/issues/17
32
- //
33
- // TLDR; The `StdMatAllocator` gets allocated once, whenever the first time a
34
- // Mat object is created without the NumpyAllocator being set (OpenCV creates
35
- // internal Mat objects for various operations that use whatever the default
36
- // allocator is). Similar to above, the `StdMatAllocator` gets allocated on the
37
- // GC heap, so if a soft reset occurs, the GC gets reset and overwrites the
38
- // memory location, causing problems
39
- //
40
- // Instead of ensuring the `StdMatAllocator` is allocated on the C heap, we just
41
- // set the NumpyAllocator as the default allocator. `Mat::setDefaultAllocator()`
42
- // does not return anything, so this wrapper function returns a dummy value so
43
- // we can use it to initialize a global variable, ensuring it gets run before
44
- // `main()` gets called
45
- bool setNumpyAllocator () {
31
+ // The function below returns a dummy value that we use to initialize a global
32
+ // variable, ensuring it gets run before `main()` gets called. This also means
33
+ // it can be used as a general boot function for anything else that needs to
34
+ // happen before `main()` is called, such as setting the default Mat allocator.
35
+ bool upyOpenCVBoot () {
46
36
try {
37
+ // Initializes `CoreTLSData` on the C heap, see:
38
+ // https://github.com/sparkfun/micropython-opencv/issues/13
39
+ theRNG ();
40
+
41
+ // Initializes all image codecs on the C heap, see:
42
+ // https://github.com/sparkfun/micropython-opencv/issues/17
43
+ haveImageWriter (" .bmp" );
44
+
45
+ // Sets the NumpyAllocator as the default Mat object allocator, see
46
+ // https://github.com/sparkfun/micropython-opencv/issues/17
47
47
Mat::setDefaultAllocator (&GetNumpyAllocator ());
48
+
48
49
return true ;
49
50
} catch (const Exception& e) {
50
51
return false ;
51
52
}
52
53
}
53
- volatile bool defaultAllocatorSet = setNumpyAllocator ();
54
+ volatile bool bootSuccess = upyOpenCVBoot ();
54
55
55
56
mp_obj_t cv2_core_convertScaleAbs (size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
56
57
// Define the arguments
0 commit comments