Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions dvis.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
Metadata-Version: 2.1
Name: dvis
Version: 0.9.0.2
Summary: The best web-based visualizer
Home-page: https://github.com/SirWyver/dvis
Author: Norman Müller
Author-email: norman.mueller@tum.de
License: UNKNOWN
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown

<p align="center"><a target="_blank" rel="noopener noreferrer"><img width="100" src="./static/icon.png"></a></p>
<h1 align="center">DVIS: 3D Visualizations made easy</h1>
<h2 align="center">Visualize your data with just one line of code </h2>
<h2 align="center">Python -> Browser </h2>


<p align="center">
<img src="./static/tracking_sample.gif" width="40%" />
<img src="./static/shapenet_sample.gif" width="42.5%" />
<img src="./static/mesh_sample.gif" width="40%" />
<img src="./static/camera_path.gif" width="42.5%" />
</p>

# 💻 Usage
```python
from dvis import dvis

dvis("mesh.obj") # load file
dvis(point_cloud, vs=0.03) # point cloud with specific voxel size
dvis(bboxes,'bbox', c=3, name='my_boxes') # show colored boxes
dvis(np.array([0,0,0,1,2,3]), 'vec') # vector from origin to (1,2,3)
dvis(transform, 'transform') # display transformation
dvis(img, 'img') # display an image using visdom
```
Check out more examples in `./examples`
```
python examples/meshes.py
python examples/point_clouds.py
python examples/...
```


# News
* 0.8.8.0: Bumped dependencies version, custom port support
```
dvis(port=<PORT>) # set port the client is sending on
dvis(vis_port=<PORT>) # set the port for visdom
```

* 0.8.7.0: CLI for server: To start the server, use run
```
dvis-server [--no_visdom]
```
* 0.8.6.0: Histogram support using plotly
```
dvis(array, "hist", mi=0.1,ma=0.8, nbins=10, name="Example histogram")
```

* 0.8.4.0: Label and range image support, auto-format for img
```
dvis(label_img [fmt='xyl']) # visualizses img of labels
dvis(depth_map [fmt='xyr', cm='jet']) # visualizes an image of continuous values using cv2 color map
dvis(heat_map [fmt='xyr', cm='hot'])
```

# 🚀 Getting started

## 1. Install the `dvis` package:
Via pypi:
```
pip install dvis
```
or from source:
```
git clone git@github.com:SirWyver/dvis.git
cd dvis
pip install .
```
## 2. Start the web server
```
# From the dvis repository folder:
dvis-server
```
or manually
```
cd server
python server.py
```

Verify you can open http://localhost:5001/ and see something like this:

<p align="center">
<img src="./static/dvis_ui.png" width=40%>
</p>

Optionally, also start [visdom](https://github.com/fossasia/visdom) to display images/videos/charts:
```
visdom -p 4999
```
The visdom server should be accessible at http://localhost:4999/.

Try out the client
```python
import numpy as np
from dvis import dvis
dvis(np.random.rand(1000,6), s=0.03) # sends randomly colored 1000x3 point cloud to the 3d server
dvis("static/icon.png","img") # sends an image to the 2d server

```
Verify you can see a colored point cloud

# 📖 Documentation
For an overview of available commands check out the [documentation](https://sirwyver.github.io/dvis_docu/)

## Shotcuts
| Shortcut | Description |
|----------|---------------------------|
| **Editor** | |
| w | Translate |
| e | Rotate |
| r | Scale |
| z | Undo |
| f | Focus |
| **DVIS** | |
| v | Show/hide selected object |
| 1-5 | Toggle layer 1-5 |
| 0 | Toggle all layers |
| Shift + 0-5 | Show layer 0-5 add. |
| g | Show/hide grid & axes helper |
| n | Next keyframe |
| b | Previous keyframe |
| . | Next frame |
| , | Previous frame |
| t | Switch camera |
| [ | Download screenshot |





14 changes: 14 additions & 0 deletions dvis.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
README.md
setup.py
dvis/__init__.py
dvis/dvis.py
dvis/dvis_cli.py
dvis/dvis_client.py
dvis/dvis_client_old.py
dvis/utils.py
dvis.egg-info/PKG-INFO
dvis.egg-info/SOURCES.txt
dvis.egg-info/dependency_links.txt
dvis.egg-info/entry_points.txt
dvis.egg-info/requires.txt
dvis.egg-info/top_level.txt
1 change: 1 addition & 0 deletions dvis.egg-info/dependency_links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

4 changes: 4 additions & 0 deletions dvis.egg-info/entry_points.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[console_scripts]
dvis = dvis.dvis_cli:dvis_cli
dvis-server = dvis.dvis_cli:dvis_server_cli

9 changes: 9 additions & 0 deletions dvis.egg-info/requires.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
numpy
pillow>=10.0
trimesh
simple-websocket>=0.2.0
python-socketio>=4.6.1
eventlet
jinja2>=3.0.2
werkzeug>=2.0.3
opencv-python
1 change: 1 addition & 0 deletions dvis.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dvis
Binary file modified dvis/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
Binary file modified dvis/__pycache__/dvis.cpython-38.pyc
Binary file not shown.
Binary file modified dvis/__pycache__/dvis_client.cpython-38.pyc
Binary file not shown.
Binary file modified dvis/__pycache__/utils.cpython-38.pyc
Binary file not shown.
43 changes: 32 additions & 11 deletions dvis/dvis.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
torch_float = None
torch_double = None

from .dvis_client import send2server, send_payload2server
from .dvis_client import send2server, send_payload2server, send_visdom_command
from .dvis_client import send_plotly, sendMesh2server, send_clear, send_config, sendTrack2server, sendCmd2server,sendPose2server,sendInject2server, send_objectKFState, sendCamImage2server
from .dvis_client import set_port, set_vis_port
import trimesh
Expand Down Expand Up @@ -50,7 +50,12 @@ def convert_to_nd(data):
return np.array(data)
except:
pass
raise Exception("Data type not understood")
try:
data = np.array(data)
print(f"Converted to np.ndarray: {data.shape}")
return data
except:
raise Exception("Data type not understood")


def matplot2PIL(fig):
Expand Down Expand Up @@ -367,7 +372,7 @@ def dvis_mesh_pc(data, vs=1, c=0, l=0, t=None, name=None, meta=None, ms=None, vi
shape=shape,
)

def _image_size(img, s, is_bool=False):
def _image_resize(img, s, is_bool=False):
if s!=1:
if isinstance(s, (int,float)):
if s < 10:
Expand Down Expand Up @@ -401,11 +406,11 @@ def dvis_img(data, vs=1, c=0, l=[0], t=None, name=None, meta=None, vis_conf=None
fn =f"tmp.{suffix}"
Connection(hostname).get(remote_path,fn)
img = Image.open(fn)
data = np.array(_image_size(img))
data = np.array(_image_resize(img,s=s))
os.remove(fn)
else:
img = Image.open(fn)
data = np.array(_image_size(img))
data = np.array(_image_resize(img,s=s))
if meta is None:
meta = {}
meta["obj_path"] = fn
Expand Down Expand Up @@ -447,7 +452,7 @@ def dvis_img(data, vs=1, c=0, l=[0], t=None, name=None, meta=None, vis_conf=None
data = (data[...,:3]*255).astype(np.uint8)
if s!=1:
img = Image.fromarray(data)
img = _image_size(img,s, is_bool=is_bool)
img = _image_resize(img,s, is_bool=is_bool)
data = np.array(img)
if is_bool:
data = data.astype(np.uint8)
Expand Down Expand Up @@ -768,7 +773,7 @@ def dvis_transform(data, s=1, c=0, l=[0], t=0, name="transform", meta=None, vis_
compression="pkl",
)

def dvis_seq(data, vs=1, c=0, l=[0], t=None, name=None, meta=None, vis_conf=None, cm='default', fmt='seq', mi=None, ma=None):
def dvis_seq(data, vs=1, c=0, l=[0], t=None, name=None, meta=None, vis_conf=None, cm='default', fmt='seq', mi=None, ma=None,s=1):
data = convert_to_nd(data)
sub_format = None
if len(data.shape)==3 or data.shape[-1] == 1:
Expand All @@ -780,7 +785,7 @@ def dvis_seq(data, vs=1, c=0, l=[0], t=None, name=None, meta=None, vis_conf=None
elif sub_format == 'xyr':
# range image with
# remap default to jet
data = np.stack(visualize_range(data[i], cm=("jet" if cm=='default' else cm), mi=mi, ma=ma) for i in range(data.shape[0]))
data = np.stack(visualize_range(data[i], cm=("jet" if cm=='default' else cm), mi=mi, ma=ma,verbose=i==0) for i in range(data.shape[0]))
if data.shape[-1] in [3,4]: # T H W C
data = data.transpose(0,3,1,2)
if name is None:
Expand All @@ -806,6 +811,17 @@ def dvis_seq(data, vs=1, c=0, l=[0], t=None, name=None, meta=None, vis_conf=None
data[...,:3] = data[...,:3] * alpha_mask + (1.0 - c) * (1-alpha_mask)
data = (data[...,:3]*255).astype(np.uint8)
data = data.transpose(0,3,1,2)

if s!=1:
is_bool = data.dtype == bool
resized_data = []
for img in data:
img = Image.fromarray(img.transpose(1,2,0))
img = _image_resize(img,s, is_bool=is_bool)
resized_data.append(np.array(img).transpose(2,0,1))
data = np.stack(resized_data)
if is_bool:
data = data.astype(np.uint8)

send2server(data=data, data_format="seq", size=vs, color=c, layers=l, t=t, name=name, meta_data=meta, vis_conf=vis_conf, sub_format=sub_format)

Expand All @@ -824,7 +840,8 @@ def _infer_format(data):
or (hasattr(matplotlib, "figure") and isinstance(data, matplotlib.figure.Figure))
):
fmt = "img"
elif isinstance(data, str):
elif isinstance(data, (Path, str)):
data = str(data)
suffix = data.split(".")[-1]
if suffix in ["jpeg", "jpg", "png", "gif"]:
fmt = "img"
Expand All @@ -849,7 +866,7 @@ def _infer_format(data):
# fmt = "cwhl"
else:
raise IOError("Data format %s not understood" % str(data.shape))
elif len(data.shape) == 3:
if len(data.shape) == 3:
if (data.shape[0] == 3 or data.shape[2] ==3) or (data.shape[0] == 4 or data.shape[2] ==4):
# assume image for convenience
fmt = "img"
Expand Down Expand Up @@ -1093,6 +1110,10 @@ def dvis(
if "vis_port" in kwargs:
set_vis_port(kwargs["vis_port"])
return
# special commands
if isinstance(data, str) and data in ["clear", "clean", "close"]:
send_visdom_command("close")
return

if isinstance(l, int):
l = [l]
Expand Down Expand Up @@ -1134,7 +1155,7 @@ def dvis(
elif fmt == "cam":
dvis_cam(data, name)
elif fmt == "seq":
dvis_seq(data, vs, c, l, t, name, meta, vis_conf, fmt=fmt, cm=kwargs.get("cm",'default'), mi=kwargs.get('mi'), ma=kwargs.get('ma'))
dvis_seq(data, vs, c, l, t, name, meta, vis_conf, fmt=fmt, cm=kwargs.get("cm",'default'), mi=kwargs.get('mi'), ma=kwargs.get('ma'),s=s)

elif fmt == "cmd":
dvis_cmd(data)
Expand Down
21 changes: 17 additions & 4 deletions dvis/dvis_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
PORT = 5001
VIS_PORT = 4999

visdom_instance = None

def set_port(port):
global PORT
PORT = port
Expand All @@ -26,6 +28,12 @@ def encode_to_base64(x):
return x
return base64.b64encode(x).decode("utf8")

def _get_visdom_instance():
global visdom_instance
if visdom_instance is None:
visdom_instance = visdom.Visdom(port=VIS_PORT)
return visdom_instance


def send2server(data, data_format, size, color, layers, t, name="", meta_data=None, vis_conf=None, shape="v", compression="gzip", sub_format=None):
if data is not None:
Expand All @@ -38,7 +46,8 @@ def send2server(data, data_format, size, color, layers, t, name="", meta_data=No
else:
print("Sending group")
if data_format in ["hwc", "img", "seq"]:
vis = visdom.Visdom(port=VIS_PORT)
vis = _get_visdom_instance()

if data_format == "seq":
for img in data:
vis.image(img, opts=dict(store_history=True), win=name)
Expand All @@ -49,7 +58,7 @@ def send2server(data, data_format, size, color, layers, t, name="", meta_data=No
data[np.all(data == 255, 2)] = np.array(color)
vis.image(data.transpose(2, 0, 1), opts={"caption": name})
elif data_format in ["gif"]:
vis = visdom.Visdom(port=VIS_PORT)
vis = _get_visdom_instance()
vis.text(f'<img src="data:image/gif;base64,{data} ">', opts={"caption": name})
else:
if compression == "pkl":
Expand All @@ -58,7 +67,7 @@ def send2server(data, data_format, size, color, layers, t, name="", meta_data=No
else:
data = pickle.dumps(data)
elif compression == "gzip":
data = gzip.compress(data.astype(np.float32).copy(order="C"))
data = gzip.compress(data.astype(np.float32).copy(order="C"), mtime=0)
elif compression in ["glb", "obj"]: # meshes
tm = data
if compression == "glb":
Expand Down Expand Up @@ -97,7 +106,7 @@ def send2server(data, data_format, size, color, layers, t, name="", meta_data=No


def send_plotly(data, layout):
vis = visdom.Visdom(port=VIS_PORT)
vis = _get_visdom_instance()
print(f"Sending plolty {data['type']}")
vis._send({"data": [data], "layout": layout})

Expand Down Expand Up @@ -125,6 +134,10 @@ def send_payload2server(
"shape": shape,
},
)
def send_visdom_command(cmd):
vis = _get_visdom_instance()
if cmd == "close":
vis.close()


def img_to_base64(image):
Expand Down
Loading