c4dynamics 1.0.80__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of c4dynamics might be problematic. Click here for more details.

c4dynamics/__init__.py CHANGED
@@ -49,12 +49,12 @@ from . import rotmat
49
49
  from .utils.const import *
50
50
  from .utils.math import *
51
51
  from .utils.gen_gif import gen_gif
52
- from .utils.cprint import print
52
+ from .utils.cprint import cprint
53
53
 
54
54
  #
55
55
  # body objects
56
56
  ##
57
- from .body.datapoint import datapoint, create
57
+ from .body.datapoint import datapoint, fdatapoint, create
58
58
  from .body.rigidbody import rigidbody
59
59
 
60
60
 
@@ -70,5 +70,5 @@ from . import detectors
70
70
  #
71
71
  # version
72
72
  ##
73
- __version__ = '1.0.80'
73
+ __version__ = '1.1.00'
74
74
 
@@ -5,6 +5,7 @@ import c4dynamics as c4d
5
5
  from c4dynamics.eqm import int3
6
6
  # from c4dynamics.src.main.py.eqm import eqm3
7
7
 
8
+
8
9
  def create(X):
9
10
  if len(X) > 6:
10
11
  rb = c4d.rigidbody()
@@ -20,8 +21,6 @@ class datapoint:
20
21
 
21
22
 
22
23
 
23
-
24
-
25
24
  # .. automethod:: c4dynamics.datapoint
26
25
  # the datapoint object is the most basic element in the translational dynamics domain.
27
26
  # --
@@ -64,47 +63,12 @@ class datapoint:
64
63
 
65
64
  # The arguments to the range constructor must be integers
66
65
 
66
+ __slots__ = ['x', 'y', 'z', 'vx', 'vy', 'vz', 'ax', 'ay', 'az', 'mass'
67
+ , 'x0', 'y0', 'z0', 'vx0', 'vy0', 'vz0'
68
+ , '_data', '_vardata', '_didx', '__dict__']
67
69
 
68
70
 
69
- #
70
- # position
71
- # NOTE: why actually there should be a docstring to every one of the variables.
72
- # unless otherwise mentioned it should transparent to users. and only attributes
73
- # - methods and variables for user ex should be docced.
74
- ##
75
- x = 0
76
- ''' float; Cartesian coordinate representing the x-position of the datapoint. '''
77
- y = 0
78
- ''' float; Cartesian coordinate representing the y-position of the datapoint. '''
79
- z = 0
80
- ''' float; Cartesian coordinate representing the z-position of the datapoint. '''
81
-
82
- #
83
- # velocity
84
- ##
85
- vx = 0
86
- ''' float; Component of velocity along the x-axis. '''
87
- vy = 0
88
- ''' float; Component of velocity along the y-axis. '''
89
- vz = 0
90
- ''' float; Component of velocity along the z-axis. '''
91
-
92
- #
93
- # acceleration
94
- ##
95
- ax = 0
96
- ''' float; Component of acceleration along the x-axis. '''
97
- ay = 0
98
- ''' float; Component of acceleration along the y-axis. '''
99
- az = 0
100
- ''' float; Component of acceleration along the z-axis. '''
101
-
102
- #
103
- # mass
104
- ##
105
- mass = 1.0
106
- ''' float; Mass of the datapoint. '''
107
-
71
+ # https://stackoverflow.com/questions/472000/usage-of-slots#:~:text=The%20proper%20use%20of%20__,one%20dict%20for%20every%20object.%5D
108
72
  # https://www.geeksforgeeks.org/getter-and-setter-in-python/
109
73
  # https://stackoverflow.com/questions/4555932/public-or-private-attribute-in-python-what-is-the-best-way
110
74
  # https://stackoverflow.com/questions/17576009/python-class-property-use-setter-but-evade-getter
@@ -114,6 +78,44 @@ class datapoint:
114
78
 
115
79
  def __init__(self, **kwargs):
116
80
  # reset mutable attributes:
