From 06fd8f8b4ae52d1688ac496d73a16c0026d92f56 Mon Sep 17 00:00:00 2001 From: Garrett Brown Date: Wed, 20 Nov 2019 17:35:58 -0800 Subject: [PATCH] cv-bridge: Update for OpenCV 4 Patches from: github.com/ros-perception/vision_opencv/pull/288 --- .../cv-bridge/0001-add-OpenCV4-support.patch | 42 ++ .../cv-bridge/0002-added-missig-file.patch | 390 ++++++++++++++++++ .../vision-opencv/cv-bridge_2.1.2-1.bb | 6 +- 3 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 generated-recipes-dashing/vision-opencv/cv-bridge/0001-add-OpenCV4-support.patch create mode 100644 generated-recipes-dashing/vision-opencv/cv-bridge/0002-added-missig-file.patch diff --git a/generated-recipes-dashing/vision-opencv/cv-bridge/0001-add-OpenCV4-support.patch b/generated-recipes-dashing/vision-opencv/cv-bridge/0001-add-OpenCV4-support.patch new file mode 100644 index 00000000000..d3785cbcf8d --- /dev/null +++ b/generated-recipes-dashing/vision-opencv/cv-bridge/0001-add-OpenCV4-support.patch @@ -0,0 +1,42 @@ +From 9b38c8ac88f3d44addc7ab5ba7ce95ec5d1c0097 Mon Sep 17 00:00:00 2001 +From: BrutusTT +Date: Wed, 4 Sep 2019 11:39:30 +0100 +Subject: [PATCH 1/2] add OpenCV4 support addresses + ros-perception/vision_opencv#272 + +--- + CMakeLists.txt | 2 +- + src/CMakeLists.txt | 4 +++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 4a2fa77..4c416cb 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -37,7 +37,7 @@ else() + endif() + + find_package(sensor_msgs REQUIRED) +-find_package(OpenCV 3 REQUIRED ++find_package(OpenCV REQUIRED + COMPONENTS + opencv_core + opencv_imgproc +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index dc40f1a..3ec80d5 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -34,7 +34,9 @@ if(PYTHON_VERSION_MAJOR VERSION_EQUAL 3) + add_definitions(-DPYTHON3) + endif() + +-if(OpenCV_VERSION_MAJOR VERSION_EQUAL 3) ++if (OpenCV_VERSION_MAJOR VERSION_EQUAL 4) ++ add_library(${PROJECT_NAME}_boost module.cpp module_opencv4.cpp) ++elseif(OpenCV_VERSION_MAJOR VERSION_EQUAL 3) + add_library(${PROJECT_NAME}_boost module.cpp module_opencv3.cpp) + else() + add_library(${PROJECT_NAME}_boost module.cpp module_opencv2.cpp) +-- +2.17.1 + diff --git a/generated-recipes-dashing/vision-opencv/cv-bridge/0002-added-missig-file.patch b/generated-recipes-dashing/vision-opencv/cv-bridge/0002-added-missig-file.patch new file mode 100644 index 00000000000..1bf1bdfd197 --- /dev/null +++ b/generated-recipes-dashing/vision-opencv/cv-bridge/0002-added-missig-file.patch @@ -0,0 +1,390 @@ +From 6fd0c5ad34407bb3c40aadaf61d31adb4971db4f Mon Sep 17 00:00:00 2001 +From: BrutusTT +Date: Thu, 17 Oct 2019 14:37:40 +0100 +Subject: [PATCH 2/2] added missig file + +--- + cv_bridge/src/module_opencv4.cpp | 371 +++++++++++++++++++++++++++++++ + 1 file changed, 371 insertions(+) + create mode 100644 cv_bridge/src/module_opencv4.cpp + +diff --git a/cv_bridge/src/module_opencv4.cpp b/cv_bridge/src/module_opencv4.cpp +new file mode 100644 +index 0000000..60a9d05 +--- /dev/null ++++ b/cv_bridge/src/module_opencv4.cpp +@@ -0,0 +1,371 @@ ++// Taken from opencv/modules/python/src2/cv2.cpp ++ ++#include "module.hpp" ++ ++#include "opencv2/core/types_c.h" ++ ++#include "opencv2/opencv_modules.hpp" ++ ++#include "pycompat.hpp" ++ ++static PyObject* opencv_error = 0; ++ ++static int failmsg(const char *fmt, ...) ++{ ++ char str[1000]; ++ ++ va_list ap; ++ va_start(ap, fmt); ++ vsnprintf(str, sizeof(str), fmt, ap); ++ va_end(ap); ++ ++ PyErr_SetString(PyExc_TypeError, str); ++ return 0; ++} ++ ++struct ArgInfo ++{ ++ const char * name; ++ bool outputarg; ++ // more fields may be added if necessary ++ ++ ArgInfo(const char * name_, bool outputarg_) ++ : name(name_) ++ , outputarg(outputarg_) {} ++ ++ // to match with older pyopencv_to function signature ++ operator const char *() const { return name; } ++}; ++ ++class PyAllowThreads ++{ ++public: ++ PyAllowThreads() : _state(PyEval_SaveThread()) {} ++ ~PyAllowThreads() ++ { ++ PyEval_RestoreThread(_state); ++ } ++private: ++ PyThreadState* _state; ++}; ++ ++class PyEnsureGIL ++{ ++public: ++ PyEnsureGIL() : _state(PyGILState_Ensure()) {} ++ ~PyEnsureGIL() ++ { ++ PyGILState_Release(_state); ++ } ++private: ++ PyGILState_STATE _state; ++}; ++ ++#define ERRWRAP2(expr) \ ++try \ ++{ \ ++ PyAllowThreads allowThreads; \ ++ expr; \ ++} \ ++catch (const cv::Exception &e) \ ++{ \ ++ PyErr_SetString(opencv_error, e.what()); \ ++ return 0; \ ++} ++ ++using namespace cv; ++ ++static PyObject* failmsgp(const char *fmt, ...) ++{ ++ char str[1000]; ++ ++ va_list ap; ++ va_start(ap, fmt); ++ vsnprintf(str, sizeof(str), fmt, ap); ++ va_end(ap); ++ ++ PyErr_SetString(PyExc_TypeError, str); ++ return 0; ++} ++ ++class NumpyAllocator : public MatAllocator ++{ ++public: ++ NumpyAllocator() { stdAllocator = Mat::getStdAllocator(); } ++ ~NumpyAllocator() {} ++ ++ UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const ++ { ++ UMatData* u = new UMatData(this); ++ u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o); ++ npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); ++ for( int i = 0; i < dims - 1; i++ ) ++ step[i] = (size_t)_strides[i]; ++ step[dims-1] = CV_ELEM_SIZE(type); ++ u->size = sizes[0]*step[0]; ++ u->userdata = o; ++ return u; ++ } ++ ++ UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, AccessFlag flags, UMatUsageFlags usageFlags) const ++ { ++ if( data != 0 ) ++ { ++ CV_Error(Error::StsAssert, "The data should normally be NULL!"); ++ // probably this is safe to do in such extreme case ++ return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags); ++ } ++ PyEnsureGIL gil; ++ ++ int depth = CV_MAT_DEPTH(type); ++ int cn = CV_MAT_CN(type); ++ const int f = (int)(sizeof(size_t)/8); ++ int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : ++ depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : ++ depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT : ++ depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT; ++ int i, dims = dims0; ++ cv::AutoBuffer _sizes(dims + 1); ++ for( i = 0; i < dims; i++ ) ++ _sizes[i] = sizes[i]; ++ if( cn > 1 ) ++ _sizes[dims++] = cn; ++ PyObject* o = PyArray_SimpleNew(dims, _sizes.data(), typenum); ++ if(!o) ++ CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); ++ return allocate(o, dims0, sizes, type, step); ++ } ++ ++ bool allocate(UMatData* u, AccessFlag accessFlags, UMatUsageFlags usageFlags) const CV_OVERRIDE ++ { ++ return stdAllocator->allocate(u, accessFlags, usageFlags); ++ } ++ ++ void deallocate(UMatData* u) const CV_OVERRIDE ++ { ++ if(!u) ++ return; ++ PyEnsureGIL gil; ++ CV_Assert(u->urefcount >= 0); ++ CV_Assert(u->refcount >= 0); ++ if(u->refcount == 0) ++ { ++ PyObject* o = (PyObject*)u->userdata; ++ Py_XDECREF(o); ++ delete u; ++ } ++ } ++ ++ const MatAllocator* stdAllocator; ++}; ++ ++NumpyAllocator g_numpyAllocator; ++ ++ ++template static ++bool pyopencv_to(PyObject* obj, T& p, const char* name = ""); ++ ++template static ++PyObject* pyopencv_from(const T& src); ++ ++enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 }; ++ ++// special case, when the convertor needs full ArgInfo structure ++static bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo info) ++{ ++ // to avoid PyArray_Check() to crash even with valid array ++ do_numpy_import( ); ++ ++ ++ bool allowND = true; ++ if(!o || o == Py_None) ++ { ++ if( !m.data ) ++ m.allocator = &g_numpyAllocator; ++ return true; ++ } ++ ++ if( PyInt_Check(o) ) ++ { ++ double v[] = {(double)PyInt_AsLong((PyObject*)o), 0., 0., 0.}; ++ m = Mat(4, 1, CV_64F, v).clone(); ++ return true; ++ } ++ if( PyFloat_Check(o) ) ++ { ++ double v[] = {PyFloat_AsDouble((PyObject*)o), 0., 0., 0.}; ++ m = Mat(4, 1, CV_64F, v).clone(); ++ return true; ++ } ++ if( PyTuple_Check(o) ) ++ { ++ int i, sz = (int)PyTuple_Size((PyObject*)o); ++ m = Mat(sz, 1, CV_64F); ++ for( i = 0; i < sz; i++ ) ++ { ++ PyObject* oi = PyTuple_GET_ITEM(o, i); ++ if( PyInt_Check(oi) ) ++ m.at(i) = (double)PyInt_AsLong(oi); ++ else if( PyFloat_Check(oi) ) ++ m.at(i) = (double)PyFloat_AsDouble(oi); ++ else ++ { ++ failmsg("%s is not a numerical tuple", info.name); ++ m.release(); ++ return false; ++ } ++ } ++ return true; ++ } ++ ++ if( !PyArray_Check(o) ) ++ { ++ failmsg("%s is not a numpy array, neither a scalar", info.name); ++ return false; ++ } ++ ++ PyArrayObject* oarr = (PyArrayObject*) o; ++ ++ bool needcopy = false, needcast = false; ++ int typenum = PyArray_TYPE(oarr), new_typenum = typenum; ++ int type = typenum == NPY_UBYTE ? CV_8U : ++ typenum == NPY_BYTE ? CV_8S : ++ typenum == NPY_USHORT ? CV_16U : ++ typenum == NPY_SHORT ? CV_16S : ++ typenum == NPY_INT ? CV_32S : ++ typenum == NPY_INT32 ? CV_32S : ++ typenum == NPY_FLOAT ? CV_32F : ++ typenum == NPY_DOUBLE ? CV_64F : -1; ++ ++ if( type < 0 ) ++ { ++ if( typenum == NPY_INT64 || typenum == NPY_UINT64 || type == NPY_LONG ) ++ { ++ needcopy = needcast = true; ++ new_typenum = NPY_INT; ++ type = CV_32S; ++ } ++ else ++ { ++ failmsg("%s data type = %d is not supported", info.name, typenum); ++ return false; ++ } ++ } ++ ++#ifndef CV_MAX_DIM ++ const int CV_MAX_DIM = 32; ++#endif ++ ++ int ndims = PyArray_NDIM(oarr); ++ if(ndims >= CV_MAX_DIM) ++ { ++ failmsg("%s dimensionality (=%d) is too high", info.name, ndims); ++ return false; ++ } ++ ++ int size[CV_MAX_DIM+1]; ++ size_t step[CV_MAX_DIM+1]; ++ size_t elemsize = CV_ELEM_SIZE1(type); ++ const npy_intp* _sizes = PyArray_DIMS(oarr); ++ const npy_intp* _strides = PyArray_STRIDES(oarr); ++ bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX; ++ ++ for( int i = ndims-1; i >= 0 && !needcopy; i-- ) ++ { ++ // these checks handle cases of ++ // a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases ++ // b) transposed arrays, where _strides[] elements go in non-descending order ++ // c) flipped arrays, where some of _strides[] elements are negative ++ if( (i == ndims-1 && (size_t)_strides[i] != elemsize) || ++ (i < ndims-1 && _strides[i] < _strides[i+1]) ) ++ needcopy = true; ++ } ++ ++ if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] ) ++ needcopy = true; ++ ++ if (needcopy) ++ { ++ if (info.outputarg) ++ { ++ failmsg("Layout of the output array %s is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)", info.name); ++ return false; ++ } ++ ++ if( needcast ) { ++ o = PyArray_Cast(oarr, new_typenum); ++ oarr = (PyArrayObject*) o; ++ } ++ else { ++ oarr = PyArray_GETCONTIGUOUS(oarr); ++ o = (PyObject*) oarr; ++ } ++ ++ _strides = PyArray_STRIDES(oarr); ++ } ++ ++ for(int i = 0; i < ndims; i++) ++ { ++ size[i] = (int)_sizes[i]; ++ step[i] = (size_t)_strides[i]; ++ } ++ ++ // handle degenerate case ++ if( ndims == 0) { ++ size[ndims] = 1; ++ step[ndims] = elemsize; ++ ndims++; ++ } ++ ++ if( ismultichannel ) ++ { ++ ndims--; ++ type |= CV_MAKETYPE(0, size[2]); ++ } ++ ++ if( ndims > 2 && !allowND ) ++ { ++ failmsg("%s has more than 2 dimensions", info.name); ++ return false; ++ } ++ ++ m = Mat(ndims, size, type, PyArray_DATA(oarr), step); ++ m.u = g_numpyAllocator.allocate(o, ndims, size, type, step); ++ m.addref(); ++ ++ if( !needcopy ) ++ { ++ Py_INCREF(o); ++ } ++ m.allocator = &g_numpyAllocator; ++ ++ return true; ++} ++ ++template<> ++bool pyopencv_to(PyObject* o, Mat& m, const char* name) ++{ ++ return pyopencv_to(o, m, ArgInfo(name, 0)); ++} ++ ++PyObject* pyopencv_from(const Mat& m) ++{ ++ if( !m.data ) ++ Py_RETURN_NONE; ++ Mat temp, *p = (Mat*)&m; ++ if(!p->u || p->allocator != &g_numpyAllocator) ++ { ++ temp.allocator = &g_numpyAllocator; ++ ERRWRAP2(m.copyTo(temp)); ++ p = &temp; ++ } ++ PyObject* o = (PyObject*)p->u->userdata; ++ Py_INCREF(o); ++ return o; ++} ++ ++int convert_to_CvMat2(const PyObject* o, cv::Mat& m) ++{ ++ pyopencv_to(const_cast(o), m, "unknown"); ++ return 0; ++} +-- +2.17.1 + diff --git a/generated-recipes-dashing/vision-opencv/cv-bridge_2.1.2-1.bb b/generated-recipes-dashing/vision-opencv/cv-bridge_2.1.2-1.bb index f8c8be4e15a..2c0719d22b1 100644 --- a/generated-recipes-dashing/vision-opencv/cv-bridge_2.1.2-1.bb +++ b/generated-recipes-dashing/vision-opencv/cv-bridge_2.1.2-1.bb @@ -61,7 +61,11 @@ DEPENDS += "${ROS_EXPORT_DEPENDS} ${ROS_BUILDTOOL_EXPORT_DEPENDS}" RDEPENDS_${PN} += "${ROS_EXEC_DEPENDS}" -SRC_URI = "https://github.com/ros2-gbp/vision_opencv-release/archive/release/dashing/cv_bridge/2.1.2-1.tar.gz;downloadfilename=${ROS_SP}.tar.gz" +SRC_URI = " \ + https://github.com/ros2-gbp/vision_opencv-release/archive/release/dashing/cv_bridge/2.1.2-1.tar.gz;downloadfilename=${ROS_SP}.tar.gz \ + file://0001-add-OpenCV4-support.patch \ + file://0002-added-missig-file.patch \ +" SRC_URI[md5sum] = "126a51a44027a451239491288baa1557" SRC_URI[sha256sum] = "a2ea40ef8b0826917ff9994b9411ab0999302bf1ac025d0bb07e2d8488e62551" S = "${WORKDIR}/vision_opencv-release-release-dashing-cv_bridge-2.1.2-1"