mat_pretty_printer.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import gdb
  2. import numpy as np
  3. from enum import Enum
  4. np.set_printoptions(suppress=True) # prevent numpy exponential notation on print, default False
  5. # np.set_printoptions(threshold=sys.maxsize)
  6. def conv(obj, t):
  7. return gdb.parse_and_eval(f'({t})({obj})')
  8. def booli(obj):
  9. return conv(str(obj).lower(), 'bool')
  10. def stri(obj):
  11. s = f'"{obj}"'
  12. return conv(s.translate(s.maketrans('\n', ' ')), 'char*')
  13. class MagicValues(Enum):
  14. MAGIC_VAL = 0x42FF0000
  15. AUTO_STEP = 0
  16. CONTINUOUS_FLAG = 1 << 14
  17. SUBMATRIX_FLAG = 1 << 15
  18. class MagicMasks(Enum):
  19. MAGIC_MASK = 0xFFFF0000
  20. TYPE_MASK = 0x00000FFF
  21. DEPTH_MASK = 7
  22. class Depth(Enum):
  23. CV_8U = 0
  24. CV_8S = 1
  25. CV_16U = 2
  26. CV_16S = 3
  27. CV_32S = 4
  28. CV_32F = 5
  29. CV_64F = 6
  30. CV_16F = 7
  31. def create_enum(n):
  32. def make_type(depth, cn):
  33. return depth.value + ((cn - 1) << 3)
  34. defs = [(f'{depth.name}C{i}', make_type(depth, i)) for depth in Depth for i in range(1, n + 1)]
  35. return Enum('Type', defs)
  36. Type = create_enum(512)
  37. class Flags:
  38. def depth(self):
  39. return Depth(self.flags & MagicMasks.DEPTH_MASK.value)
  40. def dtype(self):
  41. depth = self.depth()
  42. ret = None
  43. if depth == Depth.CV_8U:
  44. ret = (np.uint8, 'uint8_t')
  45. elif depth == Depth.CV_8S:
  46. ret = (np.int8, 'int8_t')
  47. elif depth == Depth.CV_16U:
  48. ret = (np.uint16, 'uint16_t')
  49. elif depth == Depth.CV_16S:
  50. ret = (np.int16, 'int16_t')
  51. elif depth == Depth.CV_32S:
  52. ret = (np.int32, 'int32_t')
  53. elif depth == Depth.CV_32F:
  54. ret = (np.float32, 'float')
  55. elif depth == Depth.CV_64F:
  56. ret = (np.float64, 'double')
  57. elif depth == Depth.CV_16F:
  58. ret = (np.float16, 'float16')
  59. return ret
  60. def type(self):
  61. return Type(self.flags & MagicMasks.TYPE_MASK.value)
  62. def channels(self):
  63. return ((self.flags & (511 << 3)) >> 3) + 1
  64. def is_continuous(self):
  65. return (self.flags & MagicValues.CONTINUOUS_FLAG.value) != 0
  66. def is_submatrix(self):
  67. return (self.flags & MagicValues.SUBMATRIX_FLAG.value) != 0
  68. def __init__(self, flags):
  69. self.flags = flags
  70. def __iter__(self):
  71. return iter({
  72. 'type': stri(self.type().name),
  73. 'is_continuous': booli(self.is_continuous()),
  74. 'is_submatrix': booli(self.is_submatrix())
  75. }.items())
  76. class Size:
  77. def __init__(self, ptr):
  78. self.ptr = ptr
  79. def dims(self):
  80. return int((self.ptr - 1).dereference())
  81. def to_numpy(self):
  82. return np.array([int(self.ptr[i]) for i in range(self.dims())], dtype=np.int64)
  83. def __iter__(self):
  84. return iter({'size': stri(self.to_numpy())}.items())
  85. class Mat:
  86. def __init__(self, m, size, flags):
  87. (dtype, ctype) = flags.dtype()
  88. elsize = np.dtype(dtype).itemsize
  89. ptr = m['data']
  90. dataptr = int(ptr)
  91. length = (int(m['dataend']) - dataptr) // elsize
  92. start = (int(m['datastart']) - dataptr) // elsize
  93. if length == 0:
  94. self.mat = np.array([])
  95. self.view = self.mat
  96. return
  97. if dtype != np.float16:
  98. ctype = gdb.lookup_type(ctype)
  99. ptr = ptr.cast(ctype.array(length - 1).pointer()).dereference()
  100. self.mat = np.array([ptr[i] for i in range(length)], dtype=dtype)
  101. else:
  102. u16 = gdb.lookup_type('uint16_t')
  103. ptr = ptr.cast(u16.array(length - 1).pointer()).dereference()
  104. self.mat = np.array([ptr[i] for i in range(length)], dtype=np.uint16)
  105. self.mat = self.mat.view(np.float16)
  106. steps = np.asarray([int(m['step']['p'][i]) for i in range(size.dims())], dtype=np.int64)
  107. self.view = np.lib.stride_tricks.as_strided(self.mat[start:], shape=size.to_numpy(), strides=steps)
  108. def __iter__(self):
  109. return iter({'data': stri(self.view)}.items())
  110. class MatPrinter:
  111. """Print a cv::Mat"""
  112. def __init__(self, mat):
  113. self.mat = mat
  114. def views(self):
  115. m = self.mat
  116. flags = Flags(int(m['flags']))
  117. size = Size(m['size']['p'])
  118. data = Mat(m, size, flags)
  119. for x in [flags, size, data]:
  120. for k, v in x:
  121. yield 'view_' + k, v
  122. def real(self):
  123. m = self.mat
  124. for field in m.type.fields():
  125. k = field.name
  126. v = m[k]
  127. yield k, v
  128. # TODO: add an enum in interface.h with all cv::Mat element types and use that instead
  129. # yield 'test', gdb.parse_and_eval(f'(cv::MatTypes)0')
  130. def children(self): # TODO: hide real members under new child somehow
  131. yield from self.views()
  132. yield from self.real()
  133. def get_type(val):
  134. # Get the type.
  135. vtype = val.type
  136. # If it points to a reference, get the reference.
  137. if vtype.code == gdb.TYPE_CODE_REF:
  138. vtype = vtype.target()
  139. # Get the unqualified type, stripped of typedefs.
  140. vtype = vtype.unqualified().strip_typedefs()
  141. # Get the type name.
  142. typename = vtype.tag
  143. return typename
  144. def mat_printer(val):
  145. typename = get_type(val)
  146. if typename is None:
  147. return None
  148. if str(typename) == 'cv::Mat':
  149. return MatPrinter(val)
  150. gdb.pretty_printers.append(mat_printer)