81
+ #
82
+ # position
83
+ # NOTE: why actually there should be a docstring to every one of the variables.
84
+ # unless otherwise mentioned it should transparent to users. and only attributes
85
+ # - methods and variables for user ex should be docced.
86
+ ##
87
+ self.x = 0
88
+ ''' float; Cartesian coordinate representing the x-position of the datapoint. '''
89
+ self.y = 0
90
+ ''' float; Cartesian coordinate representing the y-position of the datapoint. '''
91
+ self.z = 0
92
+ ''' float; Cartesian coordinate representing the z-position of the datapoint. '''
93
+
94
+ #
95
+ # velocity
96
+ ##
97
+ self.vx = 0
98
+ ''' float; Component of velocity along the x-axis. '''
99
+ self.vy = 0
100
+ ''' float; Component of velocity along the y-axis. '''
101
+ self.vz = 0
102
+ ''' float; Component of velocity along the z-axis. '''
103
+
104
+ #
105
+ # acceleration
106
+ ##
107
+ self.ax = 0
108
+ ''' float; Component of acceleration along the x-axis. '''
109
+ self.ay = 0
110
+ ''' float; Component of acceleration along the y-axis. '''
111
+ self.az = 0
112
+ ''' float; Component of acceleration along the z-axis. '''
113
+
114
+ #
115
+ # mass
116
+ ##
117
+ self.mass = 1.0
118
+ ''' float; Mass of the datapoint. '''
117
119
  #
118
120
  # variables for storage
119
121
  ##
@@ -122,8 +124,10 @@ class datapoint:
122
124
  self._data = [] # for permanent class variables (t, x, y .. )
123
125
  self._vardata = {} # for user additional variables
124
126
 
125
- self.__dict__.update(kwargs)
126
-
127
+ # self.__dict__.update(kwargs)
128
+ for k, v in kwargs.items():
129
+ setattr(self, k, v)
130
+
127
131
 
128
132
  self.x0 = self.x
129
133
  self.y0 = self.y
@@ -562,7 +566,9 @@ class datapoint:
562
566
 
563
567
 
564
568
  '''
565
- # TODO: add the docstring the example of the kalman variables store from the detect track exmaple.
569
+ # TODO show example of multiple vars
570
+ # maybe the example of the kalman variables store
571
+ # from the detect track exmaple.
566
572
  lvar = var if isinstance(var, list) else [var]
567
573
  for v in lvar:
568
574
  if v not in self._vardata:
@@ -730,10 +736,10 @@ class datapoint:
730
736
 
731
737
  idx = self._didx.get(var, -1)
732
738
  if idx >= 0:
733
- return np.array(self._data)[:, idx] if self._data else np.empty(1)
739
+ return np.array(self._data)[:, idx] if self._data else np.array([])
734
740
 
735
741
  # else \ user defined variables
736
- return np.array(self._vardata.get(var, np.empty((1, 2))))
742
+ return np.array(self._vardata.get(var, np.array([])))
737
743
 
738
744
 
739
745
  def timestate(self, t):
@@ -772,7 +778,7 @@ class datapoint:
772
778
  [6, 9, 53, 13, 49, 99]
773
779
 
774
780
  '''
775
- # TODO how about throwing a warning when dt is too long?
781
+ # TODO what about throwing a warning when dt is too long?
776
782
  times = self.get_data('t')
777
783
  if times.size == 0:
778
784
  out = None
@@ -786,6 +792,7 @@ class datapoint:
786
792
  #
787
793
  # to norms:
788
794
  ##
795
+ @property
789
796
  def P(self):
790
797
  '''
791
798
  Returns the Euclidean norm of the position coordinates in three dimensions.
@@ -808,21 +815,23 @@ class datapoint:
808
815
  .. code::
809
816
 
810
817
  >>> pt = c4d.datapoint(x = 7, y = 24)
811
- >>> print(pt.P())
818
+ >>> print(pt.P)
812
819
  25.0
813
820
  >>> pt.X = np.zeros(6)
814
- >>> print(pt.P())
821
+ >>> print(pt.P)
815
822
  0.0
816
823
 
817
824
  '''
818
825
  return np.sqrt(self.x**2 + self.y**2 + self.z**2)
819
826
 
820
-
827
+ @property
821
828
  def V(self):
822
829
  '''
823
- Returns the Euclidean norm of the velocity coordinates in three dimensions.
830
+ Returns the Euclidean norm of the velocity
831
+ coordinates in three dimensions.
824
832
 
825
- This method computes the Euclidean norm (magnitude) of a 3D vector represented
833
+ This method computes the Euclidean norm (magnitude)
834
+ of a 3D vector represented
826
835
  by the instance variables self.vx, self.vy, and self.vz:
827
836
 
828
837
  .. math::
@@ -841,10 +850,10 @@ class datapoint:
841
850
  .. code::
842
851
 
843
852
  >>> pt = c4d.datapoint(vx = 7, vy = 24)
844
- >>> print(pt.V())
853
+ >>> print(pt.V)
845
854
  25.0
846
855
  >>> pt.X = np.zeros(6)
847
- >>> print(pt.V())
856
+ >>> print(pt.V)
848
857
  0.0
849
858
 
850
859
  '''
@@ -1106,3 +1115,297 @@ class datapoint:
1106
1115
  # plt.show() # block = True # block = False
