@brainpilot/skills 0.0.6 → 0.0.8

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 (285) hide show
  1. package/package.json +2 -2
  2. package/skills/01_Meta-Skills/academic-research-hub/SKILL.md +108 -0
  3. package/skills/01_Meta-Skills/academic-research-hub/scripts/requirements.txt +17 -0
  4. package/skills/01_Meta-Skills/academic-research-hub/scripts/research.py +781 -0
  5. package/skills/01_Meta-Skills/beautiful-log/SKILL.md +64 -0
  6. package/skills/01_Meta-Skills/beautiful-log/scripts/beautiful_log.py +274 -0
  7. package/skills/01_Meta-Skills/ethoclaw-daily-paper/SKILL.md +130 -0
  8. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/config.template.yaml +54 -0
  9. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/top5_digest_template.md +5 -0
  10. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/build_top5_digest.py +300 -0
  11. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/common.py +137 -0
  12. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/merge_results.py +106 -0
  13. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/run_pipeline.py +177 -0
  14. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_arxiv.py +162 -0
  15. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_pubmed.py +202 -0
  16. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/SKILL.md +173 -0
  17. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/scripts/normalize_data.py +874 -0
  18. package/skills/01_Meta-Skills/ethoclaw-pdf-research/SKILL.md +134 -0
  19. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/confirmation-prompts.md +31 -0
  20. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/output-patterns.md +45 -0
  21. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_markdown_deliverables.py +41 -0
  22. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_research_log.py +84 -0
  23. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_summary_md.py +63 -0
  24. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/extract_pdf_bundle.py +140 -0
  25. package/skills/01_Meta-Skills/experiment-controller/SKILL.md +140 -0
  26. package/skills/01_Meta-Skills/knowledge-graph-builder/SKILL.md +366 -0
  27. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/entity_resolution.py +120 -0
  28. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/extraction_prompt_template.txt +19 -0
  29. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/graph_query.py +106 -0
  30. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/hypothesis_cli_reference.py +42 -0
  31. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/new_data_source_template.py +116 -0
  32. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/requirements.txt +15 -0
  33. package/skills/01_Meta-Skills/method-design/SKILL.md +61 -0
  34. package/skills/01_Meta-Skills/multi-search-engine/SKILL.md +119 -0
  35. package/skills/01_Meta-Skills/research-idea/SKILL.md +65 -0
  36. package/skills/05_EEG_ERP/eeg-skill/SKILL.md +197 -0
  37. package/skills/05_EEG_ERP/meg-skill/SKILL.md +188 -0
  38. package/skills/05_EEG_ERP/meg-skill/scripts/time_frequency.py +223 -0
  39. package/skills/05_EEG_ERP/mne-eeg-tool/SKILL.md +165 -0
  40. package/skills/05_EEG_ERP/mne-eeg-tool/scripts/eeg_pipeline_reference.py +231 -0
  41. package/skills/05_EEG_ERP/seed-iv-skill/SKILL.md +184 -0
  42. package/skills/05_EEG_ERP/seed-iv-skill/scripts/classify_seed_iv.py +154 -0
  43. package/skills/05_EEG_ERP/seed-iv-skill/scripts/extract_seed_iv_features.py +190 -0
  44. package/skills/05_EEG_ERP/seed-iv-skill/scripts/validate_seed_iv.py +102 -0
  45. package/skills/05_EEG_ERP/seed-vig-skill/SKILL.md +182 -0
  46. package/skills/05_EEG_ERP/seed-vig-skill/scripts/classify_seed_vig.py +165 -0
  47. package/skills/05_EEG_ERP/seed-vig-skill/scripts/extract_seed_vig_features.py +185 -0
  48. package/skills/05_EEG_ERP/seed-vig-skill/scripts/validate_seed_vig.py +88 -0
  49. package/skills/06_fMRI_Neuroimaging/abcd-skill/SKILL.md +308 -0
  50. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/abcd_qc_summary.py +449 -0
  51. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/extract_abcd_phenotype.py +292 -0
  52. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/reorganize_abcd.py +387 -0
  53. package/skills/06_fMRI_Neuroimaging/abide-skill/SKILL.md +302 -0
  54. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/abide_qc_summary.py +317 -0
  55. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/extract_abide_phenotype.py +267 -0
  56. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/reorganize_abide.py +387 -0
  57. package/skills/06_fMRI_Neuroimaging/adhd200-skill/SKILL.md +244 -0
  58. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/adhd200_qc_summary.py +98 -0
  59. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/extract_adhd200_phenotype.py +134 -0
  60. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/reorganize_adhd200.py +206 -0
  61. package/skills/06_fMRI_Neuroimaging/adni-skill/SKILL.md +358 -0
  62. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_adni_task_files.py +1305 -0
  63. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_vqa_from_tasks.py +766 -0
  64. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/reorganize_adni.py +491 -0
  65. package/skills/06_fMRI_Neuroimaging/aibl-skill/SKILL.md +295 -0
  66. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/aibl_qc_summary.py +260 -0
  67. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/extract_aibl_phenotype.py +365 -0
  68. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/reorganize_aibl.py +394 -0
  69. package/skills/06_fMRI_Neuroimaging/aomic-skill/SKILL.md +292 -0
  70. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/aomic_qc_summary.py +258 -0
  71. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/extract_aomic_phenotype.py +284 -0
  72. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/reorganize_aomic.py +322 -0
  73. package/skills/06_fMRI_Neuroimaging/asl-skill/SKILL.md +168 -0
  74. package/skills/06_fMRI_Neuroimaging/asl-skill/scripts/compute_cbf.py +224 -0
  75. package/skills/06_fMRI_Neuroimaging/bids-organizer/SKILL.md +241 -0
  76. package/skills/06_fMRI_Neuroimaging/bold5000-skill/SKILL.md +186 -0
  77. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/bold5000_qc_summary.py +96 -0
  78. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/extract_bold5000_stimulus.py +125 -0
  79. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/reorganize_bold5000.py +102 -0
  80. package/skills/06_fMRI_Neuroimaging/camcan-skill/SKILL.md +213 -0
  81. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/camcan_qc_summary.py +131 -0
  82. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/extract_camcan_phenotype.py +145 -0
  83. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/validate_camcan.py +141 -0
  84. package/skills/06_fMRI_Neuroimaging/cobre-skill/SKILL.md +201 -0
  85. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/cobre_qc_summary.py +95 -0
  86. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/extract_cobre_phenotype.py +104 -0
  87. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/reorganize_cobre.py +140 -0
  88. package/skills/06_fMRI_Neuroimaging/conn-tool/SKILL.md +180 -0
  89. package/skills/06_fMRI_Neuroimaging/dcm2nii/SKILL.md +189 -0
  90. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/SKILL.md +183 -0
  91. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/dmt_har_med_qc_summary.py +96 -0
  92. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/extract_dmt_har_med_phenotype.py +121 -0
  93. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/reorganize_dmt_har_med.py +125 -0
  94. package/skills/06_fMRI_Neuroimaging/dwi-skill/SKILL.md +359 -0
  95. package/skills/06_fMRI_Neuroimaging/fmri-skill/SKILL.md +371 -0
  96. package/skills/06_fMRI_Neuroimaging/fmriprep-tool/SKILL.md +228 -0
  97. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/SKILL.md +286 -0
  98. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/scripts/freesurfer_processor.py +145 -0
  99. package/skills/06_fMRI_Neuroimaging/fsl-tool/SKILL.md +208 -0
  100. package/skills/06_fMRI_Neuroimaging/hbn-skill/SKILL.md +271 -0
  101. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/extract_hbn_phenotype.py +107 -0
  102. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/hbn_qc_summary.py +96 -0
  103. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/reorganize_hbn.py +150 -0
  104. package/skills/06_fMRI_Neuroimaging/hcpa-skill/SKILL.md +210 -0
  105. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/extract_hcpa_phenotype.py +146 -0
  106. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/hcpa_qc_summary.py +120 -0
  107. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/reorganize_hcpa.py +155 -0
  108. package/skills/06_fMRI_Neuroimaging/hcpd-skill/SKILL.md +210 -0
  109. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/extract_hcpd_phenotype.py +148 -0
  110. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/hcpd_qc_summary.py +125 -0
  111. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/reorganize_hcpd.py +146 -0
  112. package/skills/06_fMRI_Neuroimaging/hcpep-skill/SKILL.md +215 -0
  113. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/extract_hcpep_phenotype.py +157 -0
  114. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/hcpep_qc_summary.py +143 -0
  115. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/reorganize_hcpep.py +146 -0
  116. package/skills/06_fMRI_Neuroimaging/hcppipeline-tool/SKILL.md +217 -0
  117. package/skills/06_fMRI_Neuroimaging/hcpya-skill/SKILL.md +214 -0
  118. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/extract_hcpya_phenotype.py +190 -0
  119. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/hcpya_qc_summary.py +152 -0
  120. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/reorganize_hcpya.py +203 -0
  121. package/skills/06_fMRI_Neuroimaging/ixi-skill/SKILL.md +198 -0
  122. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/ixi_qc_summary.py +137 -0
  123. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/reorganize_ixi.py +190 -0
  124. package/skills/06_fMRI_Neuroimaging/mnd-skill/SKILL.md +191 -0
  125. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/extract_mnd_phenotype.py +143 -0
  126. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/mnd_qc_summary.py +120 -0
  127. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/validate_mnd.py +107 -0
  128. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/SKILL.md +203 -0
  129. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/analyze_lesions.py +119 -0
  130. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/longitudinal_lesion.py +148 -0
  131. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/mschallenge_qc_summary.py +132 -0
  132. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/validate_mschallenge.py +116 -0
  133. package/skills/06_fMRI_Neuroimaging/nibabel-skill/SKILL.md +184 -0
  134. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/atlas_coordinate_reference.py +61 -0
  135. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/freesurfer_io_reference.py +34 -0
  136. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/nifti_inspection_reference.py +35 -0
  137. package/skills/06_fMRI_Neuroimaging/nifd-skill/SKILL.md +205 -0
  138. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/extract_nifd_phenotype.py +132 -0
  139. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/nifd_qc_summary.py +111 -0
  140. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/validate_nifd.py +111 -0
  141. package/skills/06_fMRI_Neuroimaging/nii2dcm/SKILL.md +143 -0
  142. package/skills/06_fMRI_Neuroimaging/nilearn-tool/SKILL.md +266 -0
  143. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/connectome_reference.py +65 -0
  144. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/denoise_timeseries_reference.py +58 -0
  145. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/hierarchical_parcellation_reference.py +53 -0
  146. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/kmeans_parcellation_reference.py +53 -0
  147. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/preprocess_bold_reference.py +76 -0
  148. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_dictlearning_reference.py +56 -0
  149. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_ica_reference.py +59 -0
  150. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/second_level_glm_reference.py +58 -0
  151. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/spacenet_classifier_reference.py +59 -0
  152. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/svm_classifier_reference.py +60 -0
  153. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/task_glm_reference.py +63 -0
  154. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/zalff_summary_reference.py +109 -0
  155. package/skills/06_fMRI_Neuroimaging/nsd-skill/SKILL.md +210 -0
  156. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/extract_nsd_stimulus.py +171 -0
  157. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/nsd_qc_summary.py +142 -0
  158. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/validate_nsd.py +142 -0
  159. package/skills/06_fMRI_Neuroimaging/oasis-skill/SKILL.md +205 -0
  160. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/extract_oasis_phenotype.py +126 -0
  161. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/oasis_qc_summary.py +115 -0
  162. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/validate_oasis.py +119 -0
  163. package/skills/06_fMRI_Neuroimaging/pet-skill/SKILL.md +173 -0
  164. package/skills/06_fMRI_Neuroimaging/pet-skill/scripts/compute_suvr.py +202 -0
  165. package/skills/06_fMRI_Neuroimaging/pnc-skill/SKILL.md +206 -0
  166. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/extract_pnc_phenotype.py +136 -0
  167. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/pnc_qc_summary.py +116 -0
  168. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/validate_pnc.py +120 -0
  169. package/skills/06_fMRI_Neuroimaging/ppmi-skill/SKILL.md +209 -0
  170. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/extract_ppmi_phenotype.py +138 -0
  171. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/ppmi_qc_summary.py +111 -0
  172. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/validate_ppmi.py +117 -0
  173. package/skills/06_fMRI_Neuroimaging/qsiprep-tool/SKILL.md +320 -0
  174. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/SKILL.md +215 -0
  175. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/extract_rest_mdd_phenotype.py +132 -0
  176. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/harmonize_sites.py +152 -0
  177. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/rest_mdd_qc_summary.py +124 -0
  178. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/validate_rest_mdd.py +103 -0
  179. package/skills/06_fMRI_Neuroimaging/smri-skill/SKILL.md +302 -0
  180. package/skills/06_fMRI_Neuroimaging/tcp-skill/SKILL.md +204 -0
  181. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/extract_tcp_phenotype.py +139 -0
  182. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/tcp_qc_summary.py +111 -0
  183. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/validate_tcp.py +99 -0
  184. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/SKILL.md +217 -0
  185. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/extract_ucla_cnp_phenotype.py +145 -0
  186. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/ucla_cnp_qc_summary.py +111 -0
  187. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/validate_ucla_cnp.py +113 -0
  188. package/skills/06_fMRI_Neuroimaging/ukb-skill/SKILL.md +310 -0
  189. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/build_ukb_survival.py +210 -0
  190. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_cases.py +308 -0
  191. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_phenotype.py +232 -0
  192. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/ukb_qc_summary.py +158 -0
  193. package/skills/06_fMRI_Neuroimaging/wmh-segmentation/SKILL.md +133 -0
  194. package/skills/07_Computational_Modeling/detrending/SKILL.md +118 -0
  195. package/skills/07_Computational_Modeling/dictlearning/SKILL.md +122 -0
  196. package/skills/07_Computational_Modeling/filtering/SKILL.md +121 -0
  197. package/skills/07_Computational_Modeling/glm/SKILL.md +153 -0
  198. package/skills/07_Computational_Modeling/hierarchical/SKILL.md +121 -0
  199. package/skills/07_Computational_Modeling/ica/SKILL.md +122 -0
  200. package/skills/07_Computational_Modeling/kmeans/SKILL.md +119 -0
  201. package/skills/07_Computational_Modeling/run_models/SKILL.md +427 -0
  202. package/skills/07_Computational_Modeling/spacenet/SKILL.md +122 -0
  203. package/skills/07_Computational_Modeling/svm/SKILL.md +120 -0
  204. package/skills/08_Computational_Neuroscience/brain_gnn/SKILL.md +183 -0
  205. package/skills/08_Computational_Neuroscience/dipy-tool/SKILL.md +239 -0
  206. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/dti_metrics_reference.py +70 -0
  207. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/load_and_mask_reference.py +76 -0
  208. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/roi_stats_reference.py +59 -0
  209. package/skills/08_Computational_Neuroscience/fm_app/SKILL.md +195 -0
  210. package/skills/08_Computational_Neuroscience/neurostorm/SKILL.md +151 -0
  211. package/skills/13_Visualization/brain-visualization/SKILL.md +191 -0
  212. package/skills/13_Visualization/brain-visualization/scripts/connectome_reference.py +108 -0
  213. package/skills/13_Visualization/brain-visualization/scripts/freesurfer_ply_reference.py +54 -0
  214. package/skills/13_Visualization/brain-visualization/scripts/zalff_summary_reference.py +116 -0
  215. package/skills/13_Visualization/ethoclaw-paper-figure-layout/SKILL.md +78 -0
  216. package/skills/13_Visualization/ethoclaw-paper-figure-layout/assets/naturecomm_figures.tex +74 -0
  217. package/skills/13_Visualization/ethoclaw-paper-figure-layout/scripts/layout_results_foldered.py +579 -0
  218. package/skills/14_Writing/overleaf-skill/SKILL.md +184 -0
  219. package/skills/14_Writing/overleaf-skill/scripts/install.sh +30 -0
  220. package/skills/14_Writing/paper-writing/SKILL.md +146 -0
  221. package/skills/14_Writing/paper-writing/scripts/data_statement_templates.py +164 -0
  222. package/skills/14_Writing/paper-writing/scripts/figure_templates.py +315 -0
  223. package/skills/14_Writing/paper-writing/scripts/nature_figure_style.py +214 -0
  224. package/skills/14_Writing/paper-writing/scripts/section_phrasebank.py +246 -0
  225. package/skills/16_Animal_Behavior/deeplabcut/SKILL.md +154 -0
  226. package/skills/16_Animal_Behavior/deeplabcut/references/3d-pose.md +89 -0
  227. package/skills/16_Animal_Behavior/deeplabcut/references/maDLC.md +123 -0
  228. package/skills/16_Animal_Behavior/deeplabcut/references/modelzoo.md +98 -0
  229. package/skills/16_Animal_Behavior/deeplabcut/references/standard-pipeline.md +165 -0
  230. package/skills/16_Animal_Behavior/deeplabcut/references/utilities.md +146 -0
  231. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/SKILL.md +274 -0
  232. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.html +112 -0
  233. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.md +21 -0
  234. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/cluster-section.md +5 -0
  235. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/heatmap-section.md +5 -0
  236. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/integrated-interpretation.md +3 -0
  237. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/overview.md +3 -0
  238. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/project-summary.md +3 -0
  239. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/radar-section.md +5 -0
  240. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/raw-trajectory.md +3 -0
  241. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/sample-check.md +3 -0
  242. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/single-subject-section.md +3 -0
  243. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/stats-section.md +5 -0
  244. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/epm.md +52 -0
  245. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/fst.md +37 -0
  246. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/nor.md +39 -0
  247. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/oft.md +43 -0
  248. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tcst.md +45 -0
  249. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tst.md +36 -0
  250. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/input-types.md +59 -0
  251. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/interpretation-guardrails.md +45 -0
  252. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/metadata-schema.md +57 -0
  253. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/report-sections.md +86 -0
  254. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/section-selection-rules.md +169 -0
  255. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/build_report_manifest.py +27 -0
  256. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/render_report.py +34 -0
  257. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/report_utils.py +1121 -0
  258. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/SKILL.md +390 -0
  259. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/reference_code.py +98 -0
  260. package/skills/16_Animal_Behavior/ethoclaw-animal-pose-estimation/SKILL.md +336 -0
  261. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/README.md +21 -0
  262. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/SKILL.md +41 -0
  263. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/batch_kinematic_generator.py +663 -0
  264. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/config.json +19 -0
  265. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/generate_kinematic_parameter.py +401 -0
  266. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/kinematic_generator.py +265 -0
  267. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/SKILL.md +72 -0
  268. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/references/config.example.toml +56 -0
  269. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params.py +232 -0
  270. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params_from_config.py +236 -0
  271. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/SKILL.md +68 -0
  272. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/references/notes.md +5 -0
  273. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/scripts/plot_h5_radar.py +513 -0
  274. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/SKILL.md +52 -0
  275. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/config.toml +81 -0
  276. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/references/stats-rule.md +18 -0
  277. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_inspect.py +79 -0
  278. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_batch.py +624 -0
  279. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_stats.py +438 -0
  280. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/SKILL.md +280 -0
  281. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_trajectory.py +790 -0
  282. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_velocity.py +855 -0
  283. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.csv +101 -0
  284. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.h5 +0 -0
  285. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_data_readme.md +126 -0
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """Generate /KinematicParameter in an existing .h5 file.
5
+
6
+ Reads:
7
+ /2Dskeleton/BodyParts (n_bodyparts,)
8
+ /2Dskeleton/data2D (n_frames, n_bodyparts*3) -> [x, y, likelihood] per bodypart
9
+
10
+ Uses FPS from:
11
+ 1) /VideoInfo/fps if present and >0
12
+ 2) if missing/0 and --search-video is enabled: try to locate a same-stem video
13
+ (e.g. rec-1-xxx.mp4/.avi/...) under common folders and read FPS from it.
14
+ 3) fallback to --fps-default
15
+
16
+ Optionally uses calibration from:
17
+ /CalibrationInfo/px_mm_ratio_x, /CalibrationInfo/px_mm_ratio_y
18
+
19
+ Writes (in-place):
20
+ /KinematicParameter/ParameterName (n_params,)
21
+ /KinematicParameter/ParameterData (n_frames, n_params)
22
+
23
+ n_params = 4*n_bodyparts + 2
24
+ (x_, y_, distance_, speed_) per bodypart + (frame_distance, frame_speed)
25
+
26
+ NOTE: This script edits the input file in-place.
27
+ """
28
+
29
+ import argparse
30
+ import os
31
+ import shutil
32
+ import subprocess
33
+ from pathlib import Path
34
+ from typing import Iterable, List, Optional
35
+
36
+ import numpy as np
37
+ import h5py
38
+
39
+
40
+ VIDEO_EXTENSIONS = [
41
+ ".mp4",
42
+ ".avi",
43
+ ".mkv",
44
+ ".mov",
45
+ ".wmv",
46
+ ".flv",
47
+ ".mpeg",
48
+ ".mpg",
49
+ ]
50
+
51
+
52
+ def _decode(x):
53
+ if isinstance(x, (bytes, np.bytes_)):
54
+ return x.decode("utf-8", errors="ignore")
55
+ return str(x)
56
+
57
+
58
+ def _as_bytes_array(str_list: List[str]):
59
+ # store as fixed-width bytes in HDF5 for portability
60
+ return np.array([s.encode("utf-8") for s in str_list], dtype="S")
61
+
62
+
63
+ def fps_from_video_opencv(video_path: Path) -> float:
64
+ try:
65
+ import cv2 # type: ignore
66
+ except Exception as e:
67
+ raise RuntimeError(
68
+ "OpenCV (cv2) is not available. Install it in your conda env, e.g.\n"
69
+ " conda install -c conda-forge opencv\n"
70
+ f"Original import error: {e}"
71
+ )
72
+
73
+ cap = cv2.VideoCapture(str(video_path))
74
+ fps = float(cap.get(cv2.CAP_PROP_FPS))
75
+ cap.release()
76
+ if not fps or fps <= 1e-6:
77
+ raise RuntimeError(f"Cannot read FPS via OpenCV from: {video_path}")
78
+ return fps
79
+
80
+
81
+ def _parse_rate(rate: str) -> Optional[float]:
82
+ rate = (rate or "").strip()
83
+ if not rate:
84
+ return None
85
+ if "/" in rate:
86
+ a, b = rate.split("/", 1)
87
+ try:
88
+ a = float(a)
89
+ b = float(b)
90
+ if b != 0:
91
+ return a / b
92
+ except Exception:
93
+ return None
94
+ try:
95
+ return float(rate)
96
+ except Exception:
97
+ return None
98
+
99
+
100
+ def fps_from_video_ffprobe(video_path: Path) -> float:
101
+ ffprobe = shutil.which("ffprobe")
102
+ if not ffprobe:
103
+ raise RuntimeError(
104
+ "ffprobe is not available on PATH. Install ffmpeg/ffprobe or use OpenCV.\n"
105
+ "- On conda (recommended): conda install -c conda-forge ffmpeg\n"
106
+ "- Or: conda install -c conda-forge opencv"
107
+ )
108
+
109
+ # Try avg_frame_rate first, then r_frame_rate
110
+ cmd = [
111
+ ffprobe,
112
+ "-v",
113
+ "error",
114
+ "-select_streams",
115
+ "v:0",
116
+ "-show_entries",
117
+ "stream=avg_frame_rate,r_frame_rate",
118
+ "-of",
119
+ "default=nk=1:nw=1",
120
+ str(video_path),
121
+ ]
122
+ out = subprocess.check_output(cmd, stderr=subprocess.STDOUT, text=True).strip().splitlines()
123
+ # output lines: avg_frame_rate, r_frame_rate (order not strictly guaranteed)
124
+ rates = [_parse_rate(x) for x in out]
125
+ rates = [x for x in rates if x and x > 1e-6]
126
+ if not rates:
127
+ raise RuntimeError(f"Cannot parse FPS from ffprobe output for: {video_path}\nOutput: {out}")
128
+ # prefer a sensible fps
129
+ return float(rates[0])
130
+
131
+
132
+ def fps_from_video(video_path: Path) -> float:
133
+ """Try OpenCV first (if installed), otherwise ffprobe."""
134
+ try:
135
+ return fps_from_video_opencv(video_path)
136
+ except Exception:
137
+ # fall back to ffprobe
138
+ return fps_from_video_ffprobe(video_path)
139
+
140
+
141
+ def _candidate_search_dirs(h5_path: Path, max_parent_levels: int = 2) -> List[Path]:
142
+ """Generate likely directories for locating a same-stem video."""
143
+ h5_dir = h5_path.parent
144
+ subs = ["videos", "video", "Videos", "Video", "data", "Data"]
145
+
146
+ dirs: List[Path] = []
147
+ # current dir and common subdirs
148
+ dirs.append(h5_dir)
149
+ for s in subs:
150
+ dirs.append(h5_dir / s)
151
+
152
+ # parent dirs and their common subdirs
153
+ cur = h5_dir
154
+ for _ in range(max_parent_levels):
155
+ cur = cur.parent
156
+ dirs.append(cur)
157
+ for s in subs:
158
+ dirs.append(cur / s)
159
+
160
+ # de-dup while preserving order
161
+ seen = set()
162
+ out = []
163
+ for d in dirs:
164
+ dp = d.resolve() if d.exists() else d
165
+ key = str(dp)
166
+ if key not in seen:
167
+ seen.add(key)
168
+ out.append(d)
169
+ return out
170
+
171
+
172
+ def find_video_for_h5(
173
+ h5_path: Path,
174
+ exts: Iterable[str] = VIDEO_EXTENSIONS,
175
+ max_parent_levels: int = 2,
176
+ ) -> Optional[Path]:
177
+ """Search for a same-stem video file near the h5 path."""
178
+ stem = h5_path.stem
179
+ exts = [e if e.startswith(".") else "." + e for e in exts]
180
+
181
+ for d in _candidate_search_dirs(h5_path, max_parent_levels=max_parent_levels):
182
+ if not d.exists() or not d.is_dir():
183
+ continue
184
+ # direct same-stem match
185
+ for ext in exts:
186
+ p = d / (stem + ext)
187
+ if p.exists():
188
+ return p
189
+ # case-insensitive check (Windows naming via WSL can be odd)
190
+ try:
191
+ for cand in d.glob(stem + ".*"):
192
+ if cand.suffix.lower() == ext.lower() and cand.exists():
193
+ return cand
194
+ except Exception:
195
+ pass
196
+
197
+ return None
198
+
199
+
200
+ def load_fps(
201
+ h5,
202
+ h5_path: Path,
203
+ fps_default: float = 30.0,
204
+ search_video: bool = True,
205
+ video_path: Optional[Path] = None,
206
+ max_parent_levels: int = 2,
207
+ ) -> float:
208
+ """Load fps from h5, or from a located video, or fallback."""
209
+ fps = None
210
+ if "VideoInfo" in h5 and "fps" in h5["VideoInfo"]:
211
+ try:
212
+ fps = float(h5["VideoInfo"]["fps"][()])
213
+ except Exception:
214
+ fps = None
215
+
216
+ if fps is not None and fps > 1e-6:
217
+ return float(fps)
218
+
219
+ if search_video:
220
+ vp = Path(video_path) if video_path else find_video_for_h5(h5_path, max_parent_levels=max_parent_levels)
221
+ if vp is not None:
222
+ return float(fps_from_video(vp))
223
+
224
+ # if search_video enabled but not found, ask user by failing loudly
225
+ raise RuntimeError(
226
+ "FPS not found in H5 (/VideoInfo/fps missing or 0), and no same-stem video file was found.\n"
227
+ "Searched: current folder, ./videos, ./data, and parent-level videos/data folders.\n"
228
+ "Please provide the exact video path via --video, or disable video search and use --fps-default."
229
+ )
230
+
231
+ return float(fps_default)
232
+
233
+
234
+ def load_calibration(h5, ratio_default: float = 1.0):
235
+ rx, ry = float(ratio_default), float(ratio_default)
236
+ if "CalibrationInfo" in h5:
237
+ ci = h5["CalibrationInfo"]
238
+ if "px_mm_ratio_x" in ci:
239
+ try:
240
+ rx = float(ci["px_mm_ratio_x"][()])
241
+ except Exception:
242
+ pass
243
+ if "px_mm_ratio_y" in ci:
244
+ try:
245
+ ry = float(ci["px_mm_ratio_y"][()])
246
+ except Exception:
247
+ pass
248
+ if rx == 0:
249
+ rx = float(ratio_default)
250
+ if ry == 0:
251
+ ry = float(ratio_default)
252
+ return rx, ry
253
+
254
+
255
+ def compute_kinematic(bodyparts: List[str], data2d: np.ndarray, fps: float, rx: float, ry: float):
256
+ """Compute per-frame kinematic features."""
257
+ n_frames = int(data2d.shape[0])
258
+ n_bp = int(len(bodyparts))
259
+
260
+ if data2d.ndim != 2:
261
+ raise ValueError(f"data2D must be 2D. Got shape={data2d.shape}")
262
+
263
+ if data2d.shape[1] < n_bp * 3:
264
+ raise ValueError(f"data2D second dim too small: got {data2d.shape}, need at least {n_bp*3}")
265
+
266
+ cols = []
267
+ names: List[str] = []
268
+
269
+ # per-bodypart x,y,distance,speed
270
+ for i, bp in enumerate(bodyparts):
271
+ x = data2d[:, i * 3 + 0].astype(np.float64)
272
+ y = data2d[:, i * 3 + 1].astype(np.float64)
273
+
274
+ # px -> mm (divide by px/mm) -> cm (/10)
275
+ x_cm = x / rx / 10.0
276
+ y_cm = y / ry / 10.0
277
+
278
+ pts = np.stack([x_cm, y_cm], axis=1)
279
+ d = np.linalg.norm(np.diff(pts, axis=0), axis=1) # frames-1
280
+ d = np.pad(d, (0, 1), mode="constant", constant_values=0.0) # to frames
281
+ speed = d * fps
282
+
283
+ names += [f"x_{bp}", f"y_{bp}", f"distance_{bp}", f"speed_{bp}"]
284
+ cols += [x_cm, y_cm, d, speed]
285
+
286
+ # frame_distance / frame_speed from mean point of all bodyparts
287
+ xs = []
288
+ ys = []
289
+ for i in range(n_bp):
290
+ xs.append(data2d[:, i * 3 + 0].astype(np.float64) / rx / 10.0)
291
+ ys.append(data2d[:, i * 3 + 1].astype(np.float64) / ry / 10.0)
292
+ mean_x = np.mean(np.stack(xs, axis=1), axis=1)
293
+ mean_y = np.mean(np.stack(ys, axis=1), axis=1)
294
+ mean_pts = np.stack([mean_x, mean_y], axis=1)
295
+
296
+ frame_d = np.linalg.norm(np.diff(mean_pts, axis=0), axis=1)
297
+ frame_d = np.insert(frame_d, 0, frame_d[0] if frame_d.size else 0.0)
298
+ if frame_d.shape[0] < n_frames:
299
+ frame_d = np.pad(frame_d, (0, n_frames - frame_d.shape[0]), mode="constant", constant_values=0.0)
300
+ frame_speed = frame_d * fps
301
+
302
+ names += ["frame_distance", "frame_speed"]
303
+ cols += [frame_d, frame_speed]
304
+
305
+ param_data = np.stack(cols, axis=1).astype(np.float32)
306
+ return names, param_data
307
+
308
+
309
+ def write_kinematic(
310
+ h5_path: Path,
311
+ overwrite: bool,
312
+ fps_default: float,
313
+ ratio_default: float,
314
+ search_video: bool,
315
+ video_path: Optional[Path],
316
+ max_parent_levels: int,
317
+ ):
318
+ h5_path = Path(h5_path)
319
+ if not h5_path.exists():
320
+ raise FileNotFoundError(h5_path)
321
+
322
+ with h5py.File(str(h5_path), "r+") as h5:
323
+ if "2Dskeleton" not in h5:
324
+ raise KeyError("Missing group: /2Dskeleton")
325
+ sk = h5["2Dskeleton"]
326
+ if "BodyParts" not in sk or "data2D" not in sk:
327
+ raise KeyError("Missing datasets: /2Dskeleton/BodyParts or /2Dskeleton/data2D")
328
+
329
+ bodyparts = [_decode(x) for x in np.array(sk["BodyParts"][()])]
330
+ data2d = np.array(sk["data2D"][()])
331
+
332
+ fps = load_fps(
333
+ h5,
334
+ h5_path=h5_path,
335
+ fps_default=fps_default,
336
+ search_video=search_video,
337
+ video_path=video_path,
338
+ max_parent_levels=max_parent_levels,
339
+ )
340
+ rx, ry = load_calibration(h5, ratio_default=ratio_default)
341
+
342
+ names, param_data = compute_kinematic(bodyparts, data2d, fps, rx, ry)
343
+
344
+ if "KinematicParameter" in h5:
345
+ if not overwrite:
346
+ raise SystemExit("KinematicParameter already exists. Re-run with --overwrite to replace it.")
347
+ del h5["KinematicParameter"]
348
+
349
+ grp = h5.create_group("KinematicParameter")
350
+ grp.create_dataset("ParameterName", data=_as_bytes_array(names))
351
+ grp.create_dataset("ParameterData", data=param_data, compression="gzip", compression_opts=4)
352
+
353
+ grp.attrs["generated_by"] = "generate_kinematic_parameter.py"
354
+ grp.attrs["fps_used"] = float(fps)
355
+ grp.attrs["px_mm_ratio_x_used"] = float(rx)
356
+ grp.attrs["px_mm_ratio_y_used"] = float(ry)
357
+
358
+ print(f"[OK] Wrote /KinematicParameter to: {h5_path}")
359
+ print(f" frames={param_data.shape[0]} params={param_data.shape[1]}")
360
+ print(f" fps={fps} rx={rx} ry={ry}")
361
+
362
+
363
+ def main():
364
+ ap = argparse.ArgumentParser()
365
+ ap.add_argument("--h5", required=True, help="Path to .h5 file")
366
+ ap.add_argument("--overwrite", action="store_true", help="Overwrite existing /KinematicParameter")
367
+
368
+ ap.add_argument("--fps-default", type=float, default=30.0, help="Fallback fps when no fps and video search disabled")
369
+ ap.add_argument("--ratio-default", type=float, default=1.0, help="Fallback px/mm ratio when missing")
370
+
371
+ ap.add_argument(
372
+ "--search-video",
373
+ action=argparse.BooleanOptionalAction,
374
+ default=True,
375
+ help="When H5 has no fps, try to locate same-stem video and read FPS (default: true)",
376
+ )
377
+ ap.add_argument("--video", default="", help="Explicit video path (overrides auto search when provided)")
378
+ ap.add_argument(
379
+ "--max-parent-levels",
380
+ type=int,
381
+ default=2,
382
+ help="How many parent levels to search for videos/data folders (default: 2)",
383
+ )
384
+
385
+ args = ap.parse_args()
386
+
387
+ video_path = Path(args.video) if str(args.video).strip() else None
388
+
389
+ write_kinematic(
390
+ h5_path=Path(args.h5),
391
+ overwrite=bool(args.overwrite),
392
+ fps_default=float(args.fps_default),
393
+ ratio_default=float(args.ratio_default),
394
+ search_video=bool(args.search_video),
395
+ video_path=video_path,
396
+ max_parent_levels=int(args.max_parent_levels),
397
+ )
398
+
399
+
400
+ if __name__ == "__main__":
401
+ main()
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Kinematic Parameter Generator Skill
5
+
6
+ This skill checks if a .h5 file contains KinematicParameter data, and if not,
7
+ generates it from the 2Dskeleton data using the generate_kinematic_parameter.py logic.
8
+
9
+ If FPS is not available in the .h5 file, it attempts to read it from the associated video file
10
+ using either ffmpeg or OpenCV.
11
+ """
12
+
13
+ import argparse
14
+ import os
15
+ import sys
16
+ from pathlib import Path
17
+ import h5py
18
+ import numpy as np
19
+
20
+
21
+ def check_kinematic_parameter_exists(h5_path):
22
+ """
23
+ Check if KinematicParameter exists in the .h5 file
24
+
25
+ Args:
26
+ h5_path (str or Path): Path to the .h5 file
27
+
28
+ Returns:
29
+ bool: True if KinematicParameter exists, False otherwise
30
+ """
31
+ h5_path = Path(h5_path)
32
+
33
+ with h5py.File(str(h5_path), 'r') as h5_file:
34
+ return 'KinematicParameter' in h5_file
35
+
36
+
37
+ def check_skeleton_data_exists(h5_path):
38
+ """
39
+ Check if 2Dskeleton data exists in the .h5 file
40
+
41
+ Args:
42
+ h5_path (str or Path): Path to the .h5 file
43
+
44
+ Returns:
45
+ bool: True if 2Dskeleton data exists, False otherwise
46
+ """
47
+ h5_path = Path(h5_path)
48
+
49
+ with h5py.File(str(h5_path), 'r') as h5_file:
50
+ return ('2Dskeleton' in h5_file and
51
+ 'BodyParts' in h5_file['2Dskeleton'] and
52
+ 'data2D' in h5_file['2Dskeleton'])
53
+
54
+
55
+ def get_fps_from_h5(h5_path):
56
+ """
57
+ Get FPS from the .h5 file if available
58
+
59
+ Args:
60
+ h5_path (str or Path): Path to the .h5 file
61
+
62
+ Returns:
63
+ float or None: FPS value if found and valid, None otherwise
64
+ """
65
+ h5_path = Path(h5_path)
66
+
67
+ with h5py.File(str(h5_path), 'r') as h5_file:
68
+ if 'VideoInfo' in h5_file and 'fps' in h5_file['VideoInfo']:
69
+ try:
70
+ fps = float(h5_file['VideoInfo']['fps'][()])
71
+ if fps > 0:
72
+ return fps
73
+ except Exception:
74
+ pass
75
+ return None
76
+
77
+
78
+ def find_associated_video(h5_path):
79
+ """
80
+ Find an associated video file with the same stem as the .h5 file
81
+
82
+ Args:
83
+ h5_path (str or Path): Path to the .h5 file
84
+
85
+ Returns:
86
+ Path or None: Path to the video file if found, None otherwise
87
+ """
88
+ h5_path = Path(h5_path)
89
+ stem = h5_path.stem
90
+
91
+ # Common video extensions
92
+ video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.mpeg', '.mpg']
93
+
94
+ # Look in the same directory as the .h5 file
95
+ h5_dir = h5_path.parent
96
+
97
+ for ext in video_extensions:
98
+ video_path = h5_dir / (stem + ext)
99
+ if video_path.exists():
100
+ return video_path
101
+
102
+ # If not found in the same directory, look in common subdirectories
103
+ for subdir in ['videos', 'video', 'Videos', 'Video', 'data', 'Data']:
104
+ sub_dir = h5_dir / subdir
105
+ if sub_dir.exists() and sub_dir.is_dir():
106
+ for ext in video_extensions:
107
+ video_path = sub_dir / (stem + ext)
108
+ if video_path.exists():
109
+ return video_path
110
+
111
+ return None
112
+
113
+
114
+ def get_fps_from_video(video_path):
115
+ """
116
+ Get FPS from a video file using ffmpeg
117
+
118
+ Args:
119
+ video_path (str or Path): Path to the video file
120
+
121
+ Returns:
122
+ float: FPS value
123
+ """
124
+ import subprocess
125
+ import shutil
126
+
127
+ video_path = Path(video_path)
128
+
129
+ # Check if ffprobe is available
130
+ if shutil.which('ffprobe'):
131
+ # Use ffprobe to get FPS
132
+ cmd = [
133
+ 'ffprobe',
134
+ '-v', 'error',
135
+ '-select_streams', 'v:0',
136
+ '-show_entries', 'stream=r_frame_rate',
137
+ '-of', 'csv=p=0',
138
+ str(video_path)
139
+ ]
140
+
141
+ try:
142
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
143
+ fps_str = result.stdout.strip()
144
+
145
+ # Handle fractional FPS (e.g., "30/1")
146
+ if '/' in fps_str:
147
+ num, den = fps_str.split('/')
148
+ return float(num) / float(den)
149
+ else:
150
+ return float(fps_str)
151
+ except subprocess.CalledProcessError:
152
+ pass
153
+
154
+ # Fallback to OpenCV if available
155
+ try:
156
+ import cv2
157
+ cap = cv2.VideoCapture(str(video_path))
158
+ fps = cap.get(cv2.CAP_PROP_FPS)
159
+ cap.release()
160
+
161
+ if fps and fps > 0:
162
+ return float(fps)
163
+ except ImportError:
164
+ pass
165
+
166
+ raise RuntimeError(f"Could not determine FPS from video: {video_path}. Neither ffprobe nor OpenCV worked.")
167
+
168
+
169
+ def run_generate_kinematic_parameter(h5_path, video_path=None, fps_default=30.0):
170
+ """
171
+ Run the generate_kinematic_parameter.py script on the .h5 file
172
+
173
+ Args:
174
+ h5_path (str or Path): Path to the .h5 file
175
+ video_path (str or Path, optional): Path to associated video file
176
+ fps_default (float): Default FPS to use if not found elsewhere
177
+ """
178
+ import subprocess
179
+ import os
180
+
181
+ # Get the path to the generate_kinematic_parameter.py script in the workspace
182
+ script_path = Path(__file__).parent.parent / ".." / "generate_kinematic_parameter.py"
183
+
184
+ # Build the command
185
+ cmd = [
186
+ sys.executable, # Use the same Python interpreter
187
+ str(script_path),
188
+ "--h5", str(h5_path),
189
+ "--fps-default", str(fps_default)
190
+ ]
191
+
192
+ # Add video path if provided
193
+ if video_path:
194
+ cmd.extend(["--video", str(video_path)])
195
+ else:
196
+ # Disable video search if no video path provided
197
+ cmd.append("--no-search-video")
198
+
199
+ # Execute the command
200
+ result = subprocess.run(cmd, capture_output=True, text=True)
201
+
202
+ if result.returncode != 0:
203
+ raise RuntimeError(f"Failed to run generate_kinematic_parameter.py:\nSTDOUT: {result.stdout}\nSTDERR: {result.stderr}")
204
+
205
+ print(result.stdout)
206
+ if result.stderr:
207
+ print("STDERR:", result.stderr)
208
+
209
+
210
+ def main():
211
+ parser = argparse.ArgumentParser(description='Check and generate KinematicParameter data in .h5 files')
212
+ parser.add_argument('--h5-path', required=True, help='Path to the .h5 file')
213
+ parser.add_argument('--fps-default', type=float, default=30.0, help='Default FPS if not found in H5 or video')
214
+
215
+ args = parser.parse_args()
216
+
217
+ h5_path = Path(args.h5_path)
218
+
219
+ if not h5_path.exists():
220
+ raise FileNotFoundError(f"H5 file does not exist: {h5_path}")
221
+
222
+ # Check if 2Dskeleton data exists
223
+ if not check_skeleton_data_exists(h5_path):
224
+ raise ValueError(f"No 2Dskeleton data found in {h5_path}")
225
+
226
+ # Check if KinematicParameter already exists
227
+ if check_kinematic_parameter_exists(h5_path):
228
+ print(f"KinematicParameter already exists in {h5_path}")
229
+ return
230
+
231
+ print(f"KinematicParameter not found in {h5_path}, generating...")
232
+
233
+ # Try to get FPS from H5 file
234
+ fps = get_fps_from_h5(h5_path)
235
+
236
+ if fps is not None:
237
+ print(f"Using FPS from H5 file: {fps}")
238
+ # Run the generation script with the FPS from H5
239
+ run_generate_kinematic_parameter(h5_path, fps_default=fps)
240
+ else:
241
+ print("FPS not found in H5 file, looking for associated video...")
242
+
243
+ # Find associated video file
244
+ video_path = find_associated_video(h5_path)
245
+
246
+ if video_path:
247
+ print(f"Found associated video: {video_path}")
248
+ try:
249
+ fps = get_fps_from_video(video_path)
250
+ print(f"Determined FPS from video: {fps}")
251
+ # Run the generation script with the video
252
+ run_generate_kinematic_parameter(h5_path, video_path=video_path)
253
+ except RuntimeError as e:
254
+ print(f"Could not get FPS from video: {e}")
255
+ print(f"Using default FPS: {args.fps_default}")
256
+ run_generate_kinematic_parameter(h5_path, fps_default=args.fps_default)
257
+ else:
258
+ print(f"No associated video found. Using default FPS: {args.fps_default}")
259
+ run_generate_kinematic_parameter(h5_path, fps_default=args.fps_default)
260
+
261
+ print(f"Processing completed for {h5_path}")
262
+
263
+
264
+ if __name__ == "__main__":
265
+ main()