bvh.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import re, os, ntpath
  2. import numpy as np
  3. channelmap = {
  4. 'Xrotation': 'x',
  5. 'Yrotation': 'y',
  6. 'Zrotation': 'z'
  7. }
  8. channelmap_inv = {
  9. 'x': 'Xrotation',
  10. 'y': 'Yrotation',
  11. 'z': 'Zrotation',
  12. }
  13. ordermap = {
  14. 'x': 0,
  15. 'y': 1,
  16. 'z': 2,
  17. }
  18. def load(filename, order=None):
  19. f = open(filename, "r")
  20. i = 0
  21. active = -1
  22. end_site = False
  23. names = []
  24. orients = np.array([]).reshape((0, 4))
  25. offsets = np.array([]).reshape((0, 3))
  26. parents = np.array([], dtype=int)
  27. # Parse the file, line by line
  28. for line in f:
  29. if "HIERARCHY" in line: continue
  30. if "MOTION" in line: continue
  31. rmatch = re.match(r"ROOT (\w+)", line)
  32. if rmatch:
  33. names.append(rmatch.group(1))
  34. offsets = np.append(offsets, np.array([[0, 0, 0]]), axis=0)
  35. orients = np.append(orients, np.array([[1, 0, 0, 0]]), axis=0)
  36. parents = np.append(parents, active)
  37. active = (len(parents) - 1)
  38. continue
  39. if "{" in line: continue
  40. if "}" in line:
  41. if end_site:
  42. end_site = False
  43. else:
  44. active = parents[active]
  45. continue
  46. offmatch = re.match(r"\s*OFFSET\s+([\-\d\.e]+)\s+([\-\d\.e]+)\s+([\-\d\.e]+)", line)
  47. if offmatch:
  48. if not end_site:
  49. offsets[active] = np.array([list(map(float, offmatch.groups()))])
  50. continue
  51. chanmatch = re.match(r"\s*CHANNELS\s+(\d+)", line)
  52. if chanmatch:
  53. channels = int(chanmatch.group(1))
  54. if order is None:
  55. channelis = 0 if channels == 3 else 3
  56. channelie = 3 if channels == 3 else 6
  57. parts = line.split()[2 + channelis:2 + channelie]
  58. if any([p not in channelmap for p in parts]):
  59. continue
  60. order = "".join([channelmap[p] for p in parts])
  61. continue
  62. jmatch = re.match("\s*JOINT\s+(\w+)", line)
  63. if jmatch:
  64. names.append(jmatch.group(1))
  65. offsets = np.append(offsets, np.array([[0, 0, 0]]), axis=0)
  66. orients = np.append(orients, np.array([[1, 0, 0, 0]]), axis=0)
  67. parents = np.append(parents, active)
  68. active = (len(parents) - 1)
  69. continue
  70. if "End Site" in line:
  71. end_site = True
  72. continue
  73. fmatch = re.match("\s*Frames:\s+(\d+)", line)
  74. if fmatch:
  75. fnum = int(fmatch.group(1))
  76. positions = offsets[np.newaxis].repeat(fnum, axis=0)
  77. rotations = np.zeros((fnum, len(orients), 3))
  78. continue
  79. fmatch = re.match("\s*Frame Time:\s+([\d\.]+)", line)
  80. if fmatch:
  81. frametime = float(fmatch.group(1))
  82. continue
  83. dmatch = line.strip().split(' ')
  84. if dmatch:
  85. data_block = np.array(list(map(float, dmatch)))
  86. N = len(parents)
  87. fi = i
  88. if channels == 3:
  89. positions[fi, 0:1] = data_block[0:3]
  90. rotations[fi, :] = data_block[3:].reshape(N, 3)
  91. elif channels == 6:
  92. data_block = data_block.reshape(N, 6)
  93. positions[fi, :] = data_block[:, 0:3]
  94. rotations[fi, :] = data_block[:, 3:6]
  95. elif channels == 9:
  96. positions[fi, 0] = data_block[0:3]
  97. data_block = data_block[3:].reshape(N - 1, 9)
  98. rotations[fi, 1:] = data_block[:, 3:6]
  99. positions[fi, 1:] += data_block[:, 0:3] * data_block[:, 6:9]
  100. else:
  101. raise Exception("Too many channels! %i" % channels)
  102. i += 1
  103. f.close()
  104. return {
  105. 'rotations': rotations,
  106. 'positions': positions,
  107. 'offsets': offsets,
  108. 'parents': parents,
  109. 'names': names,
  110. 'order': order
  111. }
  112. def save_joint(f, data, t, i, save_order, order='zyx', save_positions=False):
  113. save_order.append(i)
  114. f.write("%sJOINT %s\n" % (t, data['names'][i]))
  115. f.write("%s{\n" % t)
  116. t += '\t'
  117. f.write("%sOFFSET %f %f %f\n" % (t, data['offsets'][i,0], data['offsets'][i,1], data['offsets'][i,2]))
  118. if save_positions:
  119. f.write("%sCHANNELS 6 Xposition Yposition Zposition %s %s %s \n" % (t,
  120. channelmap_inv[order[0]], channelmap_inv[order[1]], channelmap_inv[order[2]]))
  121. else:
  122. f.write("%sCHANNELS 3 %s %s %s\n" % (t,
  123. channelmap_inv[order[0]], channelmap_inv[order[1]], channelmap_inv[order[2]]))
  124. end_site = True
  125. for j in range(len(data['parents'])):
  126. if data['parents'][j] == i:
  127. t = save_joint(f, data, t, j, save_order, order=order, save_positions=save_positions)
  128. end_site = False
  129. if end_site:
  130. f.write("%sEnd Site\n" % t)
  131. f.write("%s{\n" % t)
  132. t += '\t'
  133. f.write("%sOFFSET %f %f %f\n" % (t, 0.0, 0.0, 0.0))
  134. t = t[:-1]
  135. f.write("%s}\n" % t)
  136. t = t[:-1]
  137. f.write("%s}\n" % t)
  138. return t
  139. def save(filename, data, frametime=1.0/60.0, save_positions=False):
  140. order = data['order']
  141. with open(filename, 'w') as f:
  142. t = ""
  143. f.write("%sHIERARCHY\n" % t)
  144. f.write("%sROOT %s\n" % (t, data['names'][0]))
  145. f.write("%s{\n" % t)
  146. t += '\t'
  147. f.write("%sOFFSET %f %f %f\n" % (t, data['offsets'][0,0], data['offsets'][0,1], data['offsets'][0,2]) )
  148. f.write("%sCHANNELS 6 Xposition Yposition Zposition %s %s %s \n" %
  149. (t, channelmap_inv[order[0]], channelmap_inv[order[1]], channelmap_inv[order[2]]))
  150. save_order = [0]
  151. for i in range(len(data['parents'])):
  152. if data['parents'][i] == 0:
  153. t = save_joint(f, data, t, i, save_order, order=order, save_positions=save_positions)
  154. t = t[:-1]
  155. f.write("%s}\n" % t)
  156. rots, poss = data['rotations'], data['positions']
  157. f.write("MOTION\n")
  158. f.write("Frames: %i\n" % len(rots));
  159. f.write("Frame Time: %f\n" % frametime);
  160. for i in range(rots.shape[0]):
  161. for j in save_order:
  162. if save_positions or j == 0:
  163. f.write("%f %f %f %f %f %f " % (
  164. poss[i,j,0], poss[i,j,1], poss[i,j,2],
  165. rots[i,j,ordermap[order[0]]], rots[i,j,ordermap[order[1]]], rots[i,j,ordermap[order[2]]]))
  166. else:
  167. f.write("%f %f %f " % (
  168. rots[i,j,ordermap[order[0]]], rots[i,j,ordermap[order[1]]], rots[i,j,ordermap[order[2]]]))
  169. f.write("\n")