| | import os |
| | import cv2 |
| | import numpy as np |
| | from mpl_toolkits.mplot3d import Axes3D |
| | import matplotlib.pyplot as plt |
| | import matplotlib as mpl |
| | import os |
| | import sys |
| | os.environ["PYOPENGL_PLATFORM"] = "egl" |
| | from pytorch3d.structures import Meshes, Pointclouds |
| | from pytorch3d.renderer import ( |
| | PointLights, |
| | DirectionalLights, |
| | PerspectiveCameras, |
| | Materials, |
| | SoftPhongShader, |
| | RasterizationSettings, |
| | MeshRenderer, |
| | MeshRendererWithFragments, |
| | MeshRasterizer, |
| | TexturesVertex, |
| | PointsRasterizationSettings, |
| | PointsRenderer, |
| | PointsRasterizer, |
| | AlphaCompositor |
| | ) |
| | import torch |
| | import torch.nn as nn |
| |
|
| | def vis_keypoints_with_skeleton(img, kps, kps_lines, kp_thresh=0.4, alpha=1): |
| | |
| | cmap = plt.get_cmap('rainbow') |
| | colors = [cmap(i) for i in np.linspace(0, 1, len(kps_lines) + 2)] |
| | colors = [(c[2] * 255, c[1] * 255, c[0] * 255) for c in colors] |
| |
|
| | |
| | kp_mask = np.copy(img) |
| |
|
| | |
| | for l in range(len(kps_lines)): |
| | i1 = kps_lines[l][0] |
| | i2 = kps_lines[l][1] |
| | p1 = kps[0, i1].astype(np.int32), kps[1, i1].astype(np.int32) |
| | p2 = kps[0, i2].astype(np.int32), kps[1, i2].astype(np.int32) |
| | if kps[2, i1] > kp_thresh and kps[2, i2] > kp_thresh: |
| | cv2.line( |
| | kp_mask, p1, p2, |
| | color=colors[l], thickness=2, lineType=cv2.LINE_AA) |
| | if kps[2, i1] > kp_thresh: |
| | cv2.circle( |
| | kp_mask, p1, |
| | radius=3, color=colors[l], thickness=-1, lineType=cv2.LINE_AA) |
| | if kps[2, i2] > kp_thresh: |
| | cv2.circle( |
| | kp_mask, p2, |
| | radius=3, color=colors[l], thickness=-1, lineType=cv2.LINE_AA) |
| |
|
| | |
| | return cv2.addWeighted(img, 1.0 - alpha, kp_mask, alpha, 0) |
| |
|
| | def vis_keypoints(img, kps, alpha=1): |
| | |
| | cmap = plt.get_cmap('rainbow') |
| | colors = [cmap(i) for i in np.linspace(0, 1, len(kps) + 2)] |
| | colors = [(c[2] * 255, c[1] * 255, c[0] * 255) for c in colors] |
| |
|
| | |
| | kp_mask = np.copy(img) |
| |
|
| | |
| | for i in range(len(kps)): |
| | p = kps[i][0].astype(np.int32), kps[i][1].astype(np.int32) |
| | cv2.circle(kp_mask, p, radius=3, color=colors[i], thickness=-1, lineType=cv2.LINE_AA) |
| |
|
| | |
| | return cv2.addWeighted(img, 1.0 - alpha, kp_mask, alpha, 0) |
| |
|
| |
|
| | def render_mesh(mesh, face, cam_param, bkg, blend_ratio=1.0, return_bg_mask=False, R=None, T=None, return_fragments=False): |
| | mesh = mesh.cuda()[None,:,:] |
| | face = torch.LongTensor(face.astype(np.int64)).cuda()[None,:,:] |
| | cam_param = {k: v.cuda()[None,:] for k,v in cam_param.items()} |
| | render_shape = (bkg.shape[0], bkg.shape[1]) |
| |
|
| | batch_size, vertex_num = mesh.shape[:2] |
| | textures = TexturesVertex(verts_features=torch.ones((batch_size,vertex_num,3)).float().cuda()) |
| | mesh = torch.stack((-mesh[:,:,0], -mesh[:,:,1], mesh[:,:,2]),2) |
| | mesh = Meshes(mesh, face, textures) |
| |
|
| | if R is None: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device='cuda', |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).cuda().view(1,2)) |
| | else: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device='cuda', |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).cuda().view(1,2), |
| | R=R, |
| | T=T) |
| | |
| | raster_settings = RasterizationSettings(image_size=render_shape, blur_radius=0.0, faces_per_pixel=1, bin_size=0) |
| | rasterizer = MeshRasterizer(cameras=cameras, raster_settings=raster_settings).cuda() |
| | lights = PointLights(device='cuda') |
| | shader = SoftPhongShader(device='cuda', cameras=cameras, lights=lights) |
| | materials = Materials( |
| | device='cuda', |
| | specular_color=[[0.0, 0.0, 0.0]], |
| | shininess=0.0 |
| | ) |
| |
|
| | |
| | with torch.no_grad(): |
| | renderer = MeshRendererWithFragments(rasterizer=rasterizer, shader=shader) |
| | images, fragments = renderer(mesh, materials=materials) |
| | |
| | |
| | is_bkg = (fragments.zbuf <= 0).float().cpu().numpy()[0] |
| | render = images[0,:,:,:3].cpu().numpy() |
| | fg = render * blend_ratio + bkg/255 * (1 - blend_ratio) |
| | render = fg * (1 - is_bkg) * 255 + bkg * is_bkg |
| | ret = [render] |
| | if return_bg_mask: |
| | ret.append(is_bkg) |
| | if return_fragments: |
| | ret.append(fragments) |
| | return tuple(ret) |
| |
|
| |
|
| | def rasterize_mesh(mesh, face, cam_param, height, width, return_bg_mask=False, R=None, T=None): |
| | mesh = mesh.cuda()[None,:,:] |
| | face = face.long().cuda()[None,:,:] |
| | cam_param = {k: v.cuda()[None,:] for k,v in cam_param.items()} |
| | render_shape = (height, width) |
| |
|
| | batch_size, vertex_num = mesh.shape[:2] |
| | textures = TexturesVertex(verts_features=torch.ones((batch_size,vertex_num,3)).float().cuda()) |
| | mesh = torch.stack((-mesh[:,:,0], -mesh[:,:,1], mesh[:,:,2]),2) |
| | mesh = Meshes(mesh, face, textures) |
| |
|
| | if R is None: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device='cuda', |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).cuda().view(1,2)) |
| | else: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device='cuda', |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).cuda().view(1,2), |
| | R=R, |
| | T=T) |
| | |
| | raster_settings = RasterizationSettings(image_size=render_shape, blur_radius=0.0, faces_per_pixel=1, bin_size=0) |
| | rasterizer = MeshRasterizer(cameras=cameras, raster_settings=raster_settings).cuda() |
| |
|
| | |
| | fragments = rasterizer(mesh) |
| |
|
| | ret = [fragments] |
| |
|
| | if return_bg_mask: |
| | |
| | is_bkg = (fragments.zbuf <= 0).float().cpu().numpy()[0] |
| | ret.append(is_bkg) |
| |
|
| | return tuple(ret) |
| |
|
| |
|
| | def rasterize_points(points, cam_param, height, width, return_bg_mask=False, R=None, T=None, to_cpu=False, points_per_pixel=5, radius=0.01): |
| | points = torch.stack((-points[:, 0], -points[:, 1], points[:, 2]), 1) |
| | device = points.device |
| | if len(points.shape) == 2: |
| | points = [points] |
| | pointclouds = Pointclouds(points=points) |
| | cam_param = {k: v.to(device)[None,:] for k,v in cam_param.items()} |
| | render_shape = (height, width) |
| |
|
| | if R is None: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device=device, |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).to(device).view(1,2)) |
| | else: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device=device, |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).to(device).view(1,2), |
| | R=R, |
| | T=T) |
| | |
| | raster_settings = PointsRasterizationSettings(image_size=render_shape, radius=radius, points_per_pixel=points_per_pixel, max_points_per_bin=82000) |
| | rasterizer = PointsRasterizer(cameras=cameras, raster_settings=raster_settings).to(device) |
| |
|
| | |
| | fragments = rasterizer(pointclouds) |
| |
|
| | |
| | ret = [fragments] |
| | if return_bg_mask: |
| | if to_cpu: |
| | is_bkg = (fragments.zbuf <= 0).all(dim=-1, keepdim=True).float().cpu().numpy()[0] |
| | else: |
| | is_bkg = (fragments.zbuf <= 0).all(dim=-1, keepdim=True).float()[0] |
| | ret.append(is_bkg) |
| | |
| | return tuple(ret) |
| |
|
| |
|
| | def render_points(points, cam_param, bkg, blend_ratio=1.0, return_bg_mask=False, R=None, T=None, return_fragments=False, rgbs=None): |
| | points = torch.stack((-points[:, 0], -points[:, 1], points[:, 2]), 1) |
| | if rgbs is None: |
| | rgbs = torch.ones_like(points) |
| | if len(points.shape) == 2: |
| | points = [points] |
| | rgbs = [rgbs] |
| | pointclouds = Pointclouds(points=points, features=rgbs).cuda() |
| | cam_param = {k: v.cuda()[None,:] for k,v in cam_param.items()} |
| | render_shape = (bkg.shape[0], bkg.shape[1]) |
| |
|
| | if R is None: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device='cuda', |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).cuda().view(1,2)) |
| | else: |
| | cameras = PerspectiveCameras(focal_length=cam_param['focal'], |
| | principal_point=cam_param['princpt'], |
| | device='cuda', |
| | in_ndc=False, |
| | image_size=torch.LongTensor(render_shape).cuda().view(1,2), |
| | R=R, |
| | T=T) |
| | |
| | raster_settings = PointsRasterizationSettings(image_size=render_shape, radius=0.01, points_per_pixel=5) |
| | rasterizer = PointsRasterizer(cameras=cameras, raster_settings=raster_settings).cuda() |
| |
|
| | |
| | with torch.no_grad(): |
| | fragments = rasterizer(pointclouds) |
| | renderer = PointsRenderer(rasterizer=rasterizer, compositor=AlphaCompositor(background_color=(0, 0, 0))) |
| | images = renderer(pointclouds) |
| | |
| | |
| | is_bkg = (fragments.zbuf <= 0).all(dim=-1, keepdim=True).float().cpu().numpy()[0] |
| | render = images[0,:,:,:3].cpu().numpy() |
| | fg = render * blend_ratio + bkg/255 * (1 - blend_ratio) |
| | render = fg * (1 - is_bkg) * 255 + bkg * is_bkg |
| |
|
| | ret = [render] |
| | if return_bg_mask: |
| | ret.append(is_bkg) |
| | if return_fragments: |
| | ret.append(fragments) |
| | return tuple(ret) |
| |
|
| |
|
| | class RenderMesh(nn.Module): |
| | def __init__(self, image_size, obj_filename=None, faces=None, device='cpu'): |
| | super(RenderMesh, self).__init__() |
| | self.device = device |
| | self.image_size = image_size |
| | if obj_filename is not None: |
| | verts, faces, aux = load_obj(obj_filename, load_textures=False) |
| | self.faces = faces.verts_idx |
| | elif faces is not None: |
| | import numpy as np |
| | self.faces = torch.tensor(faces.astype(np.int32)) |
| | else: |
| | raise NotImplementedError('Must have faces.') |
| | self.raster_settings = RasterizationSettings(image_size=image_size, blur_radius=0.0, faces_per_pixel=1) |
| | self.lights = PointLights(device=device, location=[[0.0, 0.0, 3.0]]) |
| |
|
| | def _build_cameras(self, transform_matrix, focal_length, principal_point=None, intr=None): |
| | batch_size = transform_matrix.shape[0] |
| | screen_size = torch.tensor( |
| | [self.image_size, self.image_size], device=self.device |
| | ).float()[None].repeat(batch_size, 1) |
| | if principal_point is None: |
| | principal_point = torch.zeros(batch_size, 2, device=self.device).float() |
| | |
| | |
| | if intr is None: |
| | cameras_kwargs = { |
| | 'principal_point': principal_point, 'focal_length': focal_length, |
| | 'image_size': screen_size, 'device': self.device, |
| | } |
| | else: |
| | cameras_kwargs = { |
| | 'principal_point': principal_point, 'focal_length': torch.tensor([intr[0, 0], intr[1, 1]]).unsqueeze(0), |
| | 'image_size': screen_size, 'device': self.device, |
| | } |
| | cameras = PerspectiveCameras(**cameras_kwargs, R=transform_matrix[:, :3, :3], T=transform_matrix[:, :3, 3]) |
| | return cameras |
| |
|
| | def forward( |
| | self, vertices, cameras=None, transform_matrix=None, focal_length=None, principal_point=None, only_rasterize=False, intr=None, |
| | ): |
| | if cameras is None: |
| | cameras = self._build_cameras(transform_matrix, focal_length, principal_point=principal_point, intr=intr) |
| | faces = self.faces[None].repeat(vertices.shape[0], 1, 1) |
| | |
| | verts_rgb = torch.ones_like(vertices) |
| | textures = TexturesVertex(verts_features=verts_rgb.to(self.device)) |
| | mesh = Meshes( |
| | verts=vertices.to(self.device), |
| | faces=faces.to(self.device), |
| | textures=textures |
| | ) |
| | renderer = MeshRendererWithFragments( |
| | rasterizer=MeshRasterizer(cameras=cameras, raster_settings=self.raster_settings), |
| | shader=SoftPhongShader(cameras=cameras, lights=self.lights, device=self.device) |
| | ) |
| | render_results, fragments = renderer(mesh) |
| | render_results = render_results.permute(0, 3, 1, 2) |
| | if only_rasterize: |
| | return fragments |
| | images = render_results[:, :3] |
| | alpha_images = render_results[:, 3:] |
| | images[alpha_images.expand(-1, 3, -1, -1)<0.5] = 0.0 |
| | return images*255, alpha_images |
| |
|
| |
|
| | class RenderPoints(nn.Module): |
| | def __init__(self, image_size, obj_filename=None, device='cpu'): |
| | super(RenderPoints, self).__init__() |
| | self.device = device |
| | self.image_size = image_size |
| | if obj_filename is not None: |
| | verts = load_obj(obj_filename, load_textures=False) |
| | self.raster_settings = PointsRasterizationSettings(image_size=image_size, radius=0.01, points_per_pixel=1) |
| | self.lights = PointLights(device=device, location=[[0.0, 0.0, 3.0]]) |
| |
|
| | def _build_cameras(self, transform_matrix, focal_length, principal_point=None): |
| | batch_size = transform_matrix.shape[0] |
| | screen_size = torch.tensor( |
| | [self.image_size, self.image_size], device=self.device |
| | ).float()[None].repeat(batch_size, 1) |
| | if principal_point is None: |
| | principal_point = torch.zeros(batch_size, 2, device=self.device).float() |
| | |
| | |
| | cameras_kwargs = { |
| | 'principal_point': principal_point, 'focal_length': focal_length, |
| | 'image_size': screen_size, 'device': self.device, |
| | } |
| | cameras = PerspectiveCameras(**cameras_kwargs, R=transform_matrix[:, :3, :3], T=transform_matrix[:, :3, 3]) |
| | return cameras |
| |
|
| | def forward( |
| | self, vertices, cameras=None, transform_matrix=None, focal_length=None, principal_point=None, only_rasterize=False |
| | ): |
| | if cameras is None: |
| | cameras = self._build_cameras(transform_matrix, focal_length, principal_point=principal_point) |
| | |
| | verts_rgb = torch.ones_like(vertices) |
| | pointclouds = Pointclouds(points=vertices, features=verts_rgb).cuda() |
| |
|
| | |
| | rasterizer = PointsRasterizer(cameras=cameras, raster_settings=self.raster_settings).cuda() |
| | if only_rasterize: |
| | fragments = rasterizer(pointclouds) |
| | return fragments |
| | renderer = PointsRenderer(rasterizer=rasterizer, compositor=AlphaCompositor(background_color=(0, 0, 0))) |
| | render_results = renderer(pointclouds).permute(0, 3, 1, 2) |
| | images = render_results[:, :3] |
| | alpha_images = render_results[:, 3:] |
| |
|
| | return images*255, alpha_images |