Rhino 8 crashes when calling pip package methods

Hi !
I didn’t find a similar topic so I’m opening a new one.

I am using pip packages such as open3d to make operations that are not included in RhinoCommon, such as ICP point cloud registration. In may of this year I am certain calling the open3d ICP registration worked fine (probably using some version of Rhino 8.7, possibly 8.6) on MacOs.

Fast-forward to today, using rhino 8.9.24194.18122 on MacOs, as well as 8.8.24170.13001 on Windows, the code that previously worked now crashes, and the new code I am currently developing does it as well.

The issue is directly linked to specific lines of code involving open3d, but not all. For example, creating an open3d PointCloud object works fine:

    def align_to_skeleton(self, reference_skeleton):
        """
        Align the tree to a reference skeleton using ICP
        :param reference_skeleton: Pointcloud
            The reference skeleton to align to
        """
        tree_pc = o3d.geometry.PointCloud()
        tree_pc.points = o3d.utility.Vector3dVector(np.array(self.point_cloud.points))
        skeleton_pc = o3d.geometry.PointCloud()
        skeleton_pc.points = o3d.utility.Vector3dVector(np.array(self.skeleton.points))
        skeleton_pc.estimate_normals()
        reference_skeleton_pc = o3d.geometry.PointCloud()
        reference_skeleton_pc.points = o3d.utility.Vector3dVector(np.array(reference_skeleton.points))
        reference_skeleton_pc.estimate_normals()

        print("Tree point cloud has ", len(tree_pc.points), " points")
        print("Skeleton point cloud has ", len(skeleton_pc.points), " points")
        print("Reference point cloud has ", len(reference_skeleton_pc.points), " points")

        print("tree_pc is of type: ", type(tree_pc))
        print("skeleton_pc is of type: ", type(skeleton_pc))
        print("reference_pc is of type: ", type(reference_skeleton_pc))


        initial_translation = np.identity(4)
        initial_translation[0, 3] = reference_skeleton_pc.points[0][0] - skeleton_pc.points[0][0]
        initial_translation[1, 3] = reference_skeleton_pc.points[0][1] - skeleton_pc.points[0][1]
        initial_translation[2, 3] = reference_skeleton_pc.points[0][2] - skeleton_pc.points[0][2]

        # result = o3d.pipelines.registration.registration_icp(skeleton_pc, 
        #                                                      reference_pc,
        #                                                      10.0,
        #                                                      initial_translation)

terminal output:

Path of script to run ( Browse ): /c:/Users/localuser/Carnutes/src/function_3.py
Select the whole structure
Select the whole structure. Press Enter when done
Curves converted to NurbsCurve
Select the element to replace with a point cloud
Element selected: fc65a236-6eec-42b4-97a9-04bd30dc6829
Tree 6 - 4901
Tree point cloud has  4902  points
Skeleton point cloud has  11  points
reference skeleton point cloud has  31  points
tree_pc is of type:  <class 'open3d.cpu.pybind.geometry.PointCloud'>
skeleton_pc is of type:  <class 'open3d.cpu.pybind.geometry.PointCloud'>
reference_skeleton_pc is of type:  <class 'open3d.cpu.pybind.geometry.PointCloud'>
Done

but as soon as I call the ICP registration (the line commented-out in the code above), Rhino crashes altogether. On windows it freezes 2-3 seconds, on MacOs it is instantaneous. Where it gets very strange, is that using RANSAC based on feature matching doesn’t crash, but if I try to print the resulting transformation matrix, I get a strange error:

result 
= o3d.pipelines.registration.registration_ransac_based_on_feature_matching(skeleton_pc, reference_pc, skeleton_pc_fpfh, reference_pc_fpfh, False, 10.0)

transformation 
= result.transformation

tree_pc = copy.deepcopy(tree_pc)

print("Type of transformation matrix: ",
type(transformation))
print("Shape of transformation matrix: ",
transformation.shape)
print("Transformation matrix\n",
transformation)

terminal output:

Path of script to run ( Browse )/Users/admin/Carnutes/src/function_3.py
LineCurves converted to NurbsCurves
Element selected: 6ccc6e76-5267-452b-b012-07ab5a5fe95c
Tree 4 - 3315
Type of transformation matrix:  <class 'numpy.ndarray'>
Shape of transformation matrix:  (4, 4)
Transformation matrix
 Traceback (most recent call last):
  File "file:///Users/admin/Carnutes/src/function_3.py", line 99, in <module>
  File "file:///Users/admin/Carnutes/src/function_3.py", line 96, in main
  File "/Users/admin/Carnutes/src/utils/tree.py", line 113, in align_to_skeleton
    print("Transformation matrix\n", transformation)
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 1664, in _array_str_implementation
    return array2string(a, max_line_width, precision, suppress_small, ' ', "")
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 757, in array2string
    return _array2string(a, options, separator, prefix)
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 529, in wrapper
    return f(self, *args, **kwargs)
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 555, in _array2string
    format_function = _get_format_function(data, **options)
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 488, in _get_format_function
    return formatdict['float']()
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 427, in <lambda>
    'float': lambda: FloatingFormat(
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 959, in __init__
    self.fillFormat(data)
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/arrayprint.py", line 970, in fillFormat
    with errstate(over='ignore'):  # division can overflow
  File "/Users/admin/.rhinocode/py39-rh8/site-envs/default-ipRe2pAH/numpy/_core/_ufunc_config.py", line 419, in __enter__
    extobj = _make_extobj(
TypeError: python object must be callable or have a callable write method

The numpy and open3d issues might not be related, but they appeared around the same time, so maybe they are a more general issues with pip packages ?

Here is my system info of Windows:
Rhino_sys_info_Windows_Damien_Gilliard.txt (2.5 KB)

Here is my system info of MacOs
Rhino_sys_info_Mac_Damien_Gilliard.txt (4.2 KB)

on windows I don’t get any crash report, but on mac I get this:
error_report_Damien_Gilliard.txt (335.7 KB)

Since The code is on Github, to reproduce the error, I believe the most simple is to clone the Model_connectivity branch of the Carnutes repository and run the function_3.py with Rhino’s ScriptEditor. This repo is Work In Progress, but for the rest works fine.

If the issue is caused by an error of mine, I apologize in advance, and if not, I hope this Topic can improve future versions of Rhino8.

Thanks in advance !!

I ran into a similar problem, and I believe I fixed it by running the following code before trying to print any numpy array:

import numpy as np
np.set_printoptions(formatter={"float": "{:.5f}".format})

Before doing this, I couldn’t convert a multidimensional array to its string representation, which seems to be what’s happening here to you.

Hi Russel,
Thanks for your reply!

Your proposition fixed the numpy problem :+1:, but the open3d icp_registration still crashes Rhino.

I tried the same icp registration method outside of Rhino, using similar point clouds, Python 3.9, numpy 2.0.0 and open3d 0.18.0, and it works just fine. I am also able to print a numpy ndarray outside of Rhino without using the set_printoptions(). This is why this behaviour is strange to me, and why I report it here…

UPDATE:
Thanks to this Topic, I was able to work around the problem adding this at the beginning of the code (in this case for MacOs):

CONDA_ENV = r'/Users/admin/anaconda3/envs/database_creation'

sys.path.append(os.path.join(CONDA_ENV, r"lib/python3.9/site-packages"))
os.environ["DYLD_LIBRARY_PATH"] = os.path.join(CONDA_ENV, r'bin')

Now I am able to use open3d ICP registration (The code is strictly the same, but doesn’t crash now), but I suppose this is not how it should be done in an ideal scenario. I have no idea why ‘# r: open3d’ didn’t do the trick…

Is it possible to get a rhino 8.6 .dmg copy to see if the very same code does work in that version ? Thanks a lot !

Ok I got it, the issue is the new numpy 2.0.0, that generates segmentation faults in open3d. I guess Rhino 8 updates numpy automatically. By forcing a previous version of numpy with # r: numpy==1.26.4, everything works ! Sorry for polluting the forum with non-Rhino issues…

cheers