1107
1116
 
1108
1117
 
1118
+ class fdatapoint(datapoint):
1119
+
1120
+ #
1121
+ # XXX override the .X property: will distance the devs from a datapoint class.
1122
+ # con: much easier
1123
+
1124
+ __slots__ = ['_boxwidth', '_boxheight', '_framewidth', '_frameheight']
1125
+
1126
+
1127
+ def __init__(self, bbox, iclass, framesize, **kwargs):
1128
+ '''
1129
+ A class representing a data point in a video frame with a
1130
+ bounding box.
1131
+
1132
+ bbox : tuple
1133
+ Bounding box coordinates in normalized format (xc, yc, w, h).
1134
+
1135
+ xc : float; The x-coordinate of the center of the bounding box.
1136
+
1137
+ yc : float; The y-coordinate of the center of the bounding box.
1138
+
1139
+ w : float; The width of the bounding box.
1140
+
1141
+ h : float; The height of the bounding box.
1142
+
1143
+ iclass : string
1144
+ Class label or identifier associated with the data point.
1145
+
1146
+ framesize : tuple
1147
+ Size of the frame in pixels (width, height).
1148
+
1149
+ width : int; The width of the image.
1150
+
1151
+ height : int; The height of the image.
1152
+
1153
+ Note
1154
+ ----
1155
+
1156
+ The normalized coordinates are expressed with respect to the
1157
+ dimensions of the image, ranging from 0 to 1, where 0 represents
1158
+ the left or the upper edge, and 1 represents the right or the bottom edge.
1159
+
1160
+
1161
+
1162
+ '''
1163
+
1164
+ super().__init__(x = bbox[0], y = bbox[1], **kwargs)
1165
+ # - x (float): X-coordinate of the center of the bounding box in relative coordinates.
1166
+ # - y (float): Y-coordinate of the center of the bounding box in relative coordinates.
1167
+
1168
+
1169
+ self._boxwidth = bbox[2]
1170
+ ''' float; Width of the bounding box in a normalized format
1171
+ (0 = left image edge, 1 = right image edge. '''
1172
+
1173
+ self._boxheight = bbox[3]
1174
+ ''' float; Height of the bounding box in a normalized format
1175
+ (0 = upper image edge, 1 = bottom image edge. '''
1176
+
1177
+
1178
+ self._framewidth = framesize[0]
1179
+ ''' int; Width of the frame in pixels. '''
1180
+
1181
+ self._frameheight = framesize[1]
1182
+ ''' int; Height of the frame in pixels. '''
1183
+
1184
+
1185
+ self.iclass = iclass
1186
+ ''' string; Class label or identifier associated with the data point. '''
1187
+
1188
+
1189
+
1190
+ def set_box_size(self, width, height):
1191
+ # TODO document!
1192
+ '''
1193
+ Sets the box size (box width, box height)
1194
+ without changing the center.
1195
+
1196
+
1197
+ Parameters
1198
+ ----------
1199
+ b : tuple(width, height)
1200
+ A tuple containing two integers representing width and height (in pixels).
1201
+
1202
+
1203
+ Note
1204
+ ----
1205
+ This function sets the box width and height without
1206
+ chaning the box center.
1207
+ The center of the box is modified only by
1208
+ direct substitution to the state variables
1209
+ or by setting the state vector (:attr:`X <datapoint.X>`).
1210
+
1211
+
1212
+
1213
+ Examples
1214
+ -------_
1215
+
1216
+ .. code::
1217
+
1218
+ >>> width = 800
1219
+ >>> height = 600
1220
+ >>> radius = 50
1221
+ >>> img = np.zeros((height, width, 3), dtype = np.uint8)
1222
+ >>> cv2.circle(img, (width // 2, height // 2), radius, (255, 0, 0), -1)
1223
+ >>> fdp = c4d.fdatapoint(bbox = (0, 0, 0, 0), iclass = 'ball', framesize = (width, height))
1224
+ >>> fdp.x = 0.5
1225
+ >>> fdp.y = 0.5
1226
+ >>> fdp.set_box_size(2 * radius + 2, 2 * radius + 2)
1227
+ >>> cv2.rectangle(img, fdp.box[0], fdp.box[1], [255, 255, 255], 2)
1228
+ >>> _, ax3 = plt.subplots()
1229
+ >>> ax3.axis('off')
1230
+ >>> ax3.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
1231
+
1232
+ .. figure:: /_static/images/fdp_setboxsize.png
1233
+
1234
+
1235
+
1236
+ '''
1237
+
1238
+ self._boxwidth = width / self._framewidth
1239
+ self._boxheight = height / self._frameheight
1240
+
1241
+
1242
+ @property
1243
+ def box(self):
1244
+ '''
1245
+ Gets the box coordinates [(x top left, y top left)
1246
+ , (x bottom right, y bottom right)]
1247
+
1248
+ Returns
1249
+ -------
1250
+ out : list[tuple]
1251
+ List containing two tuples representing
1252
+ top-left and bottom-right coordinates (in pixels).
1253
+
1254
+
1255
+ Examples
1256
+ --------
1257
+
1258
+ Draw a bounding box around the detected object
1259
+
1260
+ .. code::
1261
+
1262
+ >>> imagename = 'planes.jpg'
1263
+ >>> img = cv2.imread(os.path.join(os.getcwd(), 'examples', 'resources', imagename))
1264
+ >>> yolo3 = c4d.detectors.yolov3()
1265
+ >>> pts = yolo3.detect(img)
1266
+ >>> for p in pts:
1267
+ ... cv2.rectangle(img, p.box[0], p.box[1], np.random.randint(0, 255, 3).tolist(), 3)
1268
+ >>> fig, ax = plt.subplots()
1269
+ >>> ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
1270
+
1271
+ .. figure:: /_static/images/fdp_box.png
1272
+
1273
+ '''
1274
+
1275
+ xc = int(self.x * self._framewidth)
1276
+ yc = int(self.y * self._frameheight)
1277
+
1278
+ # top left
1279
+ xtl = xc - int(self._boxwidth * self._framewidth / 2)
1280
+ ytl = yc - int(self._boxheight * self._frameheight / 2)
1281
+
1282
+ # bottom right
1283
+ xbr = xc + int(self._boxwidth * self._framewidth / 2)
1284
+ ybr = yc + int(self._boxheight * self._frameheight / 2)
1285
+
1286
+ return [(xtl, ytl), (xbr, ybr)]
1287
+
1288
+
1289
+ @property
1290
+ def fsize(self):
1291
+ '''
1292
+ Gets the frame size.
1293
+
1294
+ Returns
1295
+ -------
1296
+ out : tuple
1297
+ A tuple of the frame size in pixels (width, height).
1298
+
1299
+ Examples
1300
+ --------
1301
+
1302
+ .. code::
1303
+
1304
+ >>> imagename = 'planes.jpg'
1305
+ >>> imgpath = os.path.join(os.getcwd(), 'examples', 'resources', imagename)
1306
+ >>> img = cv2.imread(imgpath)
1307
+ >>> yolo3 = c4d.detectors.yolov3()
1308
+ >>> pts = yolo3.detect(img)
1309
+ >>> print('{:^10} | {:^10} | {:^10} | {:^16} | {:^16} | {:^10} | {:^14}'.format(
1310
+ ... '# object', 'center x', 'center y', 'box top-left'
1311
+ ... , 'box bottom-right', 'class', 'frame size'))
1312
+ >>> for i, p in enumerate(pts):
1313
+ ... tlb = '(' + str(p.box[0][0]) + ', ' + str(p.box[0][1]) + ')'
1314
+ ... brb = '(' + str(p.box[1][0]) + ', ' + str(p.box[1][1]) + ')'
1315
+ ... fsize = '(' + str(p.fsize[0]) + ', ' + str(p.fsize[1]) + ')'
1316
+ ... print('{:^10d} | {:^10.3f} | {:^10.3f} | {:^16} | {:^16} | {:^10} | {:^14}'.format(
1317
+ ... i, p.x, p.y, tlb, brb, p.iclass, fsize))
1318
+ ... c = np.random.randint(0, 255, 3).tolist()
1319
+ ... cv2.rectangle(img, p.box[0], p.box[1], c, 2)
1320
+ ... point = (int((p.box[0][0] + p.box[1][0]) / 2 - 75), p.box[1][1] + 22)
1321
+ ... cv2.putText(img, p.iclass, point, cv2.FONT_HERSHEY_SIMPLEX, 1, c, 2)
1322
+ >>> fig, ax = plt.subplots()
1323
+ >>> ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
1324
+ >>> ax.set_axis_off()
1325
+ # object | center x | center y | box top-left | box bottom-right | class | frame size
1326
+ 0 | 0.584 | 0.376 | (691, 234) | (802, 306) | aeroplane | (1280, 720)
1327
+ 1 | 0.457 | 0.473 | (528, 305) | (642, 376) | aeroplane | (1280, 720)
1328
+ 2 | 0.471 | 0.322 | (542, 196) | (661, 267) | aeroplane | (1280, 720)
1329
+ 3 | 0.546 | 0.873 | (645, 588) | (752, 668) | aeroplane | (1280, 720)
1330
+
1331
+ .. figure:: /_static/images/fdp_fsize.png
1332
+
1333
+
1334
+ '''
1335
+ return (self._framewidth, self._frameheight)
1336
+
1337
+
1338
+ @property
1339
+ def Xpixels(self):
1340
+ '''
1341
+ Returns the state vector in pixel coordinates.
1342
+
1343
+ Returns
1344
+ -------
1345
+ out : numpy.int32
1346
+ A numpy array of the normalized coordinates :math:`[x, y, v_x, v_y]` transformed
1347
+ to pixel coordinates considering the specific dimensions of the image.
1348
+
1349
+
1350
+ Examples
1351
+ --------
1352
+
1353
+ .. code::
1354
+
1355
+ >>> imagename = 'planes.jpg'
1356
+ >>> imgpath = os.path.join(os.getcwd(), 'examples', 'resources', imagename)
1357
+ >>> img = cv2.imread(imgpath)
1358
+ >>> yolo3 = c4d.detectors.yolov3()
1359
+ >>> pts = yolo3.detect(img)
1360
+ >>> print('{:^10} | {:^12} | {:^12} | {:^12} | {:^12}'.format(
1361
+ ... '# object', 'X normalized', 'Y normalized', 'X pixels', 'Y pixels'))
1362
+ >>> for i, p in enumerate(pts):
1363
+ ... X = p.Xpixels
1364
+ ... print('{:^10d} | {:^12.3f} | {:^12.3f} | {:^12d} | {:^12d}'.format(
1365
+ ... i, p.x, p.y, X[0], X[1]))
1366
+
1367
+ '''
1368
+ # TODO complete with full state vector.
1369
+
1370
+ superx = super().X
1371
+ return np.array([superx[0] * self._framewidth # x
1372
+ , superx[1] * self._frameheight # y
1373
+ , superx[3] * self._framewidth # vx
1374
+ , superx[4] * self._frameheight] # vy
1375
+ , dtype = np.int32)
1376
+
1377
+
1378
+
1379
+ @staticmethod
1380
+ def boxcenter(box):
1381
+ # XXX seems like useless function and indeed is not in use anywhere.
1382
+ '''
1383
+
1384
+ Calculates the center coordinates of bounding boxes.
1385
+
1386
+ Given a list of bounding boxes, this static method computes the center
1387
+ coordinates for each box.
1388
+
1389
+
1390
+
1391
+ Parameters
1392
+ ----------
1393
+ out : list[box]
1394
+ List containing one fdatapoint.box or more. where
1395
+ every fdatapoint.box has two tuples
1396
+ representing top-left and bottom-right coordinates.
1397
+
1398
+ Returns
1399
+ -------
1400
+ out : numpy.ndarray
1401
+ An array containing center coordinates for each bounding box in the
1402
+ format [[center_x1, center_y1], [center_x2, center_y2], ...].
1403
+
1404
+ '''
1405
+
1406
+ return np.array([[(b[0] + b[2]) / 2, (b[1] + b[3]) / 2] for b in box])
1407
+
1408
+
1409
+
1410
+
1411
+
@@ -67,18 +67,19 @@ class rigidbody(c4d.datapoint): #
67
67
  #
