0
$\begingroup$

Rosanswers logo

I'm running a script that uses cv_bridge with OpenCV 4, on Python 3, on ROS Melodic, on Raspbian, on a Raspberry Pi 4, and I'm running into errors trying to dynamically import cv_bridge.boost and failing.

I built ROS from source following these instructions, and installed opencv with sudo pip3 install opencv-contrib-python==4.1.0.25. I've had to do a bit of a hack to get it to import properly (I run sys.path.append('/usr/lib/python2.7/dist-packages') before I import cv2) but beyond these hacks, OpenCV 4 seems to be playing nice with Python 3, and Python 3 seems to be playing nice with ROS.

I from cv_bridge import CvBridge, CvBridgeError without issue, then run:

self.bridge = CvBridge()
image_opencv = self.bridge.imgmsg_to_cv2(data, desired_encoding="passthrough")

on a helper class, where data (as the function suggests) is a standard ROS Image message. (In my case, I'm getting these messages from the cv_camera topic /cv_camera/image_raw)

when I try to run that, I get this error:

[ERROR] [1588106367.612936]: bad callback: <bound method tpu_detector.callback of <__main__.tpu_detector object at 0xa7061df0>>
Traceback (most recent call last):
  File "/opt/ros/melodic/lib/python2.7/dist-packages/rospy/topics.py", line 750, in _invoke_callback
    cb(msg)
  File "/home/pi/catkin_ws/src/edge_tpu/scripts/detect_ros.py", line 91, in callback
    data, desired_encoding="passthrough")
  File "/home/pi/catkin_build_ws/install/lib/python2.7/dist-packages/cv_bridge/core.py", line 163, in imgmsg_to_cv2
    dtype, n_channels = self.encoding_to_dtype_with_channels(img_msg.encoding)
  File "/home/pi/catkin_build_ws/install/lib/python2.7/dist-packages/cv_bridge/core.py", line 99, in encoding_to_dtype_with_channels
    return self.cvtype2_to_dtype_with_channels(self.encoding_to_cvtype2(encoding))
  File "/home/pi/catkin_build_ws/install/lib/python2.7/dist-packages/cv_bridge/core.py", line 91, in encoding_to_cvtype2
    from cv_bridge.boost.cv_bridge_boost import getCvType
ImportError: dynamic module does not define module export function (PyInit_cv_bridge_boost)

every time an image message arrives. Which, to put it lightly, really sucks. I've googled the snot out of it, and come up with a few pages, all of which tell me to build cv_bridge for Python 3 - but I already have. Multiple times. Following the instructions in this Medium post line by line, the error persists. The error traceback above prooves that this custom-built package is being imported like it's supposed to.

It's worth noting that I had to use catkin_make to build cv_bridge properly; catkin build cv_bridge (with all the extra flags of https://stackoverflow.com/questions/49221565/unable-to-use-cv-bridge-with-ros-kinetic-and-python3, plus an extra -DPYTHON3=1 I added to placate NumPy) fails for no apparent reason (I've pasted the output into this gist if anyone believes it to be related to the issue)

I have been stuck on this issue for a multitude of hours and have gotten no closer to a solution - any help will be much appreciated!


Originally posted by hermanoid on ROS Answers with karma: 176 on 2020-04-28

Post score: 1


Original comments

Comment by anonymous60874 on 2021-03-28:
Hey did you find the solution? I'm getting the same error. If you did can you help me pls?

Comment by hermanoid on 2021-03-29:
@Onurcan Thanks for the reminder! See my new answer on this thread.

Comment by 404RobotNotFound on 2021-04-10:
While this isn't a specific answer to your problem, you are going to have a lot less headaches using python2 and opencv 3 when working with ROS melodic. If you want to stick with python 3 and opencv 4, depending on your Raspbian version, you can install ROS noetic instead since they officially ported to python 3.

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

While this is probably not the best solution, the way I eventually solved this was to remove any reference to dysfunctional libraries from the source code. The result is very solution-specific, so you'll have to make sure that your input and output data types line up - bgr8, for my example. You might be able to adapt it to a different data type if needed. The code looks like this:

NotCvBridge.py

"""
    Provides conversions between OpenCV and ROS image formats in a hard-coded way.  
    CV_Bridge, the module usually responsible for doing this, is not compatible with Python 3,
     - the language this all is written in.  So we create this module, and all is... well, all is not well,
     - but all works.  :-/
"""
import sys
import numpy as np
from sensor_msgs.msg import Image

def imgmsg_to_cv2(img_msg):
    if img_msg.encoding != "bgr8":
        rospy.logerr("This Coral detect node has been hardcoded to the 'bgr8' encoding.  Come change the code if you're actually trying to implement a new camera")
    dtype = np.dtype("uint8") # Hardcode to 8 bits...
    dtype = dtype.newbyteorder('>' if img_msg.is_bigendian else '<')
    image_opencv = np.ndarray(shape=(img_msg.height, img_msg.width, 3), # and three channels of data. Since OpenCV works with bgr natively, we don't need to reorder the channels.
                    dtype=dtype, buffer=img_msg.data)
    # If the byt order is different between the message and the system.
    if img_msg.is_bigendian == (sys.byteorder == 'little'):
        image_opencv = image_opencv.byteswap().newbyteorder()
    return image_opencv

def cv2_to_imgmsg(cv_image):
    img_msg = Image()
    img_msg.height = cv_image.shape[0]
    img_msg.width = cv_image.shape[1]
    img_msg.encoding = "bgr8"
    img_msg.is_bigendian = 0
    img_msg.data = cv_image.tostring()
    img_msg.step = len(img_msg.data) // img_msg.height # That double line is actually integer division, not a comment
    return img_msg

Originally posted by hermanoid with karma: 176 on 2021-03-29

This answer was ACCEPTED on the original site

Post score: 6


Original comments

Comment by Kelly Jones on 2021-04-10:
thank you. was having endless problems with cvbridge and the above fixed them

Comment by rosgeller on 2021-07-27:
This is the most underrated solution on the internet.. Thank you!!

Comment by Martin Günther on 2021-07-28:
I've upvoted this answer since it is an elegant solution if you can't use cv_bridge in some context (or don't want to). However, for 95% of people reading this post: You shouldn't try to use Python3 with ROS Melodic. If you want to use Python 3, use ROS Noetic. Everything else will give you endless headaches.

Comment by MambaMentality24 on 2021-10-28:
I'm using ROS Melodic and I'm trying to use torchvision.models. However, it doesn't work whenever I use Python2. Because of this, I'm "stuck" with having to use Python3. Is there any way to get PyTorch to install with python2.7?

Comment by hermanoid on 2021-10-28:
I havent used PyTorch, but in my experience with Tensorflow, convincing the framework to use old python just isn't going to work. You'll have to use an older version of PyTorch, from before it updated to Python3. If possible, life would be much easier if you could switch to Python3, even if it's just for this one ROS node.

Comment by swagatk on 2023-01-18:
Thanks a lot for this post. It really solved my problem with ROS Noetic on Raspberry Pi 4.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.