c4dynamics 2.0.3__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.
Files changed (50) hide show
  1. c4dynamics/__init__.py +240 -0
  2. c4dynamics/datasets/__init__.py +95 -0
  3. c4dynamics/datasets/_manager.py +596 -0
  4. c4dynamics/datasets/_registry.py +80 -0
  5. c4dynamics/detectors/__init__.py +37 -0
  6. c4dynamics/detectors/yolo3_opencv.py +686 -0
  7. c4dynamics/detectors/yolo3_tf.py +124 -0
  8. c4dynamics/eqm/__init__.py +324 -0
  9. c4dynamics/eqm/derivs.py +212 -0
  10. c4dynamics/eqm/integrate.py +359 -0
  11. c4dynamics/filters/__init__.py +1373 -0
  12. c4dynamics/filters/a.py +48 -0
  13. c4dynamics/filters/ekf.py +320 -0
  14. c4dynamics/filters/kalman.py +725 -0
  15. c4dynamics/filters/kalman_v0.py +1071 -0
  16. c4dynamics/filters/kalman_v1.py +821 -0
  17. c4dynamics/filters/lowpass.py +123 -0
  18. c4dynamics/filters/luenberger.py +97 -0
  19. c4dynamics/rotmat/__init__.py +141 -0
  20. c4dynamics/rotmat/animate.py +465 -0
  21. c4dynamics/rotmat/rotmat.py +351 -0
  22. c4dynamics/sensors/__init__.py +72 -0
  23. c4dynamics/sensors/lineofsight.py +78 -0
  24. c4dynamics/sensors/radar.py +740 -0
  25. c4dynamics/sensors/seeker.py +1030 -0
  26. c4dynamics/states/__init__.py +327 -0
  27. c4dynamics/states/lib/__init__.py +320 -0
  28. c4dynamics/states/lib/datapoint.py +660 -0
  29. c4dynamics/states/lib/pixelpoint.py +776 -0
  30. c4dynamics/states/lib/rigidbody.py +677 -0
  31. c4dynamics/states/state.py +1486 -0
  32. c4dynamics/utils/__init__.py +44 -0
  33. c4dynamics/utils/_struct.py +6 -0
  34. c4dynamics/utils/const.py +130 -0
  35. c4dynamics/utils/cprint.py +80 -0
  36. c4dynamics/utils/gen_gif.py +142 -0
  37. c4dynamics/utils/idx2keys.py +4 -0
  38. c4dynamics/utils/images_loader.py +63 -0
  39. c4dynamics/utils/math.py +136 -0
  40. c4dynamics/utils/plottools.py +140 -0
  41. c4dynamics/utils/plottracks.py +304 -0
  42. c4dynamics/utils/printpts.py +36 -0
  43. c4dynamics/utils/slides_gen.py +64 -0
  44. c4dynamics/utils/tictoc.py +167 -0
  45. c4dynamics/utils/video_gen.py +300 -0
  46. c4dynamics/utils/vidgen.py +182 -0
  47. c4dynamics-2.0.3.dist-info/METADATA +242 -0
  48. c4dynamics-2.0.3.dist-info/RECORD +50 -0
  49. c4dynamics-2.0.3.dist-info/WHEEL +5 -0
  50. c4dynamics-2.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,140 @@
1
+ import numpy as np
2
+ from matplotlib import pyplot as plt
3
+ from matplotlib.ticker import ScalarFormatter
4
+ import sys
5
+ sys.path.append('.')
6
+
7
+
8
+ def _figdef():
9
+ factorsize = 4
10
+ aspectratio = 1080 / 1920
11
+ return plt.subplots(1, 1, dpi = 200
12
+ , figsize = (factorsize, factorsize * aspectratio)
13
+ , gridspec_kw = {'left': 0.15, 'right': .9
14
+ , 'top': .9, 'bottom': .2})
15
+
16
+
17
+ def _legdef():
18
+ return {'fontsize': 4, 'facecolor': None}
19
+
20
+
21
+ def plotdefaults(ax, title, xlabel = '', ylabel = '', fontsize = 8, ilines = None):
22
+ '''
23
+
24
+ Setting default properties on a matplotlib axis.
25
+
26
+ Parameters
27
+ ----------
28
+
29
+ ax : matplotlib.axes.Axes
30
+ The matplotlib axis on which to set the properties.
31
+
32
+ title : str
33
+ Plot title.
34
+
35
+ xlabel : str
36
+ The label for the x-axis.
37
+
38
+ ylabel : str
39
+ The label for the y-axis.
40
+
41
+ fontsize : int, optional
42
+ The font size for the title, x-axis label, y-axis label, and tick labels. Default is 14.
43
+
44
+
45
+ Example
46
+ -------
47
+
48
+ .. code::
49
+
50
+ >>> import c4dynamics as c4d
51
+ >>> f16 = c4d.rigidbody()
52
+ >>> dt = .01
53
+ >>> for t in np.arange(0, 9, dt):
54
+ ... if t < 3:
55
+ ... f16.phi += dt * 180 / 9 * c4d.d2r
56
+ ... elif t < 6:
57
+ ... f16.phi += dt * 180 / 6 * c4d.d2r
58
+ ... else:
59
+ ... f16.phi += dt * 180 / 3 * c4d.d2r
60
+ ... f16.store(t)
61
+ >>> ax = plt.subplot()
62
+ >>> ax.plot(*f16.data('phi', c4d.r2d), 'm', linewidth = 2) # doctest: +IGNORE_OUTPUT
63
+ >>> c4d.plotdefaults(ax, '$\\varphi$', 'Time', 'deg', fontsize = 18)
64
+
65
+
66
+ .. figure:: /_examples/utils/plotdefaults.png
67
+
68
+ '''
69
+ if False:
70
+ #
71
+ # line
72
+ ##
73
+ lwidth = 2
74
+ # set colors suite to the lines:
75
+ scolors = {'cyan': np.array([0, 1, 1])
76
+ , 'magenta': np.array([1, 0, 1])
77
+ , 'gold': np.array([1, 0.84, 0])
78
+ , 'deepskyblue': np.array([0, 0.75, 1])
79
+ , 'limegreen': np.array([0.2, 0.8, 0.2])
80
+ , 'coral': np.array([1, 0.5, 0.31])
81
+ , 'orchid': np.array([0.85, 0.44, 0.84])
82
+ , 'tomato': np.array([1, 0.39, 0.28])
83
+ , 'dodgerblue': np.array([0.12, 0.56, 1])
84
+ , 'palevioletred': np.array([0.86, 0.44, 0.58])}
85
+
86
+ if ilines is None:
87
+ lcolors = lcolors
88
+ else:
89
+ lcolors = np.array(list(scolors.values()))[ilines, :]
90
+
91
+
92
+ for line, color in zip(ax.get_lines(), lcolors):
93
+ line.set_color(color)
94
+ line.set_linewidth(lwidth)
95
+ lwidth = 1
96
+
97
+ #
98
+ # legend
99
+ ##
100
+ ax.legend(fontsize = 'small', facecolor = None)
101
+
102
+ #
103
+ # axis
104
+ ##
105
+ ax.set_title(title, fontsize = fontsize, fontname = 'Times New Roman')
106
+ ax.set_xlabel(xlabel, fontsize = fontsize, fontname = 'Times New Roman')
107
+ ax.set_ylabel(ylabel, fontsize = fontsize, fontname = 'Times New Roman')
108
+ ax.grid(alpha = 0.5)
109
+ ax.tick_params(axis = 'both', labelsize = fontsize, labelfontfamily = 'Times New Roman')
110
+
111
+ ax.yaxis.set_major_formatter(ScalarFormatter())
112
+ ax.yaxis.get_major_formatter().set_useOffset(False)
113
+ ax.yaxis.get_major_formatter().set_scientific(False)
114
+
115
+
116
+ if __name__ == "__main__":
117
+
118
+ import doctest, contextlib, os
119
+ from c4dynamics import IgnoreOutputChecker, cprint
120
+
121
+ # Register the custom OutputChecker
122
+ doctest.OutputChecker = IgnoreOutputChecker
123
+
124
+ tofile = False
125
+ optionflags = doctest.FAIL_FAST
126
+
127
+ if tofile:
128
+ with open(os.path.join('tests', '_out', 'output.txt'), 'w') as f:
129
+ with contextlib.redirect_stdout(f), contextlib.redirect_stderr(f):
130
+ result = doctest.testmod(optionflags = optionflags)
131
+ else:
132
+ result = doctest.testmod(optionflags = optionflags)
133
+
134
+ if result.failed == 0:
135
+ cprint(os.path.basename(__file__) + ": all tests passed!", 'g')
136
+ else:
137
+ print(f"{result.failed}")
138
+
139
+
140
+
@@ -0,0 +1,304 @@
1
+ # import time
2
+ import os, sys
3
+ import argparse
4
+ sys.path.append('')
5
+ sys.path.append('examples')
6
+ import c4dynamics as c4d
7
+
8
+ # c4d.cprint('im in ' + os.getcwd(), 'y')
9
+ # for p in sys.path:
10
+ # c4d.cprint(p, 'c')
11
+
12
+ from matplotlib import pyplot as plt
13
+ plt.style.use('dark_background')
14
+ plt.switch_backend('TkAgg')
15
+
16
+ # from enum import Enum
17
+ import numpy as np
18
+ import pickle
19
+ # from scipy.interpolate import interp1d
20
+
21
+ from programs._mtracks import mTracks, Trkstate
22
+ # import multiprocessing
23
+
24
+ def plottracks(fol, trkid = None, block = True):
25
+ # print(fol)
26
+ # print(trkid)
27
+ # print(block)
28
+ if trkid is not None:
29
+ trkname = str(trkid)
30
+ else:
31
+ trkname = 'all tracks'
32
+
33
+ # def plottracks(fol, mtracks, pklpts, dt_video, dt, save_png, trkid = None):
34
+
35
+ # load tracks, detections
36
+
37
+ # the detections are simultenuous with the correct states.
38
+ # but the detections are independent of the tracks and the tracks perhaps miss updates, then where should the detections be plotted?
39
+ # but every thing is driven by the video. even if there are predicts in between. so
40
+ # where are these properties introduced here?
41
+
42
+ # dtctsfile = os.path.join(fol, *[f for f in os.listdir(fol) if f.endswith('detections.pkl')]
43
+
44
+ if os.path.exists(os.path.join(fol, 'mtracks.pkl')):
45
+ with open(os.path.join(fol, 'mtracks.pkl'), 'rb') as f: mtracks = pickle.load(f)
46
+ else:
47
+ raise ValueError('data folder doesnt consist tracks file')
48
+
49
+
50
+ detections = {}
51
+
52
+ if os.path.exists(os.path.join(fol, 'detections.pkl')):
53
+ # try subfol first:
54
+ with open(os.path.join(fol, 'detections.pkl'), 'rb') as f: detections = pickle.load(f)
55
+ elif os.path.exists(os.path.join(os.path.dirname(fol), 'detections.pkl')):
56
+ # then try parent folder:
57
+ with open(os.path.join(os.path.dirname(fol), 'detections.pkl'), 'rb') as f: detections = pickle.load(f)
58
+ else:
59
+ c4d.cprint('data folder doesnt consist detections file')
60
+
61
+
62
+
63
+
64
+ # if save_png == plotbackend.SAVE:
65
+ # plt.switch_backend('agg')
66
+ # else:
67
+
68
+
69
+ # X = []
70
+
71
+ # for idx, p in enumerate(detections.values()):
72
+ # px = [idx * mtracks.dt_video] + p[0].X.tolist() if p else [idx * mtracks.dt_video] + [np.nan, np.nan, np.nan, np.nan]
73
+ # X.append(px)
74
+
75
+ # X = np.array(X)
76
+ # t2 = np.linspace(X[0, 0], X[-1, 0], 3 * len(X))
77
+ # X1 = interp1d(X[:, 0], X[:, 1])(t2)
78
+ # Y1 = interp1d(X[:, 0], X[:, 2])(t2)
79
+ # W = interp1d(X[:, 0], X[:, 3])(t2)
80
+ # H = interp1d(X[:, 0], X[:, 4])(t2)
81
+ # VX1 = np.concatenate(([0], np.diff(X1) / t2[1]))
82
+ # VY1 = np.concatenate(([0], np.diff(Y1) / t2[1]))
83
+
84
+ # X = np.column_stack((t2, X1, Y1, W, H, VX1, VY1))
85
+
86
+
87
+
88
+
89
+ trks = {**mtracks.trackers_hist, **mtracks.trackers}
90
+ map = {'x': (0, 0), 'y': (1, 0), 'w': (0, 1), 'h': (1, 1) # , 'vx': (0, 2), 'vy': (1, 2)}
91
+ , 'vx': (0, 0), 'vy': (1, 0), 'ax': (0, 1), 'ay': (1, 1)}
92
+ # color = [0.36601279, 0.46364415, 0.83173777] # np.random.rand(3)
93
+ fig, axs = plt.subplots(2, 2, gridspec_kw = {'wspace': 0.3, 'hspace': 0.5})
94
+ fig.suptitle(f'{trkname}', fontsize = 16, fontweight = 'bold')
95
+ fig2, axs2 = plt.subplots(2, 2, gridspec_kw = {'wspace': 0.3, 'hspace': 0.5})
96
+ fig2.suptitle(f'{trkname}', fontsize = 16, fontweight = 'bold')
97
+ fig3, axs3 = plt.subplots(1, 2, gridspec_kw = {'wspace': 0.3, 'hspace': 0.5})
98
+ fig3.suptitle(f'{trkname}', fontsize = 16, fontweight = 'bold')
99
+ fig4, axs4 = plt.subplots(1, 2, gridspec_kw = {'wspace': 0.3, 'hspace': 0.5})
100
+ fig4.suptitle(f'{trkname}', fontsize = 16, fontweight = 'bold')
101
+
102
+
103
+ #
104
+ # draw raw detections
105
+ ##
106
+ for idx, p in detections.items():
107
+ t = idx * mtracks.dt_video
108
+ px = np.array([pi.X for pi in p if p])
109
+ if len(px) == 0: continue
110
+
111
+ for j, var in enumerate(['x', 'y', 'w', 'h']):
112
+ axs[map[var]].plot(t * np.ones(px.shape[0]), px[:, j]
113
+ , linewidth = 0, color = np.array([1, 1, 1])
114
+ , marker = 'o', markersize = 3, markerfacecolor = 'none'
115
+ , label = var + ' raw')
116
+
117
+ if var == 'x' or var == 'y':
118
+ print(map[var][0])
119
+ axs3[map[var][0]].plot(t * np.ones(px.shape[0]), px[:, j]
120
+ , linewidth = 0, color = np.array([1, 1, 1])
121
+ , marker = 'o', markersize = 4, markerfacecolor = 'none'
122
+ , label = var + ' raw')
123
+
124
+ #
125
+ # draw tracks and uncertaties
126
+ ##
127
+ np.random.seed(0)
128
+ color = np.array([1.0, 0.0, 1.0]) # magenta
129
+ color = np.array([0.0, 1.0, 1.0]) # cyan
130
+ i = 0
131
+
132
+ for k, v in trks.items():
133
+ if trkid is not None and all(f != k for f in trkid): continue
134
+ print(k)
135
+
136
+ # if trkid is None:
137
+ # color = np.random.rand(3)
138
+ # elif all(f != k for f in trkid):
139
+ # # trkid is not none and k is not in trkid
140
+ # continue
141
+
142
+ if len(v.data()) == 0: continue
143
+
144
+
145
+ # fig, axs = plt.subplots(2, 2, gridspec_kw = {'wspace': 0.2, 'hspace': 0.5})
146
+ iscorrect = np.where(np.vectorize(lambda x: x.value)(v.data('state')[1]) == Trkstate.CORRECTED.value)[0]
147
+
148
+
149
+ for var in ['x', 'y', 'w', 'h']:
150
+
151
+ x = v.data(var)[1]
152
+ t_sig, x_sig = eval('v.data("p' + var + '")')
153
+
154
+
155
+ axs[map[var]].plot(t_sig, x, linewidth = 2, color = np.array(v.color) / 255, label = var)
156
+ # ±std
157
+ axs[map[var]].plot(t_sig, x + np.sqrt(x_sig.squeeze()), linewidth = 1, color = color, label = 'std') # np.array(v.color) / 255)
158
+ axs[map[var]].plot(t_sig, x - np.sqrt(x_sig.squeeze()), linewidth = 1, color = color) # np.array(v.color) / 255)
159
+ # correct
160
+ axs[map[var]].plot(t_sig[iscorrect], x[iscorrect], linewidth = 0, color = color
161
+ , marker = 'o', markersize = 2, markerfacecolor = 'none', label = 'correct')
162
+
163
+ if var == 'x' or var == 'y':
164
+ axs3[map[var][0]].plot(t_sig, x, linewidth = 4, color = np.array(v.color) / 255, label = var)
165
+ # ±std
166
+ axs3[map[var][0]].plot(t_sig, x + np.sqrt(x_sig.squeeze()), linewidth = 2, color = color, label = 'std') # np.array(v.color) / 255)
167
+ axs3[map[var][0]].plot(t_sig, x - np.sqrt(x_sig.squeeze()), linewidth = 2, color = color) # np.array(v.color) / 255)
168
+ # correct
169
+ axs3[map[var][0]].plot(t_sig[iscorrect], x[iscorrect], linewidth = 0, color = color
170
+ , marker = 'o', markersize = 2, markerfacecolor = 'none', label = 'correct')
171
+
172
+
173
+
174
+ if i == 0:
175
+
176
+ if hasattr(v, 'ax'):
177
+ f2attrs = ['vx', 'vy', 'ax', 'ay']
178
+ else:
179
+ f2attrs = ['vx', 'vy']
180
+
181
+ if var == 'y':
182
+ axs[map[var]].invert_yaxis()
183
+ axs3[map[var][0]].invert_yaxis()
184
+
185
+
186
+ c4d.plotdefaults(axs[map[var]], var, 't', '')
187
+
188
+ if var == 'x' or var == 'y':
189
+ c4d.plotdefaults(axs3[map[var][0]], var, 't', '')
190
+
191
+
192
+ for var in f2attrs:
193
+
194
+ x = v.data(var)[1]
195
+ t_sig, x_sig = eval('v.data("p' + var + '")')
196
+
197
+ axs2[map[var]].plot(t_sig, x, linewidth = 2, color = np.array(v.color) / 255, label = var)
198
+ # ±std
199
+ axs2[map[var]].plot(t_sig, x + np.sqrt(x_sig.squeeze()), linewidth = 1, color = color, label = 'std') # np.array(v.color) / 255)
200
+ axs2[map[var]].plot(t_sig, x - np.sqrt(x_sig.squeeze()), linewidth = 1, color = color) # np.array(v.color) / 255)
201
+ # correct
202
+ axs2[map[var]].plot(t_sig[iscorrect], x[iscorrect], linewidth = 0, color = color
203
+ , marker = 'o', markersize = 2, markerfacecolor = 'none', label = 'correct')
204
+
205
+
206
+ if var == 'vx' or var == 'vy':
207
+ axs4[map[var][0]].plot(t_sig, x, linewidth = 4, color = np.array(v.color) / 255, label = var)
208
+ # ±std
209
+ axs4[map[var][0]].plot(t_sig, x + np.sqrt(x_sig.squeeze()), linewidth = 2, color = color, label = 'std') # np.array(v.color) / 255)
210
+ axs4[map[var][0]].plot(t_sig, x - np.sqrt(x_sig.squeeze()), linewidth = 2, color = color) # np.array(v.color) / 255)
211
+ # correct
212
+ axs4[map[var][0]].plot(t_sig[iscorrect], x[iscorrect], linewidth = 0, color = color
213
+ , marker = 'o', markersize = 2, markerfacecolor = 'none', label = 'correct')
214
+
215
+ if i == 0:
216
+ c4d.plotdefaults(axs2[map[var]], var, 't', '')
217
+
218
+ if var == 'vx' or var == 'vy':
219
+ c4d.plotdefaults(axs4[map[var][0]], var, 't', '')
220
+
221
+
222
+ color = np.random.rand(3)
223
+ i += 1
224
+
225
+ fig.savefig(os.path.join(fol, trkname + '.png'))
226
+ fig2.savefig(os.path.join(fol, trkname + '_2.png'))
227
+ fig3.savefig(os.path.join(fol, trkname + '_3.png'))
228
+ fig4.savefig(os.path.join(fol, trkname + '_4.png'))
229
+
230
+
231
+ # if save_png != plotbackend.SAVE:
232
+ if block:
233
+ plt.show(block = True)
234
+
235
+
236
+
237
+
238
+ if __name__ == '__main__':
239
+
240
+ # if len(sys.argv) == 1:
241
+ # sys.argv.append('--fol')
242
+ # sys.argv.append('examples\out\cars1')
243
+
244
+ # Create an ArgumentParser object
245
+ parser = argparse.ArgumentParser()
246
+
247
+ # Add arguments to the parser
248
+ parser.add_argument('--vidname', required = True, help = 'folder name containing the pickle to explore')
249
+ parser.add_argument('--trkid', nargs = '+', type = int, help = 'trk id to filter')
250
+ # store_true means if provided without following param then set it to true.
251
+ parser.add_argument('--debug', action = 'store_true', default = False, help = 'whether to run in debug mode')
252
+
253
+ # Parse the command-line arguments
254
+ args = parser.parse_args()
255
+ # Convert parsed arguments to a dictionary
256
+ args_dict = vars(args)
257
+ # Print the dictionary
258
+ c4d.cprint(args_dict, 'y')
259
+
260
+
261
+ if args.debug:
262
+ input(f'Run python debugger using process id. \nSelect the pyenv process. \nPress to continue and wait')
263
+ args_dict.pop('debug')
264
+
265
+ videoname = args.vidname
266
+ args_dict.pop('vidname')
267
+ pickledir = os.path.join('examples', '_out', videoname)
268
+
269
+ plottracks(pickledir, **args_dict)
270
+ # plot_process = multiprocessing.Process(target = plottracks, args = (args_dict, ))
271
+ # plot_process.start()
272
+
273
+
274
+
275
+
276
+
277
+ # input('continue running with background plot..')
278
+
279
+ # for a in sys.argv:
280
+ # c4d.cprint(a, 'm')
281
+ # input('press to cont')
282
+ # sys.argv.append('examples\out\cars1')
283
+ # sys.argv.append('69')
284
+
285
+ # if len(sys.argv) < 2:
286
+ # raise AttributeError('folder name is missing')
287
+ # elif len(sys.argv) == 2:
288
+ # fol = sys.argv[1]
289
+ # trkid = None
290
+ # elif len(sys.argv) == 3:
291
+ # fol = sys.argv[1]
292
+ # trkid = int(sys.argv[2])
293
+ # else:
294
+ # fol = sys.argv[1]
295
+ # trkid = int(sys.argv[2])
296
+ # if any(l == 'debug' for l in sys.argv):
297
+ # # try:
298
+ # input('run python debugger using process id. select the pyenv process. press to continue and wait')
299
+ # except Exception as e:
300
+ # time.sleep(2)
301
+ # print(f'error: {e}')
302
+
303
+ # fol = 'examples\out\cars1'
304
+ # ptspath = os.path.join(fol, 'detections.pkl')
@@ -0,0 +1,36 @@
1
+ import os, sys
2
+ sys.path.append('')
3
+ import c4dynamics as c4d
4
+ import pickle
5
+
6
+
7
+ if __name__ == '__main__':
8
+
9
+ for a in sys.argv:
10
+ c4d.cprint(a, 'm')
11
+
12
+ if len(sys.argv) >= 2:
13
+ fol = sys.argv[1]
14
+ else:
15
+ raise AttributeError('folder name is missing')
16
+
17
+ # fol = 'examples\out\cars1'
18
+ ptspath = os.path.join(fol, 'detections.pkl')
19
+
20
+ if os.path.exists(ptspath):
21
+ print('path exists')
22
+ with open(ptspath, 'rb') as file:
23
+ pklpts = pickle.load(file)
24
+ else:
25
+ raise FileNotFoundError(f'{ptspath} is missing')
26
+
27
+ for i, dp in pklpts.items():
28
+
29
+ c4d.cprint(str(i), 'c', end = ') ')
30
+ for p in dp:
31
+ c4d.cprint(p.class_id, end = ' ')
32
+ c4d.cprint()
33
+
34
+
35
+
36
+
@@ -0,0 +1,64 @@
1
+ from pptx import Presentation
2
+ from pptx.util import Inches
3
+ import argparse
4
+ import natsort
5
+ import os, re
6
+
7
+
8
+ def slides_gen(fol):
9
+ # Path to the folder containing images
10
+ # folder_path = os.path.join('D:/', 'Dropbox', 'c4dynamics', 'examples', '_out', 'cars2_short')
11
+ # print(folder_path)
12
+ # Create a PowerPoint presentation object
13
+ prs = Presentation()
14
+ # TODO take the size from the images:
15
+ prs.slide_width = Inches(20)
16
+ prs.slide_height = Inches(11.25)
17
+
18
+ pattern = re.compile(r'\d+.*\.png$')
19
+
20
+
21
+ filelist = natsort.natsorted(os.listdir(fol))
22
+ # imgfiles = [f for f in dirfiles if f.lower().endswith(('.png', '.jpg', '.jpeg', 'bmp', '.tiff'))]
23
+
24
+ # Loop through each file in the folder
25
+ for file_name in filelist:
26
+ if pattern.match(file_name):
27
+ print(file_name)
28
+ # Add a slide
29
+ slide = prs.slides.add_slide(prs.slide_layouts[6])
30
+ # Define the path to the image file
31
+ img_path = os.path.join(fol, file_name)
32
+ # Add the image to the slide
33
+ slide.shapes.add_picture(img_path, Inches(0), Inches(0), width = prs.slide_width, height = prs.slide_height)
34
+
35
+ # Save the presentation
36
+ prs.save(os.path.join(fol, 'vidslides.pptx'))
37
+
38
+
39
+
40
+
41
+
42
+ if __name__ == '__main__':
43
+
44
+ # Create an ArgumentParser object
45
+ parser = argparse.ArgumentParser()
46
+
47
+ # Add arguments to the parser
48
+ parser.add_argument('--fol', required = True, help = 'images folder')
49
+ parser.add_argument('--debug', action = 'store_true', default = False, help = 'whether to run in debug mode')
50
+
51
+ # Parse the command-line arguments
52
+ args = parser.parse_args()
53
+ # Convert parsed arguments to a dictionary
54
+ args_dict = vars(args)
55
+
56
+
57
+ if args.debug:
58
+ input(f'Run python debugger using process id. \nSelect the pyenv process. \nPress to continue and wait')
59
+ args_dict.pop('debug')
60
+
61
+ slides_gen(**args_dict)
62
+
63
+
64
+