text: """
  Renders mesh using OpenDr for visualization.
  """
  
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  
  import numpy as np
  import cv2
  
  from opendr.camera import ProjectPoints
  from opendr.renderer import ColoredRenderer
  from opendr.lighting import LambertianPointLight
  
  # newly added for depth rendering
  from opendr.renderer import DepthRenderer
  
  colors = {
      # colorbline/print/copy safe:
      'light_blue': [0.65098039, 0.74117647, 0.85882353],
      'light_pink': [.9, .7, .7],  # This is used to do no-3d
  }
  
  
  class SMPLRenderer(object):
      def __init__(self,
                   img_size=224,
                   flength=500.,
                   face_path="tf_smpl/smpl_faces.npy"):
          self.faces = np.load(face_path)
          self.w = img_size
          self.h = img_size
          self.flength = flength
  
      def __call__(self,
                   verts,
                   cam=None,
                   img=None,
                   do_alpha=False,
                   far=None,
                   near=None,
                   color_id=0,
                   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),
              #rt=np.array([np.pi, 0, 0]),
              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)
  
          imtmp = render_model(
              verts,
              self.faces,
              w,
              h,
              use_cam,
              do_alpha=do_alpha,
              img=img,
              far=far,
              near=near,
              color_id=color_id)
  
          return (imtmp * 255).astype('uint8')
      
      # newly added by CCJ for depth rendering;
      def depth_render(self,
                   max_dep,
                   verts,
                   cam=None,
                   far=None,
                   near=None,
                   img_size=None):
          
          dRenderer = DepthRenderer()
          dRenderer.camera=ProjectPoints(
              v=verts, 
              rt= np.zeros(3),
              t= np.zeros(3),
              f= cam[0] * np.ones(2),
              c= cam[1:3],
              k=np.zeros(5)
              )
          
          """
          cam is 3D [f, px, py]
          """
          if 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),
              #rt=np.array([np.pi, 0, 0]),
              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)
  
          #dRenderer.frustum={"near":1.,"far":5.,"width":self.width,"height":self.height}
          dRenderer.frustum={"near": near,"far": far,"width": w,"height": h}
          dRenderer.v = verts
          dRenderer.f = self.faces
          depthArr = dRenderer.r.copy()
          depthArr[depthArr > max_dep] = 0        
          depthArr = (depthArr / max_dep) * 255.0
          depthArr = depthArr.astype(np.uint8)
          return depthArr
  
  
      def rotated(self,
                  verts,
                  deg,
                  cam=None,
                  axis='y',
                  img=None,
                  do_alpha=True,
                  far=None,
                  near=None,
                  color_id=0,
                  img_size=None):
          import math
          if axis == 'y':
              around = cv2.Rodrigues(np.array([0, math.radians(deg), 0]))[0]
          elif axis == 'x':
              around = cv2.Rodrigues(np.array([math.radians(deg), 0, 0]))[0]
          else:
              around = cv2.Rodrigues(np.array([0, 0, math.radians(deg)]))[0]
          center = verts.mean(axis=0)
          new_v = np.dot((verts - center), around) + center
  
          return self.__call__(
              new_v,
              cam,
              img=img,
              do_alpha=do_alpha,
              far=far,
              near=near,
              img_size=img_size,
              color_id=color_id)
  
  
  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(120),
                      color=colors['light_pink']):
      # 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),
          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),
          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_id=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 else img
  
      if color_id is None:
          color = colors['light_blue']
      else:
          color_list = colors.values()
          color = color_list[color_id % len(color_list)]
  
      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
  
  
  # ------------------------------
  
  
  def get_original(proc_param, verts, cam, joints, img_size):
      img_size = proc_param['img_size']
      undo_scale = 1. / np.array(proc_param['scale'])
      print ("[***] undo_scale = {}".format(undo_scale))
      cam_s = cam[0]
      cam_pos = cam[1:]
      principal_pt = np.array([img_size, img_size]) / 2.
      
      flength = 500. # 500. in hmr code;
      #NOTE:??? CCJ: Not sure yet ???
      #flength = 600. # changed to 600 from 500 for rendering SURREAL data;
      tz = flength / (0.5 * img_size * cam_s)
      trans = np.hstack([cam_pos, tz])
      vert_shifted = verts + trans
  
      start_pt = proc_param['start_pt'] - 0.5 * img_size
      final_principal_pt = (principal_pt + start_pt) * undo_scale
      cam_for_render = np.hstack(
          [np.mean(flength * undo_scale), final_principal_pt])
  
      # This is in padded image.
      # kp_original = (joints + proc_param['start_pt']) * undo_scale
      # Subtract padding from joints.
      margin = int(img_size / 2)
      kp_original = (joints + proc_param['start_pt'] - margin) * undo_scale
  
      return cam_for_render, vert_shifted, kp_original
  
  
  def draw_skeleton(input_image, joints, draw_edges=True, vis=None, radius=None):
      """
      joints is 3 x 19. but if not will transpose it.
      0: Right ankle
      1: Right knee
      2: Right hip
      3: Left hip
      4: Left knee
      5: Left ankle
      6: Right wrist
      7: Right elbow
      8: Right shoulder
      9: Left shoulder
      10: Left elbow
      11: Left wrist
      12: Neck
      13: Head top
      14: nose
      15: left_eye
      16: right_eye
      17: left_ear
      18: right_ear
      """
      import numpy as np
      import cv2
  
      if radius is None:
          radius = max(4, (np.mean(input_image.shape[:2]) * 0.01).astype(int))
  
      colors = {
          'pink': np.array([197, 27, 125]),  # L lower leg
          'light_pink': np.array([233, 163, 201]),  # L upper leg
          'light_green': np.array([161, 215, 106]),  # L lower arm
          'green': np.array([77, 146, 33]),  # L upper arm
          'red': np.array([215, 48, 39]),  # head
          'light_red': np.array([252, 146, 114]),  # head
          'light_orange': np.array([252, 141, 89]),  # chest
          'purple': np.array([118, 42, 131]),  # R lower leg
          'light_purple': np.array([175, 141, 195]),  # R upper
          'light_blue': np.array([145, 191, 219]),  # R lower arm
          'blue': np.array([69, 117, 180]),  # R upper arm
          'gray': np.array([130, 130, 130]),  #
          'white': np.array([255, 255, 255]),  #
      }
  
      image = input_image.copy()
      input_is_float = False
  
      if np.issubdtype(image.dtype, np.float32):
          input_is_float = True
          max_val = image.max()
          if max_val <= 2.:  # should be 1 but sometimes it's slightly above 1
              image = (image * 255).astype(np.uint8)
          else:
              image = (image).astype(np.uint8)
              print ("[ ????? as np.uint8]")
  
      if joints.shape[0] != 2:
          joints = joints.T
      joints = np.round(joints).astype(int)
  
      jcolors = [
          'light_pink', 'light_pink', 'light_pink', 'pink', 'pink', 'pink',
          'light_blue', 'light_blue', 'light_blue', 'blue', 'blue', 'blue',
          'purple', 'purple', 'red', 'green', 'green', 'white', 'white'
      ]
  
      if joints.shape[1] == 19:
          # parent indices -1 means no parents
          parents = np.array([
              1, 2, 8, 9, 3, 4, 7, 8, 12, 12, 9, 10, 14, -1, 13, -1, -1, 15, 16
          ])
          # Left is light and right is dark
          ecolors = {
              0: 'light_pink',
              1: 'light_pink',
              2: 'light_pink',
              3: 'pink',
              4: 'pink',
              5: 'pink',
              6: 'light_blue',
              7: 'light_blue',
              8: 'light_blue',
              9: 'blue',
              10: 'blue',
              11: 'blue',
              12: 'purple',
              17: 'light_green',
              18: 'light_green',
              14: 'purple'
          }
      elif joints.shape[1] == 14:
          parents = np.array([
              #1, 2, 8, 9,3, 4, 7, 8, 12,12,9,10,13,-1
              1, 2, 8, 9,3, 4, 7, 8, -1,-1,9,10,13,-1
          ])
          ecolors = {
              0: 'light_pink', # 0: Right ankle
              1: 'light_pink', # 1: Right knee
              2: 'light_pink', # 2: Right hip 
              3: 'pink', # Left hip
              4: 'pink', # Left knee
              5: 'pink', # left ankle
              6: 'light_blue', # right wrist
              7: 'light_blue', # right elbow
              #8: 'light_blue', # not used, due to no parent;
              #9: 'blue', # not used, due to no parent;
              10: 'blue', # left elbow
              11: 'blue', # left wrist
              12: 'purple' # neck
          }
  
  
      else:
          print('Unknown skeleton!!')
          import ipdb
          ipdb.set_trace()
  
      for child in xrange(len(parents)):
          point = joints[:, child]
          # If invisible skip
          if vis is not None and vis[child] == 0:
              continue
          if draw_edges:
              cv2.circle(image, (point[0], point[1]), radius, colors['white'],
                         -1)
              cv2.circle(image, (point[0], point[1]), radius - 1,
                         colors[jcolors[child]], -1)
          else:
              # cv2.circle(image, (point[0], point[1]), 5, colors['white'], 1)
              cv2.circle(image, (point[0], point[1]), radius - 1,
                         colors[jcolors[child]], 1)
              # cv2.circle(image, (point[0], point[1]), 5, colors['gray'], -1)
          pa_id = parents[child]
          if draw_edges and pa_id >= 0:
              if vis is not None and vis[pa_id] == 0:
                  continue
              point_pa = joints[:, pa_id]
              cv2.circle(image, (point_pa[0], point_pa[1]), radius - 1,
                         colors[jcolors[pa_id]], -1)
              if child not in ecolors.keys():
                  print('bad')
                  import ipdb
                  ipdb.set_trace()
              cv2.line(image, (point[0], point[1]), (point_pa[0], point_pa[1]),
                       colors[ecolors[child]], radius - 2)
  
      # Convert back in original dtype
      if input_is_float:
          if max_val <= 1.:
              image = image.astype(np.float32) / 255.
          else:
              image = image.astype(np.float32)
  
      return image
  
  
  def draw_text(input_image, content):
      """
      content is a dict. draws key: val on image
      Assumes key is str, val is float
      """
      import numpy as np
      import cv2
      image = input_image.copy()
      input_is_float = False
      if np.issubdtype(image.dtype, np.float):
          input_is_float = True
          image = (image * 255).astype(np.uint8)
  
      black = np.array([0, 0, 0])
      margin = 15
      start_x = 5
      start_y = margin
      for key in sorted(content.keys()):
          text = "%s: %.2g" % (key, content[key])
          cv2.putText(image, text, (start_x, start_y), 0, 0.45, black)
          start_y += margin
  
      if input_is_float:
          image = image.astype(np.float32) / 255.
      return image
  