1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
import gdb
import numpy as np
from enum import Enum
np.set_printoptions(suppress=True) # prevent numpy exponential notation on print, default False
# np.set_printoptions(threshold=sys.maxsize)
def conv(obj, t):
return gdb.parse_and_eval(f'({t})({obj})')
def booli(obj):
return conv(str(obj).lower(), 'bool')
def stri(obj):
s = f'"{obj}"'
return conv(s.translate(s.maketrans('\n', ' ')), 'char*')
class MagicValues(Enum):
MAGIC_VAL = 0x42FF0000
AUTO_STEP = 0
CONTINUOUS_FLAG = 1 << 14
SUBMATRIX_FLAG = 1 << 15
class MagicMasks(Enum):
MAGIC_MASK = 0xFFFF0000
TYPE_MASK = 0x00000FFF
DEPTH_MASK = 7
class Depth(Enum):
CV_8U = 0
CV_8S = 1
CV_16U = 2
CV_16S = 3
CV_32S = 4
CV_32F = 5
CV_64F = 6
CV_16F = 7
def create_enum(n):
def make_type(depth, cn):
return depth.value + ((cn - 1) << 3)
defs = [(f'{depth.name}C{i}', make_type(depth, i)) for depth in Depth for i in range(1, n + 1)]
return Enum('Type', defs)
Type = create_enum(512)
class Flags:
def depth(self):
return Depth(self.flags & MagicMasks.DEPTH_MASK.value)
def dtype(self):
depth = self.depth()
ret = None
if depth == Depth.CV_8U:
ret = (np.uint8, 'uint8_t')
elif depth == Depth.CV_8S:
ret = (np.int8, 'int8_t')
elif depth == Depth.CV_16U:
ret = (np.uint16, 'uint16_t')
elif depth == Depth.CV_16S:
ret = (np.int16, 'int16_t')
elif depth == Depth.CV_32S:
ret = (np.int32, 'int32_t')
elif depth == Depth.CV_32F:
ret = (np.float32, 'float')
elif depth == Depth.CV_64F:
ret = (np.float64, 'double')
elif depth == Depth.CV_16F:
ret = (np.float16, 'float16')
return ret
def type(self):
return Type(self.flags & MagicMasks.TYPE_MASK.value)
def channels(self):
return ((self.flags & (511 << 3)) >> 3) + 1
def is_continuous(self):
return (self.flags & MagicValues.CONTINUOUS_FLAG.value) != 0
def is_submatrix(self):
return (self.flags & MagicValues.SUBMATRIX_FLAG.value) != 0
def __init__(self, flags):
self.flags = flags
def __iter__(self):
return iter({
'type': stri(self.type().name),
'is_continuous': booli(self.is_continuous()),
'is_submatrix': booli(self.is_submatrix())
}.items())
class Size:
def __init__(self, ptr):
self.ptr = ptr
def dims(self):
return int((self.ptr - 1).dereference())
def to_numpy(self):
return np.array([int(self.ptr[i]) for i in range(self.dims())], dtype=np.int64)
def __iter__(self):
return iter({'size': stri(self.to_numpy())}.items())
class Mat:
def __init__(self, m, size, flags):
(dtype, ctype) = flags.dtype()
elsize = np.dtype(dtype).itemsize
shape = size.to_numpy()
steps = np.asarray([int(m['step']['p'][i]) for i in range(len(shape))], dtype=np.int64)
ptr = m['data']
# either we are default-constructed or sizes are zero
if int(ptr) == 0 or np.prod(shape * steps) == 0:
self.mat = np.array([])
self.view = self.mat
return
# we don't want to show excess brackets
if flags.channels() != 1:
shape = np.append(shape, flags.channels())
steps = np.append(steps, elsize)
# get the length of contiguous array from data to the last element of the matrix
length = 1 + np.sum((shape - 1) * steps) // elsize
if dtype != np.float16:
# read all elements into self.mat
ctype = gdb.lookup_type(ctype)
ptr = ptr.cast(ctype.array(length - 1).pointer()).dereference()
self.mat = np.array([ptr[i] for i in range(length)], dtype=dtype)
else:
# read as uint16_t and then reinterpret the bytes as float16
u16 = gdb.lookup_type('uint16_t')
ptr = ptr.cast(u16.array(length - 1).pointer()).dereference()
self.mat = np.array([ptr[i] for i in range(length)], dtype=np.uint16)
self.mat = self.mat.view(np.float16)
# numpy will do the heavy lifting of strided access
self.view = np.lib.stride_tricks.as_strided(self.mat, shape=shape, strides=steps)
def __iter__(self):
return iter({'data': stri(self.view)}.items())
class MatPrinter:
"""Print a cv::Mat"""
def __init__(self, mat):
self.mat = mat
def views(self):
m = self.mat
flags = Flags(int(m['flags']))
size = Size(m['size']['p'])
data = Mat(m, size, flags)
for x in [flags, size, data]:
for k, v in x:
yield 'view_' + k, v
def real(self):
m = self.mat
for field in m.type.fields():
k = field.name
v = m[k]
yield k, v
# TODO: add an enum in interface.h with all cv::Mat element types and use that instead
# yield 'test', gdb.parse_and_eval(f'(cv::MatTypes)0')
def children(self): # TODO: hide real members under new child somehow
yield from self.views()
yield from self.real()
def get_type(val):
# Get the type.
vtype = val.type
# If it points to a reference, get the reference.
if vtype.code == gdb.TYPE_CODE_REF:
vtype = vtype.target()
# Get the unqualified type, stripped of typedefs.
vtype = vtype.unqualified().strip_typedefs()
# Get the type name.
typename = vtype.tag
return typename
def mat_printer(val):
typename = get_type(val)
if typename is None:
return None
if str(typename) == 'cv::Mat':
return MatPrinter(val)
gdb.pretty_printers.append(mat_printer)
|