68
68
  # variables for storage
69
69
  ##
70
- super().__init__() # Dummy values
70
+ super().__init__(**kwargs) # Dummy values
71
71
  self.__dict__.update(kwargs)
72
- self._data = [] # np.zeros((1, 19))
72
+ # self._data = [] # np.zeros((1, 19))
73
73
  self._didx.update({'phi': 7, 'theta': 8, 'psi': 9
74
74
  , 'p': 10, 'q': 11, 'r': 12})
75
75
 
76
- self.x0 = self.x
77
- self.y0 = self.y
78
- self.z0 = self.z
79
- self.vx0 = self.vx
80
- self.vy0 = self.vy
81
- self.vz0 = self.vz
76
+ # i think this one should be
77
+ # self.x0 = self.x
78
+ # self.y0 = self.y
79
+ # self.z0 = self.z
80
+ # self.vx0 = self.vx
81
+ # self.vy0 = self.vy
82
+ # self.vz0 = self.vz
82
83
 
83
84
  self.phi0 = self.phi
84
85
  self.theta0 = self.theta
@@ -8,6 +8,5 @@ C4dynamics.detectors
8
8
 
9
9
 
10
10
 
11
- # from .yolo_tf import yolo
12
- from .yolo_opencv import yolo
11
+ from .yolo3_opencv import yolov3
13
12