halib 0.1.58__py3-none-any.whl → 0.1.60__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.
@@ -124,6 +124,7 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
124
124
  all_metric_data = self.prepare_exp_data_for_metrics(
125
125
  metric_names, *args, **kwargs
126
126
  )
127
+ metric_col_names = []
127
128
  for metric in metric_names:
128
129
  if metric not in all_metric_data:
129
130
  raise ValueError(f"Metric '{metric}' not found in provided data.")
@@ -140,8 +141,12 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
140
141
  args = metric_data
141
142
  else:
142
143
  raise TypeError(f"Unsupported data format for metric '{metric}'")
144
+
143
145
  # Call update and compute
144
- tmetric.update(*args)
146
+ if len(expected_args) == 1:
147
+ tmetric.update(args) # pass as single argument
148
+ else:
149
+ tmetric.update(*args) # unpack multiple arguments
145
150
  computed_value = tmetric.compute()
146
151
  # ensure the computed value converted to a scala value or list array
147
152
  if isinstance(computed_value, torch.Tensor):
@@ -149,16 +154,16 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
149
154
  computed_value = computed_value.item()
150
155
  else:
151
156
  computed_value = computed_value.tolist()
152
- out_dict[metric] = computed_value
157
+ col_name = f"metric_{metric}" if 'metric_' not in metric else metric
158
+ metric_col_names.append(col_name)
159
+ out_dict[col_name] = computed_value
153
160
 
154
161
  # check if any kwargs named "outfile"
155
162
  csv_outfile = kwargs.get("outfile", None)
156
163
  if csv_outfile is not None:
157
- # get the file path without the extension
158
164
  filePathNoExt, _ = os.path.splitext(csv_outfile)
159
- # add the postfix to the file path
160
- csvfilename = f"{now_str()}_{filePathNoExt}{CSV_FILE_POSTFIX}.csv"
161
- csv_outfile = os.path.join(os.path.dirname(csv_outfile), csvfilename)
165
+ # pprint(f"CSV Outfile Path (No Ext): {filePathNoExt}")
166
+ csv_outfile = f'{filePathNoExt}{CSV_FILE_POSTFIX}.csv'
162
167
  elif "outdir" in kwargs:
163
168
  csvoutdir = kwargs["outdir"]
164
169
  csvfilename = f"{now_str()}_{self.get_dataset_name()}_{self.get_experiment_name()}_{CSV_FILE_POSTFIX}.csv"
@@ -166,7 +171,7 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
166
171
 
167
172
  # convert out_dict to a DataFrame
168
173
  df = pd.DataFrame([out_dict])
169
- ordered_cols = REQUIRED_COLS + custom_fields + metric_names
174
+ ordered_cols = REQUIRED_COLS + custom_fields + metric_col_names
170
175
  df = df[ordered_cols] # reorder columns
171
176
 
172
177
  if csv_outfile:
@@ -208,7 +213,7 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
208
213
  temp_df[col] = None # fill missing columns with None
209
214
  df = pd.concat([df, temp_df], ignore_index=True)
210
215
  # assert that REQUIRED_COLS are present in the DataFrame
211
- pprint(df.columns.tolist())
216
+ # pprint(df.columns.tolist())
212
217
  for col in REQUIRED_COLS:
213
218
  if col not in df.columns:
214
219
  raise ValueError(f"Required column '{col}' is missing from the DataFrame. REQUIRED_COLS = {REQUIRED_COLS}")
@@ -275,21 +280,36 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
275
280
 
276
281
  assert os.path.exists(indir), f"Input directory {indir} does not exist."
277
282
 
283
+ csv_perf_files = []
278
284
  # Find experiment subdirectories
279
285
  exp_dirs = [
280
286
  os.path.join(indir, d)
281
287
  for d in os.listdir(indir)
282
288
  if os.path.isdir(os.path.join(indir, d))
283
289
  ]
284
- assert exp_dirs, f"No experiment directories found in {indir}."
290
+ if len(exp_dirs) == 0:
291
+ csv_perf_files = glob.glob(
292
+ os.path.join(indir, f"*{exp_perf_csv_pattern}*.csv")
293
+ )
294
+ csv_perf_files = [
295
+ file_item
296
+ for file_item in csv_perf_files
297
+ if exp_perf_csv_pattern in file_item
298
+ ]
299
+ else:
300
+ # multiple experiment directories found
301
+ # Collect all matching CSV files in those subdirs
302
+ for exp_dir in exp_dirs:
303
+ # pprint(f"Searching in experiment directory: {exp_dir}")
304
+ matched = glob.glob(
305
+ os.path.join(exp_dir, f"*{exp_perf_csv_pattern}*.csv")
306
+ )
307
+ csv_perf_files.extend(matched)
285
308
 
