text: # Copyright (c) Facebook, Inc. and its affiliates.
  
  """
  Renders mesh using OpenDr / Pytorch-3d for visualization.
  Part of code is modified from https://github.com/akanazawa/hmr
  """
  
  import sys
  import numpy as np
  import cv2
  import pdb
  from PIL import Image, ImageDraw
  from opendr.camera import ProjectPoints
  from opendr.renderer import ColoredRenderer
  from opendr.lighting import LambertianPointLight
  
  
  class OpendrRenderer(object):
      def __init__(self,
                   img_size=224,
                   mesh_color=np.array([0.5, 0.5, 0.5]),):
  
          self.w = img_size
          self.h = img_size
          self.color = mesh_color
          self.img_size = img_size
          self.flength = 500.
  
      
      def render(self, verts, faces, bg_img):
          verts = verts.copy()
          faces = faces.copy()
  
          input_size = 500
  
          f = 5
  
          verts[:, 0] = (verts[:, 0] - input_size) / input_size
          verts[:, 1] = (verts[:, 1] - input_size) / input_size
  
          verts[:, 2] /= (5 * 112)
          verts[:, 2] += f
  
          cam_for_render = np.array([f, 1, 1]) * input_size
  
          rend_img = self.__call__(
              img=bg_img, cam=cam_for_render, 
              verts=verts, faces=faces, color=self.color)
          
          return rend_img
      
  
      def __call__(self,
                   verts,
                   faces,
                   cam=None,
                   img=None,
                   do_alpha=False,
                   far=None,
                   near=None,
                   color = np.array([0, 0, 255]),
                   img_size=None):
          """
          cam is 3D [f, px, py]
          """
          if img is not None:
              h, w = img.shape[:2]
          elif img_size is not None:
              h = img_size[0]
              w = img_size[1]
          else:
              h = self.h
              w = self.w
  
          if cam is None:
              cam = [self.flength, w / 2., h / 2.]
  
          use_cam = ProjectPoints(
              f=cam[0] * np.ones(2),
              rt=np.zeros(3),
              t=np.zeros(3),
              k=np.zeros(5),
              c=cam[1:3])
  
          if near is None:
              near = np.maximum(np.min(verts[:, 2]) - 25, 0.1)
          if far is None:
              far = np.maximum(np.max(verts[:, 2]) + 25, 25)
  
          return_value = render_model(
              verts,
              faces,
              w,
              h,
              use_cam,
              do_alpha=do_alpha,
              img=img,
              far=far,
              near=near,
              color=color)
  
          imtmp = return_value
          image = (imtmp * 255).astype('uint8')
          return image
  
  
  
  def _create_renderer(w=640,
                       h=480,
                       rt=np.zeros(3),
                       t=np.zeros(3),
                       f=None,
                       c=None,
                       k=None,
                       near=.5,
                       far=10.):
  
      f = np.array([w, w]) / 2. if f is None else f
      c = np.array([w, h]) / 2. if c is None else c
      k = np.zeros(5) if k is None else k
  
      rn = ColoredRenderer()
  
      rn.camera = ProjectPoints(rt=rt, t=t, f=f, c=c, k=k)
      rn.frustum = {'near': near, 'far': far, 'height': h, 'width': w}
      return rn
  
  
  def _rotateY(points, angle):
      """Rotate the points by a specified angle."""
      ry = np.array([[np.cos(angle), 0., np.sin(angle)], [0., 1., 0.],
                     [-np.sin(angle), 0., np.cos(angle)]])
      return np.dot(points, ry)
  
  
  def simple_renderer(rn,
                      verts,
                      faces,
                      yrot=np.radians(70),
                      color=np.array([0, 0, 255])
                      ):
  
      # Rendered model color
      rn.set(v=verts, f=faces, vc=color, bgcolor=np.ones(3))
      albedo = rn.vc
  
      # Construct Back Light (on back right corner)
      rn.vc = LambertianPointLight(
          f=rn.f,
          v=rn.v,
          num_verts=len(rn.v),
          light_pos=_rotateY(np.array([-200, -100, -100]), yrot),
          vc=albedo,
          light_color=np.array([1, 1, 1]))
  
      # Construct Left Light
      rn.vc += LambertianPointLight(
          f=rn.f,
          v=rn.v,
          num_verts=len(rn.v),
          # light_pos=_rotateY(np.array([800, 10, 300]), yrot),
          light_pos=_rotateY(np.array([800, 10, 300]), yrot),
          vc=albedo,
          light_color=np.array([1, 1, 1]))
  
      # Construct Right Light
      rn.vc += LambertianPointLight(
          f=rn.f,
          v=rn.v,
          num_verts=len(rn.v),
          light_pos=_rotateY(np.array([-500, 500, 1000]), yrot),
          # light_pos=_rotateY(np.array([-500, 500, 1000]), yrot),
          vc=albedo,
          light_color=np.array([.7, .7, .7]))
   
      return rn.r
  
  
  def get_alpha(imtmp, bgval=1.):
      h, w = imtmp.shape[:2]
      alpha = (~np.all(imtmp == bgval, axis=2)).astype(imtmp.dtype)
  
      b_channel, g_channel, r_channel = cv2.split(imtmp)
  
      im_RGBA = cv2.merge((b_channel, g_channel, r_channel, alpha.astype(
          imtmp.dtype)))
      return im_RGBA
  
  
  def append_alpha(imtmp):
      alpha = np.ones_like(imtmp[:, :, 0]).astype(imtmp.dtype)
      if np.issubdtype(imtmp.dtype, np.uint8):
          alpha = alpha * 255
      b_channel, g_channel, r_channel = cv2.split(imtmp)
      im_RGBA = cv2.merge((b_channel, g_channel, r_channel, alpha))
      return im_RGBA
  
  
  def render_model(verts,
                   faces,
                   w,
                   h,
                   cam,
                   near=0.5,
                   far=25,
                   img=None,
                   do_alpha=False,
                   color=None):
      rn = _create_renderer(
          w=w, h=h, near=near, far=far, rt=cam.rt, t=cam.t, f=cam.f, c=cam.c)
  
      # Uses img as background, otherwise white background.
      if img is not None:
          rn.background_image = img / 255. if img.max() > 1.1 else img
  
      imtmp = simple_renderer(rn, verts, faces, color=color)
      
      # If white bg, make transparent.
      if img is None and do_alpha:
          imtmp = get_alpha(imtmp)
      elif img is not None and do_alpha:
          imtmp = append_alpha(imtmp)
      
      return imtmp