Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save tvercaut/d210ed103f64ebb24606eb032b38de0a to your computer and use it in GitHub Desktop.

Select an option

Save tvercaut/d210ed103f64ebb24606eb032b38de0a to your computer and use it in GitHub Desktop.
torch-fit-plane.ipynb

A simple PyTorch implementation of plane fitting with RANSAC. Some ideas are taken from: https://github.com/leomariga/pyRANSAC-3D.

In each (batched-)RANSAC iteration, a batch of triplets is sampled and assessed in parallel. A cross-product is used to get plane equations from triplets. The refinement, post identification of inliers, is done with an eigen decomposition of P.T @ P where P is the matrix of points in homogeneous coordinates. Classicially, an SVD decomposition of P is used but this can be slow and memory intensive with large number of points. We thus opted for the eigen decomposition approach despite it being less numerically stable.

Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"authorship_tag": "ABX9TyPVEFGSh4AjTBgfivZS7hwk",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU",
"gpuClass": "standard"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/tvercaut/d210ed103f64ebb24606eb032b38de0a/torch-fit-plane.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "code",
"source": [
"import torch\n",
"print(f'Running PyTorch version: {torch.__version__}')\n",
"\n",
"torchdevice = torch.device('cpu')\n",
"if torch.cuda.is_available():\n",
" torchdevice = torch.device('cuda')\n",
" print('Default GPU is ' + torch.cuda.get_device_name(torch.device('cuda')))\n",
"print('Running on ' + str(torchdevice))\n",
"\n",
"import numpy as np"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JmLeblLAb_eG",
"outputId": "88604f7d-d66f-433b-e48c-beebd0cca180"
},
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Running PyTorch version: 1.12.1+cu113\n",
"Default GPU is Tesla T4\n",
"Running on cuda\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"def fit_plane_batch_crossprod(points, normalize=False):\n",
" # points: BxNx3 batched groups of N=3 3d points\n",
" # return: Bx4 where for each input in the batch we get [a, b, c, d] such that\n",
" # ax+by+cz+d = 0 is the equation of teh corresponding plane\n",
" # No care is taken about colinear inputs\n",
" num_batch = points.shape[0]\n",
" num_points = points.shape[1]\n",
" dim = points.shape[2]\n",
"\n",
" if dim != 3:\n",
" raise ValueError(f\"Only 3D points are supported, got dim={dim}\")\n",
"\n",
" if num_points != 3:\n",
" raise ValueError(f\"Only groups of 3 points are supported, got num_points={num_points}\")\n",
"\n",
" # We have to find the plane equation described by those 3 points\n",
" # We find first 2 vectors that are part of this plane\n",
" # V10 = pt1 - pt0\n",
" # V20 = pt2 - pt0\n",
" vec10 = points[:,1,:] - points[:,0,:]\n",
" vec20 = points[:,2,:] - points[:,0,:]\n",
"\n",
" # Now we compute the cross product of vec10 and vec20 to get vecN which is normal to the plane\n",
" vecN = torch.linalg.cross(vec10, vec20)\n",
" \n",
" # The plane equation will be vecN[0]*x + vecN[1]*y + vecN[0]*z = -d\n",
" # We use any of the points to find k\n",
" d = -torch.einsum('bd,bd->b', vecN, points[:,0,:].squeeze(dim=1))\n",
" plane_params = torch.cat((vecN,d.unsqueeze(1)),1)\n",
"\n",
" # We can normalise for better interpretability but this would lead to issues\n",
" # if the points are co-linear\n",
" if normalize:\n",
" plane_params /= torch.linalg.norm(plane_params,dim=1,keepdim=True)\n",
" return plane_params\n",
"\n",
"def plane_batch_dist(points, plane_params, signeddist=False):\n",
" # plane_params: Bx4 B plane equations ax+by+cz+d = 0 given as [a, b, c, d] \n",
" # points: Nx3 N 3d points\n",
" # return: BxN distances\n",
" # No care is taken in case [a,b,c] has a zero norm\n",
" num_batch = plane_params.shape[0]\n",
" num_points = points.shape[0]\n",
" dim = points.shape[1]\n",
"\n",
" if dim != 3:\n",
" raise ValueError(f\"Only 3D points are supported, got dim={dim}\")\n",
"\n",
" # Distance from a point to a plane\n",
" # https://mathworld.wolfram.com/Point-PlaneDistance.html\n",
" # ax+by+cz+d / norm([a,b,c])\n",
" denoms = torch.linalg.norm(plane_params[:,0:3],dim=1,keepdim=True)\n",
" point_h = torch.cat((points, torch.ones((num_points,1),device=points.device)),1)\n",
" dists = torch.einsum('bd,nd->bn', plane_params, point_h) / denoms\n",
" if not signeddist:\n",
" dists = torch.abs( dists )\n",
" return dists\n",
"\n",
"def fit_plane_batch_eigh(points):\n",
" # points: BxNx3 batched groups of N 3d points\n",
" # return: Bx4 where for each input in the batch we get [a, b, c, d] such that\n",
" # ax+by+cz+d = 0 is the equation of teh corresponding plane\n",
" # No care is taken about colinear inputs\n",
" num_batch = points.shape[0]\n",
" num_points = points.shape[1]\n",
" dim = points.shape[2]\n",
"\n",
" if dim != 3:\n",
" raise ValueError(f\"Only 3D points are supported, got dim={dim}\")\n",
"\n",
" points_h = torch.cat((points, torch.ones((num_batch,num_points,1),device=points.device)),2)\n",
" smat = torch.matmul( torch.transpose(points_h,1,2), points_h )\n",
" w, v = torch.linalg.eigh(smat)\n",
" return v[:, :, 0]\n",
"\n",
"def fit_plane_ransac(points, inlierthresh=0.05, batch=1000, numbatchiter=100, verbose=False):\n",
" # points: Nx3 N 3d points\n",
" # inlierthresh: Threshold distance from the plane which is considered inlier.\n",
" # batch: Number of triplets considered in parallel during each batched RANSAC\n",
" # iteration\n",
" # numbatchiter: Number of maximum iteration which RANSAC will loop over.\n",
" # return: [a, b, c, d] such that ax+by+cz+d = 0 is the equation of the\n",
" # corresponding plane\n",
" num_points = points.shape[0]\n",
" dim = points.shape[1]\n",
"\n",
" if dim != 3:\n",
" raise ValueError(f\"Only 3D points are supported, got dim={dim}\")\n",
"\n",
" best_num_inliers = 0\n",
" best_inliers = None\n",
" best_plane = None\n",
"\n",
" for iter in range(numbatchiter):\n",
" if verbose:\n",
" print(f\"iteration: {iter}\")\n",
" # Get random triplets. Ideally, we would draw without replacement in each\n",
" # triplet and also ensure we don't use duplicate triplets.\n",
" randidx = torch.randint(0, num_points, (batch,3))\n",
" triplets = points[randidx.flatten(),:].reshape(batch,3,3)\n",
"\n",
" # Get planes going through triplets\n",
" planes = fit_plane_batch_crossprod(triplets)\n",
"\n",
" # Estimate quality of each plane\n",
" dists = plane_batch_dist(points, planes)\n",
" inliers = (dists < inlierthresh)\n",
" num_inliers = torch.sum(inliers, dim=1)\n",
"\n",
" batch_best_idx = torch.argmax(num_inliers)\n",
" batch_best_num_inliers = num_inliers[batch_best_idx]\n",
" if verbose:\n",
" print(f' best batch plane: {planes[batch_best_idx,:] / torch.linalg.norm(planes[batch_best_idx,:])} - ({batch_best_num_inliers}/{num_points})')\n",
" if batch_best_num_inliers > best_num_inliers:\n",
" best_num_inliers = batch_best_num_inliers\n",
" best_inliers = inliers[batch_best_idx,:]\n",
" best_plane = planes[batch_best_idx,:]\n",
" if verbose:\n",
" print(f'best new plane: {best_plane / torch.linalg.norm(best_plane)} - ({best_num_inliers}/{num_points})')\n",
"\n",
" # Refine plane equation based on inliers\n",
" inlier_points = points[best_inliers,:]\n",
" best_plane = fit_plane_batch_eigh(inlier_points.unsqueeze(0))\n",
" if verbose:\n",
" print(f'refined_plane {best_plane}')\n",
" return best_plane, best_inliers"
],
"metadata": {
"id": "tq3hVG1IFA0Q"
},
"execution_count": 16,
"outputs": []
},
{
"cell_type": "code",
"source": [
"import urllib.request\n",
"\n",
"# Download an example point cloud\n",
"url=\"https://github.com/leomariga/pyRANSAC-3D/raw/master/tests/dataset/caixa.ply\"\n",
"urllib.request.urlretrieve(url, \"caixa.ply\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fpfZzTHx0Tnd",
"outputId": "111b430e-6222-4494-db58-ed56c358b2c0"
},
"execution_count": 3,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"('caixa.ply', <http.client.HTTPMessage at 0x7f6edb863290>)"
]
},
"metadata": {},
"execution_count": 3
}
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hS7kX7MJhn9k",
"outputId": "eb397e03-b1cd-4eab-c40d-dd871ad5bd76"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Requirement already satisfied: open3d in /usr/local/lib/python3.7/dist-packages (0.16.0)\n",
"Requirement already satisfied: configargparse in /usr/local/lib/python3.7/dist-packages (from open3d) (1.5.3)\n",
"Requirement already satisfied: pandas>=1.0 in /usr/local/lib/python3.7/dist-packages (from open3d) (1.3.5)\n",
"Requirement already satisfied: dash>=2.6.0 in /usr/local/lib/python3.7/dist-packages (from open3d) (2.7.0)\n",
"Requirement already satisfied: tqdm in /usr/local/lib/python3.7/dist-packages (from open3d) (4.64.1)\n",
"Requirement already satisfied: pillow>=8.2.0 in /usr/local/lib/python3.7/dist-packages (from open3d) (9.3.0)\n",
"Requirement already satisfied: numpy>1.15 in /usr/local/lib/python3.7/dist-packages (from open3d) (1.21.6)\n",
"Requirement already satisfied: matplotlib>=3 in /usr/local/lib/python3.7/dist-packages (from open3d) (3.2.2)\n",
"Requirement already satisfied: scikit-learn>=0.21 in /usr/local/lib/python3.7/dist-packages (from open3d) (1.0.2)\n",
"Requirement already satisfied: addict in /usr/local/lib/python3.7/dist-packages (from open3d) (2.4.0)\n",
"Requirement already satisfied: ipywidgets>=7.6.0 in /usr/local/lib/python3.7/dist-packages (from open3d) (7.7.1)\n",
"Requirement already satisfied: pyyaml>=5.4.1 in /usr/local/lib/python3.7/dist-packages (from open3d) (6.0)\n",
"Requirement already satisfied: nbformat==5.5.0 in /usr/local/lib/python3.7/dist-packages (from open3d) (5.5.0)\n",
"Requirement already satisfied: pyquaternion in /usr/local/lib/python3.7/dist-packages (from open3d) (0.9.9)\n",
"Requirement already satisfied: jupyter_core in /usr/local/lib/python3.7/dist-packages (from nbformat==5.5.0->open3d) (4.11.2)\n",
"Requirement already satisfied: traitlets>=5.1 in /usr/local/lib/python3.7/dist-packages (from nbformat==5.5.0->open3d) (5.1.1)\n",
"Requirement already satisfied: fastjsonschema in /usr/local/lib/python3.7/dist-packages (from nbformat==5.5.0->open3d) (2.16.2)\n",
"Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.7/dist-packages (from nbformat==5.5.0->open3d) (4.3.3)\n",
"Requirement already satisfied: Flask>=1.0.4 in /usr/local/lib/python3.7/dist-packages (from dash>=2.6.0->open3d) (1.1.4)\n",
"Requirement already satisfied: dash-table==5.0.0 in /usr/local/lib/python3.7/dist-packages (from dash>=2.6.0->open3d) (5.0.0)\n",
"Requirement already satisfied: dash-html-components==2.0.0 in /usr/local/lib/python3.7/dist-packages (from dash>=2.6.0->open3d) (2.0.0)\n",
"Requirement already satisfied: dash-core-components==2.0.0 in /usr/local/lib/python3.7/dist-packages (from dash>=2.6.0->open3d) (2.0.0)\n",
"Requirement already satisfied: plotly>=5.0.0 in /usr/local/lib/python3.7/dist-packages (from dash>=2.6.0->open3d) (5.5.0)\n",
"Requirement already satisfied: Werkzeug<2.0,>=0.15 in /usr/local/lib/python3.7/dist-packages (from Flask>=1.0.4->dash>=2.6.0->open3d) (1.0.1)\n",
"Requirement already satisfied: Jinja2<3.0,>=2.10.1 in /usr/local/lib/python3.7/dist-packages (from Flask>=1.0.4->dash>=2.6.0->open3d) (2.11.3)\n",
"Requirement already satisfied: click<8.0,>=5.1 in /usr/local/lib/python3.7/dist-packages (from Flask>=1.0.4->dash>=2.6.0->open3d) (7.1.2)\n",
"Requirement already satisfied: itsdangerous<2.0,>=0.24 in /usr/local/lib/python3.7/dist-packages (from Flask>=1.0.4->dash>=2.6.0->open3d) (1.1.0)\n",
"Requirement already satisfied: jupyterlab-widgets>=1.0.0 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.6.0->open3d) (3.0.3)\n",
"Requirement already satisfied: widgetsnbextension~=3.6.0 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.6.0->open3d) (3.6.1)\n",
"Requirement already satisfied: ipython-genutils~=0.2.0 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.6.0->open3d) (0.2.0)\n",
"Requirement already satisfied: ipython>=4.0.0 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.6.0->open3d) (7.9.0)\n",
"Requirement already satisfied: ipykernel>=4.5.1 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.6.0->open3d) (5.3.4)\n",
"Requirement already satisfied: tornado>=4.2 in /usr/local/lib/python3.7/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.6.0->open3d) (6.0.4)\n",
"Requirement already satisfied: jupyter-client in /usr/local/lib/python3.7/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.6.0->open3d) (6.1.12)\n",
"Requirement already satisfied: prompt-toolkit<2.1.0,>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (2.0.10)\n",
"Requirement already satisfied: pygments in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (2.6.1)\n",
"Requirement already satisfied: pickleshare in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (0.7.5)\n",
"Requirement already satisfied: decorator in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (4.4.2)\n",
"Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (57.4.0)\n",
"Requirement already satisfied: pexpect in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (4.8.0)\n",
"Requirement already satisfied: jedi>=0.10 in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (0.18.2)\n",
"Requirement already satisfied: backcall in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (0.2.0)\n",
"Requirement already satisfied: parso<0.9.0,>=0.8.0 in /usr/local/lib/python3.7/dist-packages (from jedi>=0.10->ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (0.8.3)\n",
"Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2<3.0,>=2.10.1->Flask>=1.0.4->dash>=2.6.0->open3d) (2.0.1)\n",
"Requirement already satisfied: importlib-resources>=1.4.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->nbformat==5.5.0->open3d) (5.10.0)\n",
"Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->nbformat==5.5.0->open3d) (0.19.2)\n",
"Requirement already satisfied: attrs>=17.4.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->nbformat==5.5.0->open3d) (22.1.0)\n",
"Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->nbformat==5.5.0->open3d) (4.13.0)\n",
"Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->nbformat==5.5.0->open3d) (4.1.1)\n",
"Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.7/dist-packages (from importlib-resources>=1.4.0->jsonschema>=2.6->nbformat==5.5.0->open3d) (3.10.0)\n",
"Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3->open3d) (2.8.2)\n",
"Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3->open3d) (3.0.9)\n",
"Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3->open3d) (1.4.4)\n",
"Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3->open3d) (0.11.0)\n",
"Requirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.7/dist-packages (from pandas>=1.0->open3d) (2022.6)\n",
"Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from plotly>=5.0.0->dash>=2.6.0->open3d) (1.15.0)\n",
"Requirement already satisfied: tenacity>=6.2.0 in /usr/local/lib/python3.7/dist-packages (from plotly>=5.0.0->dash>=2.6.0->open3d) (8.1.0)\n",
"Requirement already satisfied: wcwidth in /usr/local/lib/python3.7/dist-packages (from prompt-toolkit<2.1.0,>=2.0.0->ipython>=4.0.0->ipywidgets>=7.6.0->open3d) (0.2.5)\n",
"Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.21->open3d) (1.2.0)\n",
"Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.21->open3d) (3.1.0)\n",
"Requirement already satisfied: scipy>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.21->open3d) (1.7.3)\n",
"Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.7/dist-packages (from widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (5.7.16)\n",
"Requirement already satisfied: nbconvert<6.0 in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (5.6.1)\n",
"Requirement already satisfied: pyzmq>=17 in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (23.2.1)\n",
"Requirement already satisfied: prometheus-client in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.15.0)\n",
"Requirement already satisfied: terminado>=0.8.1 in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.13.3)\n",
"Requirement already satisfied: Send2Trash in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (1.8.0)\n",
"Requirement already satisfied: defusedxml in /usr/local/lib/python3.7/dist-packages (from nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.7.1)\n",
"Requirement already satisfied: mistune<2,>=0.8.1 in /usr/local/lib/python3.7/dist-packages (from nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.8.4)\n",
"Requirement already satisfied: entrypoints>=0.2.2 in /usr/local/lib/python3.7/dist-packages (from nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.4)\n",
"Requirement already satisfied: bleach in /usr/local/lib/python3.7/dist-packages (from nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (5.0.1)\n",
"Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.7/dist-packages (from nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (1.5.0)\n",
"Requirement already satisfied: testpath in /usr/local/lib/python3.7/dist-packages (from nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.6.0)\n",
"Requirement already satisfied: ptyprocess in /usr/local/lib/python3.7/dist-packages (from terminado>=0.8.1->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.7.0)\n",
"Requirement already satisfied: webencodings in /usr/local/lib/python3.7/dist-packages (from bleach->nbconvert<6.0->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.6.0->open3d) (0.5.1)\n"
]
}
],
"source": [
"# Get open3d for IO and visualisation purposes\n",
"!pip install open3d\n",
"import open3d as o3d"
]
},
{
"cell_type": "code",
"source": [
"# Load point cloud and visualize it\n",
"pcd_load = o3d.io.read_point_cloud(\"caixa.ply\")\n",
"points = np.asarray(pcd_load.points)\n",
"o3d.visualization.draw_plotly([pcd_load])"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 417
},
"id": "fg0AVRQejLjL",
"outputId": "d4d4c123-8632-4dc4-a425-8c1dafb5f55c"
},
"execution_count": 5,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/html": [
"<html>\n",
"<head><meta charset=\"utf-8\" /></head>\n",
"<body>\n",
" <div> <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG\"></script><script type=\"text/javascript\">if (window.MathJax) {MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}</script> <script type=\"text/javascript\">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>\n",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment