pyfaceau 1.3.3__tar.gz → 1.3.5__tar.gz

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 (64) hide show
  1. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/MANIFEST.in +6 -3
  2. {pyfaceau-1.3.3/pyfaceau.egg-info → pyfaceau-1.3.5}/PKG-INFO +1 -1
  3. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/config.py +6 -5
  4. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/data/training_data_generator.py +69 -11
  5. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/parallel_pipeline.py +2 -1
  6. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/pipeline.py +39 -8
  7. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/au_predictor.py +2 -1
  8. {pyfaceau-1.3.3 → pyfaceau-1.3.5/pyfaceau.egg-info}/PKG-INFO +1 -1
  9. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyproject.toml +9 -2
  10. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/setup.py +1 -1
  11. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/LICENSE +0 -0
  12. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/README.md +0 -0
  13. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/__init__.py +0 -0
  14. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/alignment/__init__.py +0 -0
  15. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/alignment/calc_params.py +0 -0
  16. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/alignment/face_aligner.py +0 -0
  17. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/alignment/numba_calcparams_accelerator.py +0 -0
  18. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/alignment/paw.py +0 -0
  19. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/data/__init__.py +0 -0
  20. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/data/hdf5_dataset.py +0 -0
  21. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/data/quality_filter.py +0 -0
  22. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/detectors/__init__.py +0 -0
  23. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/detectors/extract_mtcnn_weights.py +0 -0
  24. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/detectors/openface_mtcnn.py +0 -0
  25. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/detectors/pfld.py +0 -0
  26. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/detectors/pymtcnn_detector.py +0 -0
  27. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/detectors/retinaface.py +0 -0
  28. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/download_weights.py +0 -0
  29. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/features/__init__.py +0 -0
  30. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/features/histogram_median_tracker.py +0 -0
  31. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/features/pdm.py +0 -0
  32. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/features/triangulation.py +0 -0
  33. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/__init__.py +0 -0
  34. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/au_prediction_inference.py +0 -0
  35. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/au_prediction_net.py +0 -0
  36. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/fast_pipeline.py +0 -0
  37. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/landmark_pose_inference.py +0 -0
  38. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/landmark_pose_net.py +0 -0
  39. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/train_au_prediction.py +0 -0
  40. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/nn/train_landmark_pose.py +0 -0
  41. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/__init__.py +0 -0
  42. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/batched_au_predictor.py +0 -0
  43. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/model_parser.py +0 -0
  44. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/online_au_correction.py +0 -0
  45. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/running_median.py +0 -0
  46. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/prediction/running_median_fallback.py +0 -0
  47. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/processor.py +0 -0
  48. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/refinement/__init__.py +0 -0
  49. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/refinement/pdm.py +0 -0
  50. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/refinement/svr_patch_expert.py +0 -0
  51. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/refinement/targeted_refiner.py +0 -0
  52. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/utils/__init__.py +0 -0
  53. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/utils/cython_extensions/cython_histogram_median.pyx +0 -0
  54. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/utils/cython_extensions/cython_rotation_update.pyx +0 -0
  55. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau/utils/cython_extensions/setup.py +0 -0
  56. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau.egg-info/SOURCES.txt +0 -0
  57. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau.egg-info/dependency_links.txt +0 -0
  58. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau.egg-info/entry_points.txt +0 -0
  59. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau.egg-info/not-zip-safe +0 -0
  60. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau.egg-info/requires.txt +0 -0
  61. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau.egg-info/top_level.txt +0 -0
  62. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/pyfaceau_gui.py +0 -0
  63. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/requirements.txt +0 -0
  64. {pyfaceau-1.3.3 → pyfaceau-1.3.5}/setup.cfg +0 -0
@@ -7,14 +7,17 @@ include requirements.txt
7
7
  # Include Cython source files for building extensions
8
8
  recursive-include pyfaceau/utils/cython_extensions *.pyx *.pxd *.c
9
9
 
10
+ # Include pre-compiled Cython extensions (platform-specific)
11
+ # These provide 240x speedup for running median calculation
12
+ include pyfaceau/*.so
13
+ include pyfaceau/cython_*.so
14
+
10
15
  # Include package data files
11
16
  recursive-include pyfaceau *.txt *.json
12
17
 
13
- # Exclude compiled files and caches
18
+ # Exclude compiled files and caches (except our Cython extensions)
14
19
  global-exclude *.pyc
15
20
  global-exclude *.pyo
16
- global-exclude *.so
17
- global-exclude *.dylib
18
21
  global-exclude __pycache__
19
22
  global-exclude .DS_Store
20
23
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyfaceau
3
- Version: 1.3.3
3
+ Version: 1.3.5
4
4
  Summary: Pure Python OpenFace 2.2 AU extraction with CLNF landmark refinement
5
5
  Home-page: https://github.com/johnwilsoniv/face-analysis
6
6
  Author: John Wilson
@@ -16,9 +16,12 @@ CLNF_CONFIG = {
16
16
  'max_iterations': 10,
17
17
  'convergence_threshold': 0.005, # Gold standard (stricter than 0.01)
18
18
  'sigma': 2.25, # C++ CECLM default (1.5 × 1.5 scale factor)
19
- 'use_eye_refinement': True, # Enable hierarchical eye model refinement
19
+ 'use_eye_refinement': True, # Enabled: fixed transpose bug, now improves accuracy
20
20
  'convergence_profile': 'video', # Enable template tracking + scale adaptation
21
21
  'detector': False, # Disable built-in detector (pyfaceau handles)
22
+ 'use_gpu': True, # Enable GPU acceleration (10-20x speedup)
23
+ 'gpu_device': 'auto', # GPU device: 'auto', 'mps', 'cuda', 'cpu'
24
+ 'use_validator': False, # Disable detection validator (68% of CLNF time)
22
25
  }
23
26
 
24
27
  # =============================================================================
@@ -67,11 +70,9 @@ AU_CONFIG = {
67
70
  'max_stored_frames': 3000, # OpenFace default for re-prediction
68
71
 
69
72
  # AU-specific cutoff overrides
70
- # Python raw predictions are systematically higher than C++ for certain AUs.
71
- # These adjusted cutoffs compensate to match C++ behavior.
72
- # See diagnose_raw_prediction_diff.py for derivation.
73
+ # NOTE: With the fix to include zeros in cutoff calculation (matching C++),
74
+ # most overrides are no longer needed. Only keep AU26_r which has unusual behavior.
73
75
  'cutoff_overrides': {
74
- 'AU20_r': 0.40, # Original: 0.65 -> 0.9729 correlation (PASS)
75
76
  'AU26_r': 0.12, # Original: 0.30 -> 0.9317 correlation (best achievable)
76
77
  },
77
78
  }
@@ -130,6 +130,72 @@ class TrainingDataGenerator:
130
130
  # pyfhog 0.1.4+ outputs in OpenFace-compatible format (4464,)
131
131
  return hog.astype(np.float32)
132
132
 
133
+ def _crop_and_align_bbox(
134
+ self,
135
+ image: np.ndarray,
136
+ bbox: np.ndarray
137
+ ) -> tuple:
138
+ """
139
+ Crop face from image using bbox (matching NNCLNF inference alignment).
140
+
141
+ This creates the SAME alignment that NNCLNF uses at inference time,
142
+ ensuring training and inference see the same type of crops.
143
+
144
+ Args:
145
+ image: BGR image
146
+ bbox: Face bounding box [x, y, width, height]
147
+
148
+ Returns:
149
+ aligned_face: 112x112 BGR face image
150
+ warp_matrix: 2x3 affine transform matrix (for landmark transformation)
151
+ """
152
+ bbox_x, bbox_y, bbox_w, bbox_h = bbox
153
+
154
+ # Apply PyMTCNN bbox correction (matching NNCLNF)
155
+ bbox_x = bbox_x + bbox_w * 0.0625
156
+ bbox_y = bbox_y + bbox_h * 0.0625
157
+ bbox_w = bbox_w * 0.875
158
+ bbox_h = bbox_h * 0.875
159
+
160
+ size = max(bbox_w, bbox_h)
161
+ center_x = bbox_x + bbox_w / 2
162
+ center_y = bbox_y + bbox_h / 2
163
+
164
+ # Y offset correction (matching NNCLNF inference)
165
+ center_y -= size * 0.12
166
+
167
+ # Add padding (10% on each side)
168
+ padding = 0.1
169
+ size_with_pad = size * (1 + 2 * padding)
170
+
171
+ x1 = center_x - size_with_pad / 2
172
+ y1 = center_y - size_with_pad / 2
173
+ x2 = center_x + size_with_pad / 2
174
+ y2 = center_y + size_with_pad / 2
175
+
176
+ src_pts = np.array([
177
+ [x1, y1],
178
+ [x2, y1],
179
+ [x2, y2],
180
+ ], dtype=np.float32)
181
+
182
+ dst_pts = np.array([
183
+ [0, 0],
184
+ [112, 0],
185
+ [112, 112],
186
+ ], dtype=np.float32)
187
+
188
+ M = cv2.getAffineTransform(src_pts, dst_pts)
189
+
190
+ aligned_face = cv2.warpAffine(
191
+ image, M, (112, 112),
192
+ flags=cv2.INTER_LINEAR,
193
+ borderMode=cv2.BORDER_CONSTANT,
194
+ borderValue=(0, 0, 0)
195
+ )
196
+
197
+ return aligned_face, M
198
+
133
199
  def _predict_aus(self, hog_features: np.ndarray, geom_features: np.ndarray) -> np.ndarray:
134
200
  """Predict AU intensities from features."""
135
201
  full_vector = np.concatenate([hog_features, geom_features])
@@ -213,18 +279,10 @@ class TrainingDataGenerator:
213
279
  print(f" [DEBUG] CalcParams error: {e}")
214
280
  return None
215
281
 
216
- # Face alignment - also get the warp matrix for landmark transformation
282
+ # Face alignment - use bbox-based alignment (matching NNCLNF inference)
283
+ # This ensures training and inference use the SAME alignment approach
217
284
  try:
218
- tx, ty, rz = global_params[4], global_params[5], global_params[3]
219
- aligned_face, warp_matrix = self._face_aligner.align_face_with_matrix(
220
- image=frame,
221
- landmarks_68=landmarks,
222
- pose_tx=tx,
223
- pose_ty=ty,
224
- p_rz=rz,
225
- apply_mask=True,
226
- triangulation=self._triangulation
227
- )
285
+ aligned_face, warp_matrix = self._crop_and_align_bbox(frame, bbox)
228
286
  except Exception as e:
229
287
  if self.config.verbose:
230
288
  print(f" [DEBUG] Face alignment error: {e}")
@@ -217,7 +217,8 @@ class ParallelAUPipeline:
217
217
  geom_features = frame_features['geom_features']
218
218
 
219
219
  # Update running median (must be sequential)
220
- update_histogram = (idx % 2 == 1)
220
+ # C++ increments frames_tracking BEFORE check, update on even frames
221
+ update_histogram = (idx % 2 == 0)
221
222
  self.main_pipeline.running_median.update(
222
223
  hog_features,
223
224
  geom_features,
@@ -44,7 +44,7 @@ from pyfaceau.refinement.targeted_refiner import TargetedCLNFRefiner
44
44
 
45
45
  # Import Cython-optimized running median (with fallback)
46
46
  try:
47
- from cython_histogram_median import DualHistogramMedianTrackerCython as DualHistogramMedianTracker
47
+ from pyfaceau.cython_histogram_median import DualHistogramMedianTrackerCython as DualHistogramMedianTracker
48
48
  USING_CYTHON = True
49
49
  except ImportError:
50
50
  from pyfaceau.features.histogram_median_tracker import DualHistogramMedianTracker
@@ -57,6 +57,9 @@ try:
57
57
  except ImportError:
58
58
  USING_BATCHED_PREDICTOR = False
59
59
 
60
+ # NNCLNF (neural network replacement for CLNF) is defunct and archived
61
+ # Use pyclnf with GPU acceleration instead for best accuracy + speed
62
+
60
63
  # Import online AU correction (C++ CorrectOnlineAUs equivalent)
61
64
  from pyfaceau.prediction.online_au_correction import OnlineAUCorrection
62
65
 
@@ -191,6 +194,7 @@ class FullPythonAUPipeline:
191
194
  use_calc_params: bool = True,
192
195
  track_faces: bool = True,
193
196
  use_batched_predictor: bool = True,
197
+ use_nnclnf: str = 'pyclnf', # NNCLNF is defunct, always use pyclnf
194
198
  max_clnf_iterations: int = CLNF_CONFIG['max_iterations'],
195
199
  clnf_convergence_threshold: float = CLNF_CONFIG['convergence_threshold'],
196
200
  debug_mode: bool = False,
@@ -199,7 +203,7 @@ class FullPythonAUPipeline:
199
203
  """
200
204
  Initialize the full Python AU pipeline (OpenFace-compatible)
201
205
 
202
- Architecture: PyMTCNN → CLNF → AU Prediction
206
+ Architecture: PyMTCNN → pyclnf CLNF → AU Prediction
203
207
  (matches OpenFace C++ 2.2 pipeline)
204
208
 
205
209
  Args:
@@ -211,6 +215,7 @@ class FullPythonAUPipeline:
211
215
  use_calc_params: DEPRECATED - pyclnf params are now used instead (default: True)
212
216
  track_faces: Use face tracking between frames (default: True)
213
217
  use_batched_predictor: Use optimized batched AU predictor (default: True)
218
+ use_nnclnf: DEPRECATED - always uses pyclnf (NNCLNF is defunct)
214
219
  max_clnf_iterations: Maximum CLNF optimization iterations (default: 10)
215
220
  clnf_convergence_threshold: CLNF convergence threshold in pixels (default: 0.01)
216
221
  debug_mode: Enable debug mode for diagnostics (default: False)
@@ -236,6 +241,7 @@ class FullPythonAUPipeline:
236
241
  'au_models_dir': au_models_dir,
237
242
  'triangulation_file': triangulation_file,
238
243
  'patch_expert_file': patch_expert_file,
244
+ 'use_nnclnf': use_nnclnf,
239
245
  'max_clnf_iterations': max_clnf_iterations,
240
246
  'clnf_convergence_threshold': clnf_convergence_threshold,
241
247
  }
@@ -317,11 +323,12 @@ class FullPythonAUPipeline:
317
323
  print(f" Active backend: {backend_info}")
318
324
  print("Face detector loaded\n")
319
325
 
320
- # Component 2: Landmark Detection (CLNF - OpenFace approach via pyclnf)
326
+ # Component 2: Landmark Detection (pyclnf CLNF with GPU acceleration)
321
327
  if self.verbose:
322
328
  print("[2/8] Loading CLNF landmark detector (pyclnf)...")
323
329
  print(f" Max iterations: {max_clnf_iterations}")
324
330
  print(f" Convergence threshold: {clnf_convergence_threshold} pixels")
331
+ print(f" GPU enabled: {CLNF_CONFIG.get('use_gpu', False)}")
325
332
 
326
333
  # Lazy import to avoid circular import (pyfaceau ↔ pyclnf)
327
334
  from pyclnf import CLNF
@@ -333,8 +340,12 @@ class FullPythonAUPipeline:
333
340
  detector=CLNF_CONFIG['detector'], # Disable built-in PyMTCNN (pyfaceau handles detection)
334
341
  use_eye_refinement=CLNF_CONFIG['use_eye_refinement'], # Enable hierarchical eye model refinement
335
342
  convergence_profile=CLNF_CONFIG['convergence_profile'], # Enable video mode with template tracking + scale adaptation
336
- sigma=CLNF_CONFIG['sigma'] # KDE kernel sigma matching C++ CECLM
343
+ sigma=CLNF_CONFIG['sigma'], # KDE kernel sigma matching C++ CECLM
344
+ use_gpu=CLNF_CONFIG.get('use_gpu', False), # GPU acceleration (10-20x speedup)
345
+ gpu_device=CLNF_CONFIG.get('gpu_device', 'auto'), # GPU device selection
346
+ use_validator=CLNF_CONFIG.get('use_validator', True) # Detection validator (disabled for speed)
337
347
  )
348
+
338
349
  if self.verbose:
339
350
  print(f"CLNF detector loaded\n")
340
351
 
@@ -429,6 +440,18 @@ class FullPythonAUPipeline:
429
440
 
430
441
  self._components_initialized = True
431
442
 
443
+ @property
444
+ def using_nnclnf(self) -> bool:
445
+ """DEPRECATED: NNCLNF is defunct, always returns False."""
446
+ return False
447
+
448
+ @property
449
+ def landmark_detector_name(self) -> str:
450
+ """Get the name of the landmark detector being used."""
451
+ if not self._components_initialized:
452
+ return "not initialized"
453
+ return "pyclnf"
454
+
432
455
  def _initialize_landmarks_from_bbox(self, bbox):
433
456
  """
434
457
  Initialize 2D landmarks from PDM mean shape scaled to fit bbox.
@@ -893,7 +916,9 @@ class FullPythonAUPipeline:
893
916
  t0 = time.time() if debug_info is not None else None
894
917
  if self.verbose and frame_idx < 3:
895
918
  print(f"[Frame {frame_idx}] Step 7: Updating running median...")
896
- update_histogram = (frame_idx % 2 == 1) # Every 2nd frame
919
+ # C++ increments frames_tracking BEFORE the check, so frame 0 → counter=1 update
920
+ # To match: update on frames 0, 2, 4, 6... (even frames)
921
+ update_histogram = (frame_idx % 2 == 0) # Match C++ timing
897
922
  self.running_median.update(hog_features, geom_features, update_histogram=update_histogram)
898
923
  running_median = self.running_median.get_combined_median()
899
924
  if self.verbose and frame_idx < 3:
@@ -1089,10 +1114,16 @@ class FullPythonAUPipeline:
1089
1114
  if model_cutoff <= 0 or model_cutoff >= 1.0:
1090
1115
  continue
1091
1116
 
1092
- # Fix 2: Match C++ - sort only VALID (non-zero) predictions
1093
- # C++ FaceAnalyser.cpp:656 uses au_good which excludes zeros
1117
+ # Match C++ - include ALL values from successful frames
1118
+ # C++ FaceAnalyser.cpp uses au_good which includes all values from frames
1119
+ # where successes[frame]==true, INCLUDING zeros
1094
1120
  au_values = df[au_col].values
1095
- valid_mask = au_values > 0.001 # Filter out zeros/near-zeros
1121
+
1122
+ # Filter by success flag if available, otherwise use all non-NaN values
1123
+ if 'success' in df.columns:
1124
+ valid_mask = df['success'].values == 1
1125
+ else:
1126
+ valid_mask = ~np.isnan(au_values)
1096
1127
  valid_vals = au_values[valid_mask]
1097
1128
 
1098
1129
  # Need enough valid values to compute meaningful percentile
@@ -302,7 +302,8 @@ class OpenFace22AUPredictor:
302
302
  geom_feat = self._extract_geometric_features(csv_data.iloc[i])
303
303
 
304
304
  # Update tracker (every 2nd frame)
305
- update_histogram = (i % 2 == 1)
305
+ # C++ increments frames_tracking BEFORE check, update on even frames
306
+ update_histogram = (i % 2 == 0)
306
307
  median_tracker.update(hog_feat, geom_feat, update_histogram=update_histogram)
307
308
 
308
309
  # Store running median
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyfaceau
3
- Version: 1.3.3
3
+ Version: 1.3.5
4
4
  Summary: Pure Python OpenFace 2.2 AU extraction with CLNF landmark refinement
5
5
  Home-page: https://github.com/johnwilsoniv/face-analysis
6
6
  Author: John Wilson
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyfaceau"
7
- version = "1.3.3"
7
+ version = "1.3.5"
8
8
  description = "Pure Python OpenFace 2.2 AU extraction with CLNF landmark refinement"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -67,4 +67,11 @@ include = ["pyfaceau*"]
67
67
  exclude = ["tests*", "tools*", "benchmarks*"]
68
68
 
69
69
  [tool.setuptools.package-data]
70
- pyfaceau = ["*.txt", "*.json", "utils/cython_extensions/*.pyx", "utils/cython_extensions/*.pxd"]
70
+ pyfaceau = [
71
+ "*.txt",
72
+ "*.json",
73
+ "*.so", # Pre-compiled Cython extensions (240x speedup)
74
+ "cython_*.so",
75
+ "utils/cython_extensions/*.pyx",
76
+ "utils/cython_extensions/*.pxd",
77
+ ]
@@ -11,7 +11,7 @@ long_description = (this_directory / "README.md").read_text()
11
11
 
12
12
  setup(
13
13
  name="pyfaceau",
14
- version="1.3.3",
14
+ version="1.3.5",
15
15
  author="John Wilson",
16
16
  author_email="", # Add email if desired
17
17
  description="Pure Python OpenFace 2.2 AU extraction with PyMTCNN face detection and CLNF refinement",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes