add rendering pointcloud and voxel ode
This commit is contained in:
parent
5d1e63102a
commit
bff091bfa2
|
@ -17,6 +17,7 @@
|
|||
</p>
|
||||
|
||||
## Update
|
||||
* add pointclouds rendering code used for paper figure, see `utils/render_mitsuba_pc.py`
|
||||
* When opening an issue, please add @ZENGXH so that I can reponse faster!
|
||||
|
||||
## Install
|
||||
|
|
393
utils/_render_mitsuba_cubes.py
Normal file
393
utils/_render_mitsuba_cubes.py
Normal file
|
@ -0,0 +1,393 @@
|
|||
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
#
|
||||
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
|
||||
# and proprietary rights in and to this software, related documentation
|
||||
# and any modifications thereto. Any use, reproduction, disclosure or
|
||||
# distribution of this software and related documentation without an express
|
||||
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
|
||||
|
||||
import numpy as np
|
||||
import sys, os, subprocess
|
||||
import mitsuba as mi
|
||||
import OpenEXR
|
||||
import Imath
|
||||
from PIL import Image
|
||||
from plyfile import PlyData, PlyElement
|
||||
import torch
|
||||
import time
|
||||
from PIL import Image, ImageChops
|
||||
random_str = hex(int(time.time() + 12345))[2:]
|
||||
def trim(im):
|
||||
bg = Image.new(im.mode, im.size, im.getpixel((0,0))) ##border)
|
||||
diff = ImageChops.difference(im, bg)
|
||||
bbox = diff.getbbox()
|
||||
if bbox:
|
||||
return im.crop(bbox)
|
||||
else:
|
||||
return im
|
||||
|
||||
|
||||
PATH_TO_MITSUBA2 = "/home/xzeng/code/mitsuba2/build/dist/mitsuba" ## Codes/mitsuba2/build/dist/mitsuba" # mitsuba exectuable
|
||||
|
||||
|
||||
xml_head_segment = \
|
||||
"""
|
||||
<scene version="0.6.0">
|
||||
<integrator type="path">
|
||||
<integer name="maxDepth" value="-1"/>
|
||||
</integrator>
|
||||
<sensor type="perspective">
|
||||
<float name="farClip" value="100"/>
|
||||
<float name="nearClip" value="0.1"/>
|
||||
<transform name="toWorld">
|
||||
<lookat origin="{},{},{}" target="0,0,0" up="0,0,1"/>
|
||||
</transform>
|
||||
<float name="fov" value="25"/>
|
||||
<sampler type="ldsampler">
|
||||
<integer name="sampleCount" value="{}"/>
|
||||
</sampler>
|
||||
<film type="hdrfilm">
|
||||
<integer name="width" value="{}"/>
|
||||
<integer name="height" value="{}"/>
|
||||
<rfilter type="gaussian"/>
|
||||
</film>
|
||||
</sensor>
|
||||
|
||||
<bsdf type="roughplastic" id="surfaceMaterial">
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.05"/>
|
||||
<float name="intIOR" value="1.46"/>
|
||||
<rgb name="diffuseReflectance" value="1,1,1"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
|
||||
"""
|
||||
|
||||
xml_head = \
|
||||
"""
|
||||
<scene version="0.6.0">
|
||||
<integrator type="path">
|
||||
<integer name="maxDepth" value="-1"/>
|
||||
</integrator>
|
||||
|
||||
<sensor type="perspective">
|
||||
<float name="farClip" value="100"/>
|
||||
<float name="nearClip" value="0.1"/>
|
||||
<transform name="toWorld">
|
||||
<lookat origin="3,3,3" target="0,0,0" up="0,0,1"/>
|
||||
</transform>
|
||||
<float name="fov" value="25"/>
|
||||
<sampler type="ldsampler">
|
||||
<integer name="sampleCount" value="256"/>
|
||||
</sampler>
|
||||
<film type="hdrfilm">
|
||||
<integer name="width" value="800"/>
|
||||
<integer name="height" value="600"/>
|
||||
<rfilter type="gaussian"/>
|
||||
</film>
|
||||
</sensor>
|
||||
|
||||
<bsdf type="roughplastic" id="surfaceMaterial">
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.05"/>
|
||||
<float name="intIOR" value="1.46"/>
|
||||
<rgb name="diffuseReflectance" value="1,1,1"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
|
||||
<bsdf type="roughdielectric" id="trans">
|
||||
<float name="int_ior" value="1.31"/>
|
||||
<float name="ext_ior" value="1.6"/>
|
||||
</bsdf>
|
||||
<bsdf type="roughplastic" id="trans2">
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.05"/>
|
||||
<float name="intIOR" value="1.46"/>
|
||||
<rgb name="diffuseReflectance" value="0.6,0.3,0.2"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
<bsdf type="roughdielectric" id="trans3">
|
||||
<float name="int_ior" value="1.51"/>
|
||||
<float name="ext_ior" value="1.0"/>
|
||||
<rgb name="specular_reflectance" value="0.6,0.3,0.2"/>
|
||||
</bsdf>
|
||||
|
||||
"""
|
||||
|
||||
# I also use a smaller point size
|
||||
xml_ball_segment = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="0.025"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="diffuse">
|
||||
<rgb name="reflectance" value="{},{},{}"/>
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
xml_cube_segment = \
|
||||
"""
|
||||
<shape type="ply" >
|
||||
<string name="filename" value="./script/paper/vis_voxel_exp/unit_cube2w1.ply"/>
|
||||
<transform name="toWorld">
|
||||
<scale x="{}" y="{}" z="{}"/>
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="roughplastic" >
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.05"/>
|
||||
<float name="intIOR" value="1.46"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
|
||||
</shape>
|
||||
"""
|
||||
|
||||
xml_shape_segment = \
|
||||
"""
|
||||
<shape type="ply" id="mesh">
|
||||
<string name="filename" value="{}"/>
|
||||
<bsdf type="roughplastic" id="surfaceMaterialshape">
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.05"/>
|
||||
<float name="intIOR" value="1.46"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
|
||||
</shape>
|
||||
"""
|
||||
## <ref name="bsdf" id="trans3"/>
|
||||
# <shape type="sphere">
|
||||
# <float name="radius" value="0.025"/>
|
||||
# <transform name="toWorld">
|
||||
# <translate x="0" y="0" z="0.4"/>
|
||||
#
|
||||
# </transform>
|
||||
# <bsdf type="diffuse">
|
||||
# <rgb name="reflectance" value="0.7,0.4,0.5"/>
|
||||
# </bsdf>
|
||||
# </shape>
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
# <shape type="sphere">
|
||||
# <float name="radius" value="0.025"/>
|
||||
# <transform name="toWorld">
|
||||
# <translate x="1" y="1" z="1"/>
|
||||
#
|
||||
# </transform>
|
||||
# <bsdf type="diffuse">
|
||||
# <rgb name="reflectance" value="0.7,0.4,0.5"/>
|
||||
# </bsdf>
|
||||
# </shape>
|
||||
# <shape type="rectangle">
|
||||
# <transform name="toWorld">
|
||||
# <scale x="0.05" y="0.05" z="0.05"/>
|
||||
# <translate x="1" y="1" z="0.8"/>
|
||||
# </transform>
|
||||
#
|
||||
# <bsdf type="diffuse">
|
||||
# <rgb name="reflectance" value="0.7,0.4,0.5"/>
|
||||
# </bsdf>
|
||||
# </shape>
|
||||
# <shape type="rectangle">
|
||||
# <transform name="toWorld">
|
||||
# <scale x="0.05" y="0.05" z="0.05"/>
|
||||
# <translate x="1" y="1.2" z="0.6"/>
|
||||
# </transform>
|
||||
#
|
||||
# <bsdf type="diffuse">
|
||||
# <rgb name="reflectance" value="0.7,0.4,0.5"/>
|
||||
# </bsdf>
|
||||
# </shape>
|
||||
#
|
||||
#
|
||||
# <shape type="sphere">
|
||||
# <point name="center" x="-1" y="1" z="1.5"/>
|
||||
# <float name="radius" value="0.05"/>
|
||||
# <emitter type="area">
|
||||
# <rgb name="radiance" value="30,10,10"/>
|
||||
# </emitter>
|
||||
# </shape>
|
||||
#
|
||||
|
||||
# <bsdf type="diffuse">
|
||||
# <rgb name="reflectance" value="1,0,0"/>
|
||||
# </bsdf>
|
||||
#
|
||||
# <bsdf type="diffuse">
|
||||
# <rgb name="reflectance" value="{},{},{}"/>
|
||||
# </bsdf>
|
||||
# <bsdf type="roughplastic" id="surfaceMaterialshape">
|
||||
# <string name="distribution" value="ggx"/>
|
||||
# <float name="alpha" value="0.05"/>
|
||||
# <float name="intIOR" value="1.46"/>
|
||||
# <rgb name="diffuseReflectance" value="1,0,0.5"/> <!-- default 0.5 -->
|
||||
# </bsdf>
|
||||
#
|
||||
|
||||
xml_tail = \
|
||||
"""
|
||||
<shape type="rectangle">
|
||||
<ref name="bsdf" id="surfaceMaterial"/>
|
||||
<transform name="toWorld">
|
||||
<scale x="10" y="10" z="1"/>
|
||||
<translate x="0" y="0" z="-0.5"/>
|
||||
</transform>
|
||||
</shape>
|
||||
|
||||
<shape type="rectangle">
|
||||
<transform name="toWorld">
|
||||
<scale x="10" y="10" z="1"/>
|
||||
<lookat origin="-1,1,20" target="0,0,0" up="0,0,1"/>
|
||||
</transform>
|
||||
<emitter type="area">
|
||||
<rgb name="radiance" value="6,6,6"/>
|
||||
</emitter>
|
||||
</shape>
|
||||
|
||||
|
||||
</scene>
|
||||
"""
|
||||
# <shape type="sphere">
|
||||
# <point name="center" x="5" y="5" z="5"/>
|
||||
# <float name="radius" value="1.5"/>
|
||||
# <emitter type="area">
|
||||
# <rgb name="radiance" value="3,3,3"/>
|
||||
# </emitter>
|
||||
# </shape>
|
||||
|
||||
## <point name="center" x="2" y="2" z="2"/>
|
||||
# <shape type="rectangle">
|
||||
# <transform name="toWorld">
|
||||
# <scale x="10" y="10" z="1"/>
|
||||
# <lookat origin="-4,4,20" target="0,0,0" up="0,0,1"/>
|
||||
# </transform>
|
||||
# <emitter type="area">
|
||||
# <rgb name="radiance" value="6,6,6"/>
|
||||
# </emitter>
|
||||
# </shape>
|
||||
#
|
||||
|
||||
def colormap(x, y, z):
|
||||
vec = np.array([x, y, z])
|
||||
vec = np.clip(vec, 0.001, 1.0)
|
||||
norm = np.sqrt(np.sum(vec ** 2))
|
||||
vec /= norm
|
||||
return [vec[0], vec[1], vec[2]]
|
||||
|
||||
|
||||
def standardize_bbox(pcl, points_per_object):
|
||||
pt_indices = np.random.choice(pcl.shape[0], points_per_object, replace=False)
|
||||
np.random.shuffle(pt_indices)
|
||||
pcl = pcl[pt_indices] # n by 3
|
||||
mins = np.amin(pcl, axis=0)
|
||||
maxs = np.amax(pcl, axis=0)
|
||||
center = (mins + maxs) / 2.
|
||||
scale = np.amax(maxs - mins)
|
||||
print("Center: {}, Scale: {}".format(center, scale))
|
||||
result = ((pcl - center) / scale).astype(np.float32) # [-0.5, 0.5]
|
||||
return result
|
||||
|
||||
|
||||
# only for debugging reasons
|
||||
def writeply(vertices, ply_file):
|
||||
sv = np.shape(vertices)
|
||||
points = []
|
||||
for v in range(sv[0]):
|
||||
vertex = vertices[v]
|
||||
points.append("%f %f %f\n" % (vertex[0], vertex[1], vertex[2]))
|
||||
print(np.shape(points))
|
||||
file = open(ply_file, "w")
|
||||
file.write('''ply
|
||||
format ascii 1.0
|
||||
element vertex %d
|
||||
property float x
|
||||
property float y
|
||||
property float z
|
||||
end_header
|
||||
%s
|
||||
''' % (len(vertices), "".join(points)))
|
||||
file.close()
|
||||
|
||||
|
||||
# as done in https://gist.github.com/drakeguan/6303065
|
||||
def ConvertEXRToJPG(exrfile, jpgfile):
|
||||
File = OpenEXR.InputFile(exrfile)
|
||||
PixType = Imath.PixelType(Imath.PixelType.FLOAT)
|
||||
DW = File.header()['dataWindow']
|
||||
Size = (DW.max.x - DW.min.x + 1, DW.max.y - DW.min.y + 1)
|
||||
|
||||
rgb = [np.fromstring(File.channel(c, PixType), dtype=np.float32) for c in 'RGB']
|
||||
for i in range(3):
|
||||
print(rgb[i].max(), rgb[i].min())
|
||||
rgb[i] = np.where(rgb[i] <= 0.0031308,
|
||||
(rgb[i] * 12.92) * 255.0,
|
||||
(1.055 * (rgb[i] ** (1.0 / 2.4)) - 0.055) * 255.0)
|
||||
|
||||
rgb8 = [Image.frombytes("F", Size, c.tostring()).convert("L") for c in rgb]
|
||||
# rgb8 = [Image.fromarray(c.astype(int)) for c in rgb]
|
||||
Image.merge("RGB", rgb8).save(jpgfile, "PNG")
|
||||
##, quality=95)
|
||||
img = Image.open(jpgfile)
|
||||
img = trim(img)
|
||||
img.save(jpgfile)
|
||||
|
||||
|
||||
def render_cubes2png(pcl, filename, colorm=[24,107,239], vs_size=0.5,
|
||||
sample_count=256, out_width=800, out_height=600,
|
||||
lookat_1=3, lookat_2=3, lookat_3=3, trim_img=0):
|
||||
xml_head = xml_head_segment.format(
|
||||
lookat_1, lookat_2, lookat_3,
|
||||
sample_count, out_width, out_height)
|
||||
xml_segments = [xml_head]
|
||||
print('color: ', colorm)
|
||||
for i in range(pcl.shape[0]):
|
||||
color = [c/255.0 for c in colorm]
|
||||
xml_segments.append(xml_cube_segment.format(
|
||||
vs_size, vs_size, vs_size,
|
||||
pcl[i, 0], pcl[i, 1], pcl[i, 2],
|
||||
*color))
|
||||
xml_segments.append(xml_tail)
|
||||
|
||||
xml_content = str.join('', xml_segments)
|
||||
|
||||
xmlFile = '/tmp/tmp_%s.xml'%random_str # ("%s/xml/%s.xml" % (folder, filename))
|
||||
exrFile = '/tmp/tmp_%s.exr'%random_str ##("%s/exr/%s.exr" % (folder, filename))
|
||||
## png = ("%s/%s.png" % (folder, filename))
|
||||
with open(xmlFile, 'w') as f:
|
||||
f.write(xml_content)
|
||||
f.close()
|
||||
print('save as xmlFile: ', xmlFile)
|
||||
|
||||
if not os.path.exists(os.path.dirname(exrFile)):
|
||||
os.makedirs(os.path.dirname(exrFile))
|
||||
#subprocess.run([PATH_TO_MITSUBA2, '-o', exrFile, xmlFile])
|
||||
png = filename
|
||||
if not os.path.exists(os.path.dirname(png)):
|
||||
os.makedirs(os.path.dirname(png))
|
||||
|
||||
#print(['Converting EXR to PNG ...', png])
|
||||
#ConvertEXRToJPG(exrFile, png)
|
||||
scene = mi.load_file(xmlFile)
|
||||
image = mi.render(scene) ##, spp=256)
|
||||
mi.util.write_bitmap(png, image)
|
||||
if trim_img:
|
||||
img = Image.open(png)
|
||||
img = trim(img)
|
||||
img.save(png)
|
||||
|
||||
return png
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if (len(sys.argv) < 2):
|
||||
print('filename to npy/ply is not passed as argument. terminated.')
|
||||
raise ValueError
|
||||
|
||||
pathToFile = sys.argv[1]
|
||||
|
||||
|
||||
main(pathToFile)
|
418
utils/render_mitsuba_pc.py
Normal file
418
utils/render_mitsuba_pc.py
Normal file
|
@ -0,0 +1,418 @@
|
|||
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
#
|
||||
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
|
||||
# and proprietary rights in and to this software, related documentation
|
||||
# and any modifications thereto. Any use, reproduction, disclosure or
|
||||
# distribution of this software and related documentation without an express
|
||||
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
|
||||
|
||||
import numpy as np
|
||||
import mitsuba as mi
|
||||
mi.set_variant("cuda_ad_rgb")
|
||||
from loguru import logger
|
||||
import sys, os, subprocess
|
||||
import copy
|
||||
import OpenEXR
|
||||
import Imath
|
||||
from PIL import Image
|
||||
## from plyfile import PlyData, PlyElement
|
||||
import torch
|
||||
import open3d as o3d
|
||||
from PIL import Image, ImageChops
|
||||
import time
|
||||
random_str = hex(int(time.time() + 12345))[2:]
|
||||
PATH_TO_MITSUBA2 = "/home/xzeng/code/mitsuba2/build/dist/mitsuba" ## Codes/mitsuba2/build/dist/mitsuba" # mitsuba exectuable
|
||||
|
||||
# replaced by command line arguments
|
||||
def standardize_bbox_based_on(pcl, eps):
|
||||
pcl = pcl.numpy()[:, [0,2,1]]
|
||||
eps = eps.numpy()[:, [0,2,1]]
|
||||
pcl, center, scale = standardize_bbox(pcl, return_center_scale=1)
|
||||
eps = (eps - center) / scale if eps is not None else None
|
||||
offset = - 0.475 - pcl[:,2].min()
|
||||
eps[:,2] += offset
|
||||
return torch.from_numpy(eps)
|
||||
|
||||
# PATH_TO_NPY = 'pcl_ex.npy' # the tensor to load
|
||||
def rotate_pts(pts, r, axis=1, do_transform=0, is_point_flow_data=1, eps=None):
|
||||
assert(len(pts.shape) == 2), f'require N,3 tensor, get: {pts.shape}'
|
||||
## logger.info('rotating pts: {}, get eps: {} ', pts.shape, eps is not None )
|
||||
is_tensor = torch.is_tensor(pts)
|
||||
if not is_tensor:
|
||||
pts = torch.from_numpy(pts)
|
||||
if eps is not None and not torch.is_tensor(eps):
|
||||
eps = torch.from_numpy(eps)
|
||||
if do_transform:
|
||||
pcl = pts.cpu().numpy()
|
||||
eps = eps.cpu().numpy() if eps is not None else None
|
||||
if not is_point_flow_data:
|
||||
pcl[:,0] *= -1
|
||||
pcl = pcl[:, [2,1,0]]
|
||||
|
||||
if eps is not None:
|
||||
eps[:,0] *= -1
|
||||
eps = eps[:, [2,1,0]]
|
||||
|
||||
pcl, center, scale = standardize_bbox(pcl, return_center_scale=1)
|
||||
eps = (eps - center) / scale if eps is not None else None
|
||||
pcl = pcl[:, [2, 0, 1]]
|
||||
pcl[:,0] *= -1
|
||||
pcl[:,2] += 0.0125
|
||||
if eps is not None:
|
||||
eps = eps[:, [2, 0, 1]]
|
||||
eps[:,0] *= -1
|
||||
eps[:,2] += 0.0125
|
||||
|
||||
offset = - 0.475 - pcl[:,2].min()
|
||||
pcl[:,2] += offset
|
||||
if eps is not None:
|
||||
eps[:,2] += offset
|
||||
pts = torch.from_numpy(pcl)
|
||||
eps = torch.from_numpy(eps) if eps is not None else None
|
||||
|
||||
pcl = o3d.geometry.PointCloud()
|
||||
pcl.points = o3d.utility.Vector3dVector(pts.cpu())
|
||||
if axis == 1:
|
||||
R = pcl.get_rotation_matrix_from_xyz((0, - r * np.pi / 2, 0))
|
||||
elif axis == 2:
|
||||
R = pcl.get_rotation_matrix_from_xyz((0, 0, - r * np.pi / 2))
|
||||
elif axis == 0:
|
||||
R = pcl.get_rotation_matrix_from_xyz((- r * np.pi / 2, 0, 0))
|
||||
|
||||
#mesh_r = copy.deepcopy(pcl)
|
||||
#mesh_r.rotate(R, center=(0, 0, 0))
|
||||
#pts = np.asarray(mesh_r.points)
|
||||
|
||||
h_center = w_center = 0
|
||||
center = np.array([h_center, w_center, 0]).reshape(-1,3)
|
||||
pts = np.matmul(pts.numpy() - center, R.T) + center
|
||||
eps = np.matmul(eps.numpy() - center, R.T) + center if eps is not None else eps
|
||||
|
||||
if is_tensor:
|
||||
pts = torch.from_numpy(pts)
|
||||
eps = torch.from_numpy(eps) if eps is not None and not torch.is_tensor(eps) else eps
|
||||
|
||||
if eps is not None:
|
||||
return pts, eps
|
||||
return pts
|
||||
|
||||
# note that sampler is changed to 'independent' and the ldrfilm is changed to hdrfilm
|
||||
xml_head_segment = \
|
||||
"""
|
||||
<scene version="0.6.0">
|
||||
<integrator type="path">
|
||||
<integer name="maxDepth" value="-1"/>
|
||||
</integrator>
|
||||
<sensor type="perspective">
|
||||
<float name="farClip" value="100"/>
|
||||
<float name="nearClip" value="0.1"/>
|
||||
<transform name="toWorld">
|
||||
<lookat origin="{},{},{}" target="0,0,0" up="0,0,1"/>
|
||||
</transform>
|
||||
<float name="fov" value="25"/>
|
||||
<sampler type="ldsampler">
|
||||
<integer name="sampleCount" value="{}"/>
|
||||
</sampler>
|
||||
<film type="hdrfilm">
|
||||
<integer name="width" value="{}"/>
|
||||
<integer name="height" value="{}"/>
|
||||
<rfilter type="gaussian"/>
|
||||
</film>
|
||||
</sensor>
|
||||
|
||||
<bsdf type="roughplastic" id="surfaceMaterial">
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.05"/>
|
||||
<float name="intIOR" value="1.46"/>
|
||||
<rgb name="diffuseReflectance" value="1,1,1"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
|
||||
"""
|
||||
|
||||
# I also use a smaller point size
|
||||
xml_ball_segment = ['']*10
|
||||
xml_ball_segment[0] = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="{}"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="diffuse">
|
||||
<rgb name="reflectance" value="{},{},{}"/>
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
xml_ball_segment[1] = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="{}"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="plastic" >
|
||||
<float name="intIOR" value="2.0"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
|
||||
|
||||
xml_ball_segment[2] = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="{}"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="plastic" >
|
||||
<float name="intIOR" value="1.9"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
|
||||
xml_ball_segment[3] = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="{}"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="roughplastic" >
|
||||
<float name="intIOR" value="1.9"/>
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.2"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
xml_ball_segment[4] = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="{}"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="roughplastic" >
|
||||
<float name="intIOR" value="1.6"/>
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.2"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
xml_ball_segment[5] = \
|
||||
"""
|
||||
<shape type="sphere">
|
||||
<float name="radius" value="{}"/>
|
||||
<transform name="toWorld">
|
||||
<translate x="{}" y="{}" z="{}"/>
|
||||
</transform>
|
||||
<bsdf type="roughplastic">
|
||||
<float name="intIOR" value="1.7"/>
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value="0.2"/>
|
||||
<rgb name="diffuseReflectance" value="{},{},{}"/> <!-- default 0.5 -->
|
||||
</bsdf>
|
||||
</shape>
|
||||
"""
|
||||
xml_tail = \
|
||||
"""
|
||||
<shape type="rectangle">
|
||||
<ref name="bsdf" id="surfaceMaterial"/>
|
||||
<transform name="toWorld">
|
||||
<scale x="10" y="10" z="1"/>
|
||||
<translate x="0" y="0" z="-0.5"/>
|
||||
</transform>
|
||||
</shape>
|
||||
|
||||
<shape type="rectangle">
|
||||
<transform name="toWorld">
|
||||
<scale x="10" y="10" z="1"/>
|
||||
<lookat origin="-1,1,20" target="0,0,0" up="0,0,1"/>
|
||||
</transform>
|
||||
<emitter type="area">
|
||||
<rgb name="radiance" value="6,6,6"/>
|
||||
</emitter>
|
||||
</shape>
|
||||
</scene>
|
||||
"""
|
||||
def trim(im):
|
||||
bg = Image.new(im.mode, im.size, im.getpixel((0,0))) ##border)
|
||||
diff = ImageChops.difference(im, bg)
|
||||
bbox = diff.getbbox()
|
||||
if bbox:
|
||||
return im.crop(bbox)
|
||||
else:
|
||||
return im
|
||||
|
||||
|
||||
def colormap(x, y, z):
|
||||
if torch.is_tensor(x):
|
||||
x = x.cpu().numpy()
|
||||
vec = np.array([x, y, z])
|
||||
vec = np.clip(vec, 0.001, 1.0)
|
||||
norm = np.sqrt(np.sum(vec ** 2))
|
||||
vec /= norm
|
||||
return [vec[0], vec[1], vec[2]]
|
||||
|
||||
|
||||
def standardize_bbox(pcl, return_center_scale=0):
|
||||
#pt_indices = np.random.choice(pcl.shape[0], points_per_object, replace=False)
|
||||
#np.random.shuffle(pt_indices)
|
||||
#pcl = pcl[pt_indices] # n by 3
|
||||
if torch.is_tensor(pcl):
|
||||
pcl = pcl.numpy()
|
||||
mins = np.amin(pcl, axis=0)
|
||||
maxs = np.amax(pcl, axis=0)
|
||||
center = (mins + maxs) / 2.
|
||||
scale = np.amax(maxs - mins)
|
||||
#print("Center: {}, Scale: {}".format(center, scale))
|
||||
result = ((pcl - center) / scale).astype(np.float32) # [-0.5, 0.5]
|
||||
if return_center_scale:
|
||||
return result, center, scale
|
||||
return result
|
||||
|
||||
|
||||
# only for debugging reasons
|
||||
def writeply(vertices, ply_file):
|
||||
sv = np.shape(vertices)
|
||||
points = []
|
||||
for v in range(sv[0]):
|
||||
vertex = vertices[v]
|
||||
points.append("%f %f %f\n" % (vertex[0], vertex[1], vertex[2]))
|
||||
print(np.shape(points))
|
||||
file = open(ply_file, "w")
|
||||
file.write('''ply
|
||||
format ascii 1.0
|
||||
element vertex %d
|
||||
property float x
|
||||
property float y
|
||||
property float z
|
||||
end_header
|
||||
%s
|
||||
''' % (len(vertices), "".join(points)))
|
||||
file.close()
|
||||
|
||||
|
||||
# as done in https://gist.github.com/drakeguan/6303065
|
||||
def ConvertEXRToJPG(exrfile, jpgfile, trim_img):
|
||||
File = OpenEXR.InputFile(exrfile)
|
||||
PixType = Imath.PixelType(Imath.PixelType.FLOAT)
|
||||
DW = File.header()['dataWindow']
|
||||
Size = (DW.max.x - DW.min.x + 1, DW.max.y - DW.min.y + 1)
|
||||
|
||||
rgb = [np.fromstring(File.channel(c, PixType), dtype=np.float32) for c in 'RGB']
|
||||
for i in range(3):
|
||||
rgb[i] = np.where(rgb[i] <= 0.0031308,
|
||||
(rgb[i] * 12.92) * 255.0,
|
||||
(1.055 * (rgb[i] ** (1.0 / 2.4)) - 0.055) * 255.0)
|
||||
|
||||
rgb8 = [Image.frombytes("F", Size, c.tostring()).convert("L") for c in rgb]
|
||||
Image.merge("RGB", rgb8).save(jpgfile, "PNG") ##JPEG", quality=95)
|
||||
img = Image.open(jpgfile)
|
||||
if trim_img:
|
||||
img = trim(img)
|
||||
img.save(jpgfile)
|
||||
|
||||
def pts2png(input_pts, file_name, colorm=[24,107,239],
|
||||
skip_if_exists=False, is_color_list=False,
|
||||
sample_count=256, out_width=1600, out_height=1200,
|
||||
ball_size=0.025, do_standardize=0, same_computed_loc_color=0, material_id=0, precomputed_color=None,
|
||||
output_xml_file=None,
|
||||
use_loc_color=False, lookat_1=3, lookat_2=3, lookat_3=3, do_transform=1, trim_img=0):
|
||||
"""
|
||||
Argus:
|
||||
input_pts: (B,N,3) the points to be render
|
||||
file_name: list; output image name
|
||||
"""
|
||||
assert(len(input_pts.shape) == 3), f'expect: B,N,3; get: {input_pts.shape}'
|
||||
assert(type(file_name) is list), f'require file_name as list'
|
||||
xml_head = xml_head_segment.format(
|
||||
lookat_1, lookat_2, lookat_3,
|
||||
sample_count, out_width, out_height)
|
||||
input_pts = input_pts.cpu()
|
||||
# print('get shape; ', input_pts.shape)
|
||||
color_list = []
|
||||
for pcli in range(0, input_pts.shape[0]):
|
||||
xmlFile = '/tmp/tmp_%s.xml'%random_str if output_xml_file is None else output_xml_file
|
||||
# ("%s/xml/%s.xml" % (folder, filename))
|
||||
exrFile = '/tmp/tmp_%s.exr'%random_str ##("%s/exr/%s.exr" % (folder, filename))
|
||||
png = file_name[pcli]
|
||||
if skip_if_exists and os.path.exists(png):
|
||||
print(f'find png: {png}, skip ')
|
||||
continue
|
||||
pcl = input_pts[pcli, :, :]
|
||||
if do_transform:
|
||||
pcl = standardize_bbox(pcl)
|
||||
pcl = pcl[:, [2, 0, 1]]
|
||||
pcl[:, 0] *= -1
|
||||
pcl[:, 2] += 0.0125
|
||||
|
||||
offset = - 0.475 - pcl[:,2].min()
|
||||
pcl[:,2] += offset
|
||||
if do_standardize:
|
||||
pcl = standardize_bbox(pcl)
|
||||
offset = - 0.475 - pcl[:,2].min()
|
||||
pcl[:,2] += offset
|
||||
|
||||
xml_segments = [xml_head]
|
||||
for i in range(pcl.shape[0]):
|
||||
if precomputed_color is not None:
|
||||
color = precomputed_color[i]
|
||||
elif use_loc_color and not same_computed_loc_color:
|
||||
color = colormap(pcl[i, 0] + 0.5, pcl[i, 1] + 0.5, pcl[i, 2] + 0.5 - 0.0125)
|
||||
elif use_loc_color and same_computed_loc_color:
|
||||
if pcli == 0:
|
||||
color = colormap(pcl[i, 0] + 0.5, pcl[i, 1] + 0.5, pcl[i, 2] + 0.5 - 0.0125)
|
||||
color_list.append(color)
|
||||
else:
|
||||
color = color_list[i] # same color as first shape
|
||||
elif is_color_list:
|
||||
color = colorm[pcli]
|
||||
color = [c/255.0 for c in color]
|
||||
else:
|
||||
color = [c/255.0 for c in colorm]
|
||||
xml_segments.append(xml_ball_segment[material_id].format(
|
||||
ball_size,
|
||||
pcl[i, 0], pcl[i, 1], pcl[i, 2], *color))
|
||||
## print('using color: ', color)
|
||||
xml_segments.append(xml_tail)
|
||||
|
||||
xml_content = str.join('', xml_segments)
|
||||
|
||||
if not os.path.exists(os.path.dirname(xmlFile)):
|
||||
os.makedirs(os.path.dirname(xmlFile))
|
||||
with open(xmlFile, 'w') as f:
|
||||
f.write(xml_content)
|
||||
logger.info('[render_mitsuba_pc] write output at: {}', xmlFile)
|
||||
f.close()
|
||||
|
||||
if not os.path.exists(os.path.dirname(exrFile)):
|
||||
os.makedirs(os.path.dirname(exrFile))
|
||||
if not os.path.exists(os.path.dirname(png)):
|
||||
os.makedirs(os.path.dirname(png))
|
||||
logger.info('*'*20 + f'{png}' +'*'*20)
|
||||
# mitsuba2
|
||||
#subprocess.run([PATH_TO_MITSUBA2, '-o', exrFile, xmlFile])
|
||||
#ConvertEXRToJPG(exrFile, png, trim_img)
|
||||
scene = mi.load_file(xmlFile)
|
||||
image = mi.render(scene) ##, spp=256)
|
||||
mi.util.write_bitmap(png, image)
|
||||
if trim_img:
|
||||
img = Image.open(png)
|
||||
img.save(png)
|
||||
|
||||
return png
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if (len(sys.argv) < 2):
|
||||
print('filename to npy/ply is not passed as argument. terminated.')
|
||||
raise ValueError
|
||||
|
||||
pathToFile = sys.argv[1]
|
||||
|
||||
|
||||
main(pathToFile)
|
128
utils/render_voxel_cubes.py
Normal file
128
utils/render_voxel_cubes.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
#
|
||||
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
|
||||
# and proprietary rights in and to this software, related documentation
|
||||
# and any modifications thereto. Any use, reproduction, disclosure or
|
||||
# distribution of this software and related documentation without an express
|
||||
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
|
||||
|
||||
import os
|
||||
import numpy as np
|
||||
import open3d as o3d
|
||||
import sys
|
||||
import torch
|
||||
import point_cloud_utils as pcu
|
||||
from PIL import Image
|
||||
|
||||
sys.path.append('.')
|
||||
import torch
|
||||
from utils._render_mitsuba_cubes import render_cubes2png
|
||||
# from script.paper.vis_mesh.render_mitsuba import reformat_ply
|
||||
def reformat_ply(input, output, r=0, is_point_flow_data=0,
|
||||
ascii=False, write_normal=False, fixed_trimesh=1):
|
||||
m = open3d.io.read_triangle_mesh(input)
|
||||
pcl = np.asarray(m.vertices)
|
||||
if not is_point_flow_data:
|
||||
pcl[:,0] *= -1
|
||||
pcl = pcl[:, [2,1,0]]
|
||||
|
||||
pcl = standardize_bbox(pcl)
|
||||
pcl = pcl[:, [2, 0, 1]]
|
||||
pcl[:,0] *= -1
|
||||
pcl[:,2] += 0.0125
|
||||
|
||||
offset = - 0.475 - pcl[:,2].min()
|
||||
pcl[:,2] += offset
|
||||
m.vertices = open3d.utility.Vector3dVector(pcl)
|
||||
|
||||
R = m.get_rotation_matrix_from_xyz((0, 0, - r * np.pi / 2))
|
||||
mesh_r = copy.deepcopy(m)
|
||||
mesh_r.rotate(R, center=(0, 0, 0))
|
||||
## o3d.visualization.draw_geometries([mesh_r])
|
||||
open3d.io.write_triangle_mesh(output, mesh_r, write_ascii=ascii, write_vertex_normals=False)
|
||||
if fixed_trimesh:
|
||||
mesh = trimesh.load_mesh(output) ## '../models/featuretype.STL')
|
||||
trimesh.repair.fix_inversion(mesh)
|
||||
trimesh.repair.fix_normals(mesh)
|
||||
mesh.export(output)
|
||||
logger.info(f'load {input}, write as {output}; ascii={ascii}, write_normal: {write_normal}')
|
||||
return output
|
||||
|
||||
|
||||
def get_vpts(cubes):
|
||||
import kaolin
|
||||
v,f = kaolin.ops.conversions.voxelgrids_to_cubic_meshes(cubes) ##voxelgrids_to_trianglemeshes(voxel_volume)
|
||||
v = [vi.cpu() for vi in v]
|
||||
f = [fi.cpu() for fi in f]
|
||||
return v, f
|
||||
|
||||
def create_dir(output_path):
|
||||
if not os.path.exists(output_path):
|
||||
os.makedirs(output_path)
|
||||
|
||||
def convert_cube_2_mesh(voxel_size, center_list, output_path, overwrite=0, colorm=[93,64,211], rotate=None, config={}):
|
||||
scale = 0.5 * (center_list.max() - center_list.min())
|
||||
pcl = center_list
|
||||
mins = np.amin(pcl, axis=0).reshape(1,pcl.shape[-1]) ##np.amin(pcl, axis=1)[:, None, :], axis=0)[None, None, :]
|
||||
maxs = np.amax(pcl, axis=0).reshape(1,pcl.shape[-1]) ##np.amin(pcl, axis=1)[:, None, :], axis=0)[None, None, :]
|
||||
|
||||
center = ( mins + maxs ) / 2.
|
||||
scale = np.amax(maxs-mins)
|
||||
|
||||
center_list = (center_list - center) / scale ## (center_list.max() - center_list.min())
|
||||
|
||||
center_list = center_list[:,[2,0,1]]
|
||||
center_list[:,0] *= -1 #center_list
|
||||
offset = - 0.475 - center_list[:,2].min()
|
||||
center_list[:,2] += offset
|
||||
if rotate is not None:
|
||||
pts = torch.from_numpy(center_list)
|
||||
pcl = o3d.geometry.PointCloud()
|
||||
pcl.points = o3d.utility.Vector3dVector(pts.cpu())
|
||||
R = pcl.get_rotation_matrix_from_xyz((0, 0, - rotate * np.pi / 2))
|
||||
center = np.array([0, 0, 0]).reshape(-1,3)
|
||||
pts = np.matmul(pts.numpy() - center, R.T) + center
|
||||
center_list = pts
|
||||
|
||||
output_name = output_path
|
||||
print('center_list: ', center_list.shape)
|
||||
if not os.path.exists(os.path.dirname(output_name)):
|
||||
os.makedirs(os.path.dirname(output_name))
|
||||
if os.path.exists(output_name) and not overwrite:
|
||||
print(f'find rendered output: {output_name}, skip')
|
||||
return
|
||||
out = render_cubes2png(pcl=center_list, filename=output_name,
|
||||
vs_size=0.9*voxel_size/scale, colorm=colorm, **config)
|
||||
print(' save as: ', out)
|
||||
#img = Image.open(out)
|
||||
#img.show()
|
||||
print('output_path: ', output_path)
|
||||
return out
|
||||
|
||||
def create_unit_cube():
|
||||
voxelgrid = torch.tensor([1], device='cuda', dtype=torch.uint8).view(1,1,1,1)
|
||||
v, f = get_vpts(voxelgrid)
|
||||
v = v[0]
|
||||
f = f[0]
|
||||
v = v - 0.5 # [-0.5, 0.5]
|
||||
print('v: ', v)
|
||||
print('f: ', v)
|
||||
output_name = './script/paper/vis_voxel_exp/unit_cube.ply'
|
||||
print('save output as: ', output_name)
|
||||
pcu.save_mesh_vf(output_name, v.numpy(), f.numpy())
|
||||
reformat_ply(output_name, output_name, r=0)
|
||||
|
||||
def write_small_cube():
|
||||
mesh_compare = './script/paper/vis_voxel_exp/unit_cube2.ply'
|
||||
m = o3d.io.read_triangle_mesh(mesh_compare)
|
||||
pcl = np.asarray(m.vertices) * 0.5
|
||||
m.vertices = o3d.utility.Vector3dVector(pcl) ##.float()) ## torch.from_numpy(pcl))
|
||||
o3d.io.write_triangle_mesh(mesh_compare.replace('.ply', 'w1.ply'),
|
||||
m, write_ascii=True, write_vertex_normals=True)
|
||||
|
||||
# write_small_cube()
|
||||
if __name__ == '__main__':
|
||||
input_path = '/home/xzeng/plots/voxel_exp/voxel_cube/raw'
|
||||
index = "3 328 91 83 74 73 64 63 54 51 48 45 41 30 22"
|
||||
convert_cube_2_mesh(input_path, index)
|
||||
# create_unit_cube()
|
Loading…
Reference in a new issue