286
- # Collect all matching CSV files in those subdirs
287
- csv_perf_files = []
288
- for exp_dir in exp_dirs:
289
- pprint(f"Searching in experiment directory: {exp_dir}")
290
- matched = glob.glob(os.path.join(exp_dir, f"*{exp_perf_csv_pattern}*.csv"))
309
+ assert (
310
+ len(csv_perf_files) > 0
311
+ ), f"No CSV files matching pattern '{exp_perf_csv_pattern}' found in the experiment directories."
291
312
 
292
- csv_perf_files.extend(matched)
293
313
  assert len(csv_perf_files) > 0, f"No CSV files matching pattern '{exp_perf_csv_pattern}' found in the experiment directories."
294
314
 
295
315
  all_exp_perf_df = get_df_for_all_exp_perf(csv_perf_files, csv_sep=csv_sep)
@@ -26,6 +26,7 @@ def yaml_to_dataclass(name: str, yaml_str: str):
26
26
  data = yaml.safe_load(yaml_str)
27
27
  return dict_to_dataclass(name, data)
28
28
 
29
+
29
30
  def yamlfile_to_dataclass(name: str, file_path: str):
30
31
  data_dict = yamlfile.load_yaml(file_path, to_dict=True)
31
32
  if "__base__" in data_dict:
halib/utils/dict_op.py ADDED
@@ -0,0 +1,9 @@
1
+ def flatten_dict(d, parent_key="", sep="."):
2
+ items = {}
3
+ for k, v in d.items():
4
+ key = f"{parent_key}{sep}{k}" if parent_key else k
5
+ if isinstance(v, dict):
6
+ items.update(flatten_dict(v, key, sep=sep))
7
+ else:
8
+ items[key] = v
9
+ return items
halib/utils/video.py ADDED
@@ -0,0 +1,62 @@
1
+ import os
2
+ import cv2
3
+ from ..filetype import csvfile
4
+ from ..system import filesys as fs
5
+
6
+
7
+ class VideoUtils:
8
+ @staticmethod
9
+ def get_video_meta_dict(video_path):
10
+ # Open the video file
11
+ cap = cv2.VideoCapture(video_path)
12
+
13
+ # Check if the video was opened successfully
14
+ if not cap.isOpened():
15
+ print(f"Error: Could not open video file {video_path}")
16
+ return None, None
17
+
18
+ # Get the frame count
19
+ frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
20
+
21
+ # Get the FPS
22
+ fps = cap.get(cv2.CAP_PROP_FPS)
23
+
24
+ # Release the video capture object
25
+ cap.release()
26
+ meta_dict = {
27
+ "video_path": video_path,
28
+ "frame_count": frame_count,
29
+ "fps": fps
30
+ }
31
+ return meta_dict
32
+
33
+ @staticmethod
34
+ def get_video_dir_meta_df(video_dir, video_exts=['.mp4', '.avi', '.mov', '.mkv'], search_recursive=False, csv_outfile=None):
35
+ assert os.path.exists(video_dir), f"Video directory {video_dir} does not exist"
36
+ video_files = fs.filter_files_by_extension(video_dir, video_exts, recursive=search_recursive)
37
+ assert len(video_files) > 0, f"No video files found in {video_dir} with extensions {video_exts}"
38
+ video_meta_list = []
39
+ for vfile in video_files:
40
+ meta_dict = VideoUtils.get_video_meta_dict(vfile)
41
+ if meta_dict:
42
+ video_meta_list.append(meta_dict)
43
+ dfmk = csvfile.DFCreator()
44
+ columns = list(video_meta_list[0].keys())
45
+ assert len(columns) > 0, "No video metadata found"
46
+ assert 'video_path' in columns, "video_path column not found in video metadata"
47
+ # move video_path to the first column
48
+ columns.remove('video_path')
49
+ columns.insert(0, 'video_path')
50
+ dfmk.create_table("video_meta", columns)
51
+ rows = [[meta[col] for col in columns] for meta in video_meta_list]
52
+ dfmk.insert_rows("video_meta", rows)
53
+ dfmk.fill_table_from_row_pool("video_meta")
54
+
55
+ if csv_outfile:
56
+ dfmk["video_meta"].to_csv(csv_outfile, index=False, sep=";")
57
+ return dfmk["video_meta"].copy()
58
+
59
+
60
+
61
+
62
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: halib
3
- Version: 0.1.58
3
+ Version: 0.1.60
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -45,7 +45,11 @@ Requires-Dist: dataclass-wizard
45
45
 
46
46
  Helper package for coding and automation
47
47
 
48
- **Version 0.1.58**
48
+ **Version 0.1.60**
49
+
50
+ + add `util/video`: add `VideoUtils` class to handle common video-related tasks
51
+
52
+ **Version 0.1.59**
49
53
 
50
54
  + add `util/perfcalc`: abstract class for performance calculation. This class need to be inherited and implemented with specific performance calculation logic.
51
55
 
@@ -30,7 +30,7 @@ halib/online/projectmake.py,sha256=Zrs96WgXvO4nIrwxnCOletL4aTBge-EoF0r7hpKO1w8,4
30
30
  halib/research/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  halib/research/benchquery.py,sha256=FuKnbWQtCEoRRtJAfN-zaN-jPiO_EzsakmTOMiqi7GQ,4626
32
32
  halib/research/dataset.py,sha256=QU0Hr5QFb8_XlvnOMgC9QJGIpwXAZ9lDd0RdQi_QRec,6743
33
- halib/research/perfcalc.py,sha256=AhcYqYO6aDIFQZ35pdVIfajwSAStIQSQ-ChiyhPML34,14392
33
+ halib/research/perfcalc.py,sha256=qKgoDbXQtyOpRgOjSMUus7r4mgyiH8Gu9o59sd48SAE,15147
34
34
  halib/research/perftb.py,sha256=vazU-dYBJhfc4sK4zFgxOvzeXGi-5TyPHCt20ItiWhY,30463
35
35
  halib/research/plot.py,sha256=-pDUk4z3C_GnyJ5zWmf-mGMdT4gaipVJWzIgcpIPiRk,9448
36
36
  halib/research/torchloader.py,sha256=yqUjcSiME6H5W210363HyRUrOi3ISpUFAFkTr1w4DCw,6503
@@ -42,11 +42,13 @@ halib/system/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
42
  halib/system/cmd.py,sha256=b2x7JPcNnFjLGheIESVYvqAb-w2UwBM1PAwYxMZ5YjA,228
43
43
  halib/system/filesys.py,sha256=ERpnELLDKJoTIIKf-AajgkY62nID4qmqmX5TkE95APU,2931
44
44
  halib/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- halib/utils/dataclass_util.py,sha256=aD5Ik9BRJzIEyfdlOCHmOddA7TM_TIAfapZfU0vMigE,1414
45
+ halib/utils/dataclass_util.py,sha256=rj2IMLlUzbm2OlF5_B2dRTk9njZOaF7tTjYkOsq8uLY,1416
46
+ halib/utils/dict_op.py,sha256=wYE6Iw-_CnCWdMg9tpJ2Y2-e2ESkW9FxmdBkZkbUh80,299
46
47
  halib/utils/listop.py,sha256=Vpa8_2fI0wySpB2-8sfTBkyi_A4FhoFVVvFiuvW8N64,339
47
48
  halib/utils/tele_noti.py,sha256=-4WXZelCA4W9BroapkRyIdUu9cUVrcJJhegnMs_WpGU,5928
48
- halib-0.1.58.dist-info/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
49
- halib-0.1.58.dist-info/METADATA,sha256=8g1pRBqG07Nf_wyrglomhbe-qvzbzcMhX1TfmMUG3AQ,4856
50
- halib-0.1.58.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
51
- halib-0.1.58.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
52
- halib-0.1.58.dist-info/RECORD,,
49
+ halib/utils/video.py,sha256=mJQFHFbijmu3lo0NZk4Ed64Tfa1u5KxNJpd_TuckpPU,2228
50
+ halib-0.1.60.dist-info/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
51
+ halib-0.1.60.dist-info/METADATA,sha256=QMs6mroREHr6qCcrUJwOCwL86Rbu0_bQvf8sLiRsYFk,4957
52
+ halib-0.1.60.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
53
+ halib-0.1.60.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
54
+ halib-0.1.60.dist-info/RECORD,,
File without changes