griegler/octnet

How to properly visualize octree?

Closed this issue · 5 comments

Hi, thanks for your code. Is there a tool to 'visualize' the octree data?

Attached is some code to write the octree structure to a tikz figure.

import sys
import numpy as np
import matplotlib.pyplot as plt
import time

sys.path.append('../../code/common/build')
import pyoctree_cpu

def tikz_cube(f, x0,y0,z0, x1,y1,z1, fmt_str):
  f.write('\\draw[%s] (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- cycle;\n' % (fmt_str, x0,y0,z0, x0,y1,z0, x1,y1,z0, x1,y0,z0))
  f.write('\\draw[%s] (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- cycle;\n' % (fmt_str, x0,y0,z0, x0,y0,z1, x0,y1,z1, x0,y1,z0))
  f.write('\\draw[%s] (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- cycle;\n' % (fmt_str, x0,y1,z0, x1,y1,z0, x1,y1,z1, x0,y1,z1))
  f.write('\\draw[%s] (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- cycle;\n' % (fmt_str, x0,y0,z0, x1,y0,z0, x1,y0,z1, x0,y0,z1))
  f.write('\\draw[%s] (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- cycle;\n' % (fmt_str, x0,y0,z1, x0,y1,z1, x1,y1,z1, x1,y0,z1))
  f.write('\\draw[%s] (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- (%d,%d,%d) -- cycle;\n' % (fmt_str, x1,y0,z0, x1,y0,z1, x1,y1,z1, x1,y1,z0))

def tikz_grid_solid(f, grid, vis_grid_idx=None, color_from_data=False):
  n_blocks = grid.num_blocks() if vis_grid_idx is None else 1

  f.write("\\documentclass{minimal}\n")
  f.write("\\usepackage{xcolor}\n")
  f.write("\\usepackage{tikz,tikz-3dplot}\n")
  f.write("\\begin{document}\n")
  f.write("\\tdplotsetmaincoords{50}{130}\n")
  f.write("\\begin{tikzpicture}[scale=0.5, tdplot_main_coords]\n")

  for (leaf, grid_idx, bit_idx, gd,gh,gw, bd,bh,bw, level) in pyoctree_cpu.leaf_iterator(grid, leafs_only=False):
    if color_from_data:
      if leaf:
        grid_data = grid.get_grid_data()
        data_idx = grid.data_idx(grid_idx, bit_idx)
        color = [grid_data[data_idx + 0], grid_data[data_idx + 1], grid_data[data_idx + 2]]
      else:
        color = [0,0,0]
    else:
      cm = plt.cm.get_cmap('viridis')
      color = cm(grid_idx * 1.0 / n_blocks)
      color = [int(255*color[0]), int(255*color[1]), int(255*color[2])]

    if vis_grid_idx is not None and vis_grid_idx != grid_idx:
      continue

    x = gw * 8 + bw
    y = gh * 8 + bh
    z = gd * 8 + bd
    width = 2**(3 - level)

    x0 = x
    y0 = y
    z0 = z
    x1 = x + width
    y1 = y + width
    z1 = z + width

    if leaf or level == 0:
      color_str = 'color_%d' % grid_idx
      f.write('\\definecolor{%s}{RGB}{%d,%d,%d}\n' % (color_str, color[0], color[1], color[2]))

      if leaf:
        tikz_cube(f, x0,y0,z0, x1,y1,z1, 'very thin, gray, fill=%s,fill opacity=1.0' % (color_str))
      else:
        tikz_cube(f, x0,y0,z0, x1,y1,z1, 'very thick,black')
  f.write("\\end{tikzpicture}\n")
  f.write("\\end{document}\n")

def tikz_grid_wireframe(f, grid, vis_grid_idx=None, color_from_data=False):
  n_blocks = grid.num_blocks() if vis_grid_idx is None else 1

  f.write("\\documentclass{minimal}\n")
  f.write("\\usepackage{xcolor}\n")
  f.write("\\usepackage{tikz,tikz-3dplot}\n")
  f.write("\\begin{document}\n")
  f.write("\\tdplotsetmaincoords{50}{130}\n")
  f.write("\\begin{tikzpicture}[scale=0.5, tdplot_main_coords]\n")

  for (leaf, grid_idx, bit_idx, gd,gh,gw, bd,bh,bw, level) in pyoctree_cpu.leaf_iterator(grid, leafs_only=False):
    if color_from_data:
      if leaf:
        grid_data = grid.get_grid_data()
        data_idx = grid.data_idx(grid_idx, bit_idx)
        color = [grid_data[data_idx + 0], grid_data[data_idx + 1], grid_data[data_idx + 2]]
      else:
        color = [0,0,0]
    else:
      cm = plt.cm.get_cmap('viridis')
      color = cm(grid_idx * 1.0 / n_blocks)
      color = [int(255*color[0]), int(255*color[1]), int(255*color[2])]

    if vis_grid_idx is not None and vis_grid_idx != grid_idx:
      continue

    x = gw * 8 + bw
    y = gh * 8 + bh
    z = gd * 8 + bd
    width = 2**(3 - level)

    x0 = x
    y0 = y
    z0 = z
    x1 = x + width
    y1 = y + width
    z1 = z + width

    if leaf:
      color_str = 'color_%d' % grid_idx
      f.write('\\definecolor{%s}{RGB}{%d,%d,%d}\n' % (color_str, color[0], color[1], color[2]))
      tikz_cube(f, x0,y0,z0, x1,y1,z1, 'very thin, %s' % (color_str))
  f.write("\\end{tikzpicture}\n")
  f.write("\\end{document}\n")


off_path = 'airplane_0710.off'
factor = 2
depth, height, width  = 8 * factor, 8 * factor, 8 * factor
R = np.eye(3, dtype=np.float32)
grid = pyoctree_cpu.Octree.create_from_off(off_path, depth, height, width, R, pack=False, n_threads=6)

f = open('out_solid.tex', 'w')
tikz_grid_solid(f, grid)
f.close()

f = open('out_wireframe.tex', 'w')
tikz_grid_wireframe(f, grid)
f.close()

Hi, Thanks for your reply. import pyoctnet and import pyoctree_cpu which is correct? In the example code create_data.py I found import pyoctnet and pyoctnet.Octree.create_from_off. But I can't import pyoctree_cpu. Did you update the code? And I didn't find '../../code/common/build' in the current GitHub repository.
I have successfully built cpu version of core and create and can import pyoctnet but cannot import pyoctree_cpu

sys.path.append('../../code/common/build') should point to the path, where you did build the Python extension. And replace pyoctree_cpu with pyoctnet.

Thanks!
Can I ask what the n_threads argument in the create functions means? I am doing medical applications and I create octree from a 512512128 dense volume, the resulting octree is very big(more than 2 Gb). I am wondering whether there are some arguments to control the size of the octree. What should I do if I want the octree be smaller? I also tried to create octree using a very fine mesh(from a CT scan), the octree is still very large. I noticed there are depth, height and width arguments. Will setting these arguments smaller help?

Is there other codes to save the visualization of octree to other formats? The generated tikz figure( .tex) sometimes is too big for overleaf to render(I use medical data)... It would be more convenient to be able to visualize it directly... It would be great if there's some documentation about the usage of the functions.