@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.
- package/package.json +2 -2
- package/skills/01_Meta-Skills/academic-research-hub/SKILL.md +108 -0
- package/skills/01_Meta-Skills/academic-research-hub/scripts/requirements.txt +17 -0
- package/skills/01_Meta-Skills/academic-research-hub/scripts/research.py +781 -0
- package/skills/01_Meta-Skills/beautiful-log/SKILL.md +64 -0
- package/skills/01_Meta-Skills/beautiful-log/scripts/beautiful_log.py +274 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/SKILL.md +130 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/config.template.yaml +54 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/top5_digest_template.md +5 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/build_top5_digest.py +300 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/common.py +137 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/merge_results.py +106 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/run_pipeline.py +177 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_arxiv.py +162 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_pubmed.py +202 -0
- package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/SKILL.md +173 -0
- package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/scripts/normalize_data.py +874 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/SKILL.md +134 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/confirmation-prompts.md +31 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/output-patterns.md +45 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_markdown_deliverables.py +41 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_research_log.py +84 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_summary_md.py +63 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/extract_pdf_bundle.py +140 -0
- package/skills/01_Meta-Skills/experiment-controller/SKILL.md +140 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/SKILL.md +366 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/entity_resolution.py +120 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/extraction_prompt_template.txt +19 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/graph_query.py +106 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/hypothesis_cli_reference.py +42 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/new_data_source_template.py +116 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/requirements.txt +15 -0
- package/skills/01_Meta-Skills/method-design/SKILL.md +61 -0
- package/skills/01_Meta-Skills/multi-search-engine/SKILL.md +119 -0
- package/skills/01_Meta-Skills/research-idea/SKILL.md +65 -0
- package/skills/05_EEG_ERP/eeg-skill/SKILL.md +197 -0
- package/skills/05_EEG_ERP/meg-skill/SKILL.md +188 -0
- package/skills/05_EEG_ERP/meg-skill/scripts/time_frequency.py +223 -0
- package/skills/05_EEG_ERP/mne-eeg-tool/SKILL.md +165 -0
- package/skills/05_EEG_ERP/mne-eeg-tool/scripts/eeg_pipeline_reference.py +231 -0
- package/skills/05_EEG_ERP/seed-iv-skill/SKILL.md +184 -0
- package/skills/05_EEG_ERP/seed-iv-skill/scripts/classify_seed_iv.py +154 -0
- package/skills/05_EEG_ERP/seed-iv-skill/scripts/extract_seed_iv_features.py +190 -0
- package/skills/05_EEG_ERP/seed-iv-skill/scripts/validate_seed_iv.py +102 -0
- package/skills/05_EEG_ERP/seed-vig-skill/SKILL.md +182 -0
- package/skills/05_EEG_ERP/seed-vig-skill/scripts/classify_seed_vig.py +165 -0
- package/skills/05_EEG_ERP/seed-vig-skill/scripts/extract_seed_vig_features.py +185 -0
- package/skills/05_EEG_ERP/seed-vig-skill/scripts/validate_seed_vig.py +88 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/SKILL.md +308 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/abcd_qc_summary.py +449 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/extract_abcd_phenotype.py +292 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/reorganize_abcd.py +387 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/SKILL.md +302 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/abide_qc_summary.py +317 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/extract_abide_phenotype.py +267 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/reorganize_abide.py +387 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/SKILL.md +244 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/adhd200_qc_summary.py +98 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/extract_adhd200_phenotype.py +134 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/reorganize_adhd200.py +206 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/SKILL.md +358 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_adni_task_files.py +1305 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_vqa_from_tasks.py +766 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/reorganize_adni.py +491 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/SKILL.md +295 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/aibl_qc_summary.py +260 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/extract_aibl_phenotype.py +365 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/reorganize_aibl.py +394 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/SKILL.md +292 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/aomic_qc_summary.py +258 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/extract_aomic_phenotype.py +284 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/reorganize_aomic.py +322 -0
- package/skills/06_fMRI_Neuroimaging/asl-skill/SKILL.md +168 -0
- package/skills/06_fMRI_Neuroimaging/asl-skill/scripts/compute_cbf.py +224 -0
- package/skills/06_fMRI_Neuroimaging/bids-organizer/SKILL.md +241 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/SKILL.md +186 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/bold5000_qc_summary.py +96 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/extract_bold5000_stimulus.py +125 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/reorganize_bold5000.py +102 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/SKILL.md +213 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/camcan_qc_summary.py +131 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/extract_camcan_phenotype.py +145 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/validate_camcan.py +141 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/SKILL.md +201 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/cobre_qc_summary.py +95 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/extract_cobre_phenotype.py +104 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/reorganize_cobre.py +140 -0
- package/skills/06_fMRI_Neuroimaging/conn-tool/SKILL.md +180 -0
- package/skills/06_fMRI_Neuroimaging/dcm2nii/SKILL.md +189 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/SKILL.md +183 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/dmt_har_med_qc_summary.py +96 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/extract_dmt_har_med_phenotype.py +121 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/reorganize_dmt_har_med.py +125 -0
- package/skills/06_fMRI_Neuroimaging/dwi-skill/SKILL.md +359 -0
- package/skills/06_fMRI_Neuroimaging/fmri-skill/SKILL.md +371 -0
- package/skills/06_fMRI_Neuroimaging/fmriprep-tool/SKILL.md +228 -0
- package/skills/06_fMRI_Neuroimaging/freesurfer-tool/SKILL.md +286 -0
- package/skills/06_fMRI_Neuroimaging/freesurfer-tool/scripts/freesurfer_processor.py +145 -0
- package/skills/06_fMRI_Neuroimaging/fsl-tool/SKILL.md +208 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/SKILL.md +271 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/extract_hbn_phenotype.py +107 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/hbn_qc_summary.py +96 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/reorganize_hbn.py +150 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/SKILL.md +210 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/extract_hcpa_phenotype.py +146 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/hcpa_qc_summary.py +120 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/reorganize_hcpa.py +155 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/SKILL.md +210 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/extract_hcpd_phenotype.py +148 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/hcpd_qc_summary.py +125 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/reorganize_hcpd.py +146 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/SKILL.md +215 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/extract_hcpep_phenotype.py +157 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/hcpep_qc_summary.py +143 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/reorganize_hcpep.py +146 -0
- package/skills/06_fMRI_Neuroimaging/hcppipeline-tool/SKILL.md +217 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/SKILL.md +214 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/extract_hcpya_phenotype.py +190 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/hcpya_qc_summary.py +152 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/reorganize_hcpya.py +203 -0
- package/skills/06_fMRI_Neuroimaging/ixi-skill/SKILL.md +198 -0
- package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/ixi_qc_summary.py +137 -0
- package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/reorganize_ixi.py +190 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/SKILL.md +191 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/extract_mnd_phenotype.py +143 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/mnd_qc_summary.py +120 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/validate_mnd.py +107 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/SKILL.md +203 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/analyze_lesions.py +119 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/longitudinal_lesion.py +148 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/mschallenge_qc_summary.py +132 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/validate_mschallenge.py +116 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/SKILL.md +184 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/atlas_coordinate_reference.py +61 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/freesurfer_io_reference.py +34 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/nifti_inspection_reference.py +35 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/SKILL.md +205 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/extract_nifd_phenotype.py +132 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/nifd_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/validate_nifd.py +111 -0
- package/skills/06_fMRI_Neuroimaging/nii2dcm/SKILL.md +143 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/SKILL.md +266 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/connectome_reference.py +65 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/denoise_timeseries_reference.py +58 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/hierarchical_parcellation_reference.py +53 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/kmeans_parcellation_reference.py +53 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/preprocess_bold_reference.py +76 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_dictlearning_reference.py +56 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_ica_reference.py +59 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/second_level_glm_reference.py +58 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/spacenet_classifier_reference.py +59 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/svm_classifier_reference.py +60 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/task_glm_reference.py +63 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/zalff_summary_reference.py +109 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/SKILL.md +210 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/extract_nsd_stimulus.py +171 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/nsd_qc_summary.py +142 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/validate_nsd.py +142 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/SKILL.md +205 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/extract_oasis_phenotype.py +126 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/oasis_qc_summary.py +115 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/validate_oasis.py +119 -0
- package/skills/06_fMRI_Neuroimaging/pet-skill/SKILL.md +173 -0
- package/skills/06_fMRI_Neuroimaging/pet-skill/scripts/compute_suvr.py +202 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/SKILL.md +206 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/extract_pnc_phenotype.py +136 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/pnc_qc_summary.py +116 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/validate_pnc.py +120 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/SKILL.md +209 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/extract_ppmi_phenotype.py +138 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/ppmi_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/validate_ppmi.py +117 -0
- package/skills/06_fMRI_Neuroimaging/qsiprep-tool/SKILL.md +320 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/SKILL.md +215 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/extract_rest_mdd_phenotype.py +132 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/harmonize_sites.py +152 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/rest_mdd_qc_summary.py +124 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/validate_rest_mdd.py +103 -0
- package/skills/06_fMRI_Neuroimaging/smri-skill/SKILL.md +302 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/SKILL.md +204 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/extract_tcp_phenotype.py +139 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/tcp_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/validate_tcp.py +99 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/SKILL.md +217 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/extract_ucla_cnp_phenotype.py +145 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/ucla_cnp_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/validate_ucla_cnp.py +113 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/SKILL.md +310 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/build_ukb_survival.py +210 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_cases.py +308 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_phenotype.py +232 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/ukb_qc_summary.py +158 -0
- package/skills/06_fMRI_Neuroimaging/wmh-segmentation/SKILL.md +133 -0
- package/skills/07_Computational_Modeling/detrending/SKILL.md +118 -0
- package/skills/07_Computational_Modeling/dictlearning/SKILL.md +122 -0
- package/skills/07_Computational_Modeling/filtering/SKILL.md +121 -0
- package/skills/07_Computational_Modeling/glm/SKILL.md +153 -0
- package/skills/07_Computational_Modeling/hierarchical/SKILL.md +121 -0
- package/skills/07_Computational_Modeling/ica/SKILL.md +122 -0
- package/skills/07_Computational_Modeling/kmeans/SKILL.md +119 -0
- package/skills/07_Computational_Modeling/run_models/SKILL.md +427 -0
- package/skills/07_Computational_Modeling/spacenet/SKILL.md +122 -0
- package/skills/07_Computational_Modeling/svm/SKILL.md +120 -0
- package/skills/08_Computational_Neuroscience/brain_gnn/SKILL.md +183 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/SKILL.md +239 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/scripts/dti_metrics_reference.py +70 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/scripts/load_and_mask_reference.py +76 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/scripts/roi_stats_reference.py +59 -0
- package/skills/08_Computational_Neuroscience/fm_app/SKILL.md +195 -0
- package/skills/08_Computational_Neuroscience/neurostorm/SKILL.md +151 -0
- package/skills/13_Visualization/brain-visualization/SKILL.md +191 -0
- package/skills/13_Visualization/brain-visualization/scripts/connectome_reference.py +108 -0
- package/skills/13_Visualization/brain-visualization/scripts/freesurfer_ply_reference.py +54 -0
- package/skills/13_Visualization/brain-visualization/scripts/zalff_summary_reference.py +116 -0
- package/skills/13_Visualization/ethoclaw-paper-figure-layout/SKILL.md +78 -0
- package/skills/13_Visualization/ethoclaw-paper-figure-layout/assets/naturecomm_figures.tex +74 -0
- package/skills/13_Visualization/ethoclaw-paper-figure-layout/scripts/layout_results_foldered.py +579 -0
- package/skills/14_Writing/overleaf-skill/SKILL.md +184 -0
- package/skills/14_Writing/overleaf-skill/scripts/install.sh +30 -0
- package/skills/14_Writing/paper-writing/SKILL.md +146 -0
- package/skills/14_Writing/paper-writing/scripts/data_statement_templates.py +164 -0
- package/skills/14_Writing/paper-writing/scripts/figure_templates.py +315 -0
- package/skills/14_Writing/paper-writing/scripts/nature_figure_style.py +214 -0
- package/skills/14_Writing/paper-writing/scripts/section_phrasebank.py +246 -0
- package/skills/16_Animal_Behavior/deeplabcut/SKILL.md +154 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/3d-pose.md +89 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/maDLC.md +123 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/modelzoo.md +98 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/standard-pipeline.md +165 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/utilities.md +146 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/SKILL.md +274 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.html +112 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.md +21 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/cluster-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/heatmap-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/integrated-interpretation.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/overview.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/project-summary.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/radar-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/raw-trajectory.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/sample-check.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/single-subject-section.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/stats-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/epm.md +52 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/fst.md +37 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/nor.md +39 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/oft.md +43 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tcst.md +45 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tst.md +36 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/input-types.md +59 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/interpretation-guardrails.md +45 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/metadata-schema.md +57 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/report-sections.md +86 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/section-selection-rules.md +169 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/build_report_manifest.py +27 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/render_report.py +34 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/report_utils.py +1121 -0
- package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/SKILL.md +390 -0
- package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/reference_code.py +98 -0
- package/skills/16_Animal_Behavior/ethoclaw-animal-pose-estimation/SKILL.md +336 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/README.md +21 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/SKILL.md +41 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/batch_kinematic_generator.py +663 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/config.json +19 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/generate_kinematic_parameter.py +401 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/kinematic_generator.py +265 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/SKILL.md +72 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/references/config.example.toml +56 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params.py +232 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params_from_config.py +236 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/SKILL.md +68 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/references/notes.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/scripts/plot_h5_radar.py +513 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/SKILL.md +52 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/config.toml +81 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/references/stats-rule.md +18 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_inspect.py +79 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_batch.py +624 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_stats.py +438 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/SKILL.md +280 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_trajectory.py +790 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_velocity.py +855 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.csv +101 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.h5 +0 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_data_readme.md +126 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Batch process .h5 files to check for KinematicParameter and generate it if missing.
|
|
4
|
+
Also adds video information to VideoInfo if video is available.
|
|
5
|
+
If no .h5 files are found, processes .csv files and converts them to .h5 first.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
import h5py
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_fps_from_video(video_path):
|
|
18
|
+
"""Extract FPS from video file using ffprobe."""
|
|
19
|
+
import subprocess
|
|
20
|
+
import json
|
|
21
|
+
|
|
22
|
+
cmd = [
|
|
23
|
+
'ffprobe',
|
|
24
|
+
'-v', 'quiet',
|
|
25
|
+
'-print_format', 'json',
|
|
26
|
+
'-show_format',
|
|
27
|
+
'-show_streams',
|
|
28
|
+
str(video_path)
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
33
|
+
video_info = json.loads(result.stdout)
|
|
34
|
+
|
|
35
|
+
# Find video stream
|
|
36
|
+
for stream in video_info.get('streams', []):
|
|
37
|
+
if stream.get('codec_type') == 'video':
|
|
38
|
+
avg_frame_rate = stream.get('avg_frame_rate')
|
|
39
|
+
if avg_frame_rate:
|
|
40
|
+
# avg_frame_rate is often in form "num/den" like "30/1"
|
|
41
|
+
if '/' in avg_frame_rate:
|
|
42
|
+
num, den = avg_frame_rate.split('/')
|
|
43
|
+
fps = float(num) / float(den) if float(den) != 0 else 30.0
|
|
44
|
+
else:
|
|
45
|
+
fps = float(avg_frame_rate)
|
|
46
|
+
return fps
|
|
47
|
+
|
|
48
|
+
# Alternative: get from format if not in streams
|
|
49
|
+
format_info = video_info.get('format', {})
|
|
50
|
+
if 'avg_frame_rate' in format_info:
|
|
51
|
+
avg_frame_rate = format_info['avg_frame_rate']
|
|
52
|
+
if avg_frame_rate and avg_frame_rate != '0/0':
|
|
53
|
+
if '/' in avg_frame_rate:
|
|
54
|
+
num, den = avg_frame_rate.split('/')
|
|
55
|
+
fps = float(num) / float(den) if float(den) != 0 else 30.0
|
|
56
|
+
else:
|
|
57
|
+
fps = float(avg_frame_rate)
|
|
58
|
+
return fps
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
print(f" - Warning: Could not get FPS from video {video_path}: {e}")
|
|
62
|
+
|
|
63
|
+
# Fallback to OpenCV
|
|
64
|
+
try:
|
|
65
|
+
import cv2
|
|
66
|
+
cap = cv2.VideoCapture(str(video_path))
|
|
67
|
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
|
68
|
+
cap.release()
|
|
69
|
+
if fps and fps > 0:
|
|
70
|
+
return fps
|
|
71
|
+
except Exception as cv_e:
|
|
72
|
+
print(f" - Warning: OpenCV fallback also failed: {cv_e}")
|
|
73
|
+
|
|
74
|
+
return 30.0 # Default FPS if all methods fail
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def add_video_info_to_h5(h5_path, video_path, fps):
|
|
78
|
+
"""Add video information to the HDF5 file under /VideoInfo."""
|
|
79
|
+
import subprocess
|
|
80
|
+
import json
|
|
81
|
+
|
|
82
|
+
# Get additional video info using ffprobe
|
|
83
|
+
cmd = [
|
|
84
|
+
'ffprobe',
|
|
85
|
+
'-v', 'quiet',
|
|
86
|
+
'-print_format', 'json',
|
|
87
|
+
'-show_format',
|
|
88
|
+
'-show_streams',
|
|
89
|
+
str(video_path)
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
94
|
+
video_info = json.loads(result.stdout)
|
|
95
|
+
|
|
96
|
+
# Extract video stream info
|
|
97
|
+
video_stream = None
|
|
98
|
+
for stream in video_info.get('streams', []):
|
|
99
|
+
if stream.get('codec_type') == 'video':
|
|
100
|
+
video_stream = stream
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
# Get format info
|
|
104
|
+
format_info = video_info.get('format', {})
|
|
105
|
+
|
|
106
|
+
# Add video info to HDF5
|
|
107
|
+
with h5py.File(str(h5_path), 'a') as f: # Open in append mode
|
|
108
|
+
# Create or get VideoInfo group
|
|
109
|
+
if 'VideoInfo' in f:
|
|
110
|
+
vid_group = f['VideoInfo']
|
|
111
|
+
else:
|
|
112
|
+
vid_group = f.create_group('VideoInfo')
|
|
113
|
+
|
|
114
|
+
# Add FPS
|
|
115
|
+
if 'fps' in vid_group:
|
|
116
|
+
del vid_group['fps']
|
|
117
|
+
vid_group.create_dataset('fps', data=float(fps))
|
|
118
|
+
|
|
119
|
+
# Add other video properties if available
|
|
120
|
+
if video_stream:
|
|
121
|
+
# Resolution
|
|
122
|
+
width = video_stream.get('width')
|
|
123
|
+
height = video_stream.get('height')
|
|
124
|
+
|
|
125
|
+
if width:
|
|
126
|
+
if 'width' in vid_group:
|
|
127
|
+
del vid_group['width']
|
|
128
|
+
vid_group.create_dataset('width', data=int(width))
|
|
129
|
+
|
|
130
|
+
if height:
|
|
131
|
+
if 'height' in vid_group:
|
|
132
|
+
del vid_group['height']
|
|
133
|
+
vid_group.create_dataset('height', data=int(height))
|
|
134
|
+
|
|
135
|
+
# Codec
|
|
136
|
+
codec_name = video_stream.get('codec_name')
|
|
137
|
+
if codec_name:
|
|
138
|
+
if 'codec' in vid_group:
|
|
139
|
+
del vid_group['codec']
|
|
140
|
+
vid_group.create_dataset('codec', data=codec_name.encode('utf-8'))
|
|
141
|
+
|
|
142
|
+
# Duration (from stream level)
|
|
143
|
+
duration = video_stream.get('duration')
|
|
144
|
+
if duration:
|
|
145
|
+
if 'duration' in vid_group:
|
|
146
|
+
del vid_group['duration']
|
|
147
|
+
vid_group.create_dataset('duration', data=float(duration))
|
|
148
|
+
|
|
149
|
+
# Add format-level info
|
|
150
|
+
if format_info:
|
|
151
|
+
# Duration (from format level)
|
|
152
|
+
if 'duration' not in (video_stream or {}) and 'duration' in format_info:
|
|
153
|
+
duration = float(format_info['duration'])
|
|
154
|
+
if 'duration' in vid_group:
|
|
155
|
+
del vid_group['duration']
|
|
156
|
+
vid_group.create_dataset('duration', data=duration)
|
|
157
|
+
|
|
158
|
+
# Bit rate
|
|
159
|
+
bit_rate = format_info.get('bit_rate')
|
|
160
|
+
if bit_rate:
|
|
161
|
+
if 'bit_rate' in vid_group:
|
|
162
|
+
del vid_group['bit_rate']
|
|
163
|
+
vid_group.create_dataset('bit_rate', data=int(bit_rate))
|
|
164
|
+
|
|
165
|
+
# File size
|
|
166
|
+
size = format_info.get('size')
|
|
167
|
+
if size:
|
|
168
|
+
if 'size' in vid_group:
|
|
169
|
+
del vid_group['size']
|
|
170
|
+
vid_group.create_dataset('size', data=int(size))
|
|
171
|
+
except Exception as e:
|
|
172
|
+
print(f" - Warning: Could not add detailed video info to {h5_path}: {e}")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def find_associated_video(h5_path):
|
|
176
|
+
"""
|
|
177
|
+
Find an associated video file with the same stem as the .h5 file
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
h5_path (str or Path): Path to the .h5 file
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Path or None: Path to the video file if found, None otherwise
|
|
184
|
+
"""
|
|
185
|
+
h5_path = Path(h5_path)
|
|
186
|
+
stem = h5_path.stem
|
|
187
|
+
|
|
188
|
+
# Common video extensions
|
|
189
|
+
video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.mpeg', '.mpg']
|
|
190
|
+
|
|
191
|
+
# Look in the same directory as the .h5 file
|
|
192
|
+
h5_dir = h5_path.parent
|
|
193
|
+
|
|
194
|
+
for ext in video_extensions:
|
|
195
|
+
video_path = h5_dir / (stem + ext)
|
|
196
|
+
if video_path.exists():
|
|
197
|
+
return video_path
|
|
198
|
+
|
|
199
|
+
# Look in the current working directory
|
|
200
|
+
for ext in video_extensions:
|
|
201
|
+
video_path = Path.cwd() / (stem + ext)
|
|
202
|
+
if video_path.exists():
|
|
203
|
+
return video_path
|
|
204
|
+
|
|
205
|
+
# Look in common subdirectories of the current directory
|
|
206
|
+
for subdir in ['videos', 'video', 'Videos', 'Video', 'data', 'Data']:
|
|
207
|
+
sub_dir = h5_dir / subdir
|
|
208
|
+
if sub_dir.exists() and sub_dir.is_dir():
|
|
209
|
+
for ext in video_extensions:
|
|
210
|
+
video_path = sub_dir / (stem + ext)
|
|
211
|
+
if video_path.exists():
|
|
212
|
+
return video_path
|
|
213
|
+
|
|
214
|
+
# For typical project structures, look for related directories
|
|
215
|
+
# E.g., if h5 is in 1_2Dskeleton, check for 0_videos
|
|
216
|
+
parent_dir = h5_dir.parent
|
|
217
|
+
if parent_dir.name.endswith('_2Dskeleton') or parent_dir.name.endswith('_2Dkeypoints'):
|
|
218
|
+
# Try to find a sibling directory with videos
|
|
219
|
+
project_dir = parent_dir.parent
|
|
220
|
+
for sibling_dir in project_dir.iterdir():
|
|
221
|
+
if sibling_dir.is_dir() and ('video' in sibling_dir.name.lower() or
|
|
222
|
+
'0_' in sibling_dir.name or
|
|
223
|
+
'raw' in sibling_dir.name.lower()):
|
|
224
|
+
for ext in video_extensions:
|
|
225
|
+
video_path = sibling_dir / (stem + ext)
|
|
226
|
+
if video_path.exists():
|
|
227
|
+
return video_path
|
|
228
|
+
|
|
229
|
+
# Try parent directory and its subdirectories
|
|
230
|
+
for parent_level in range(1, 4): # Go up to 3 levels
|
|
231
|
+
cur_dir = h5_path
|
|
232
|
+
for _ in range(parent_level):
|
|
233
|
+
cur_dir = cur_dir.parent
|
|
234
|
+
if cur_dir == cur_dir.parent: # Reached root
|
|
235
|
+
break
|
|
236
|
+
else:
|
|
237
|
+
# Check in this parent directory
|
|
238
|
+
for ext in video_extensions:
|
|
239
|
+
video_path = cur_dir / (stem + ext)
|
|
240
|
+
if video_path.exists():
|
|
241
|
+
return video_path
|
|
242
|
+
|
|
243
|
+
# Check subdirectories of this parent
|
|
244
|
+
for subdir in cur_dir.iterdir():
|
|
245
|
+
if subdir.is_dir():
|
|
246
|
+
for ext in video_extensions:
|
|
247
|
+
video_path = subdir / (stem + ext)
|
|
248
|
+
if video_path.exists():
|
|
249
|
+
return video_path
|
|
250
|
+
|
|
251
|
+
return None
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def csv_to_h5(csv_path, h5_output_path, fps=30.0):
|
|
255
|
+
"""
|
|
256
|
+
Convert a CSV file containing 2D skeleton data to HDF5 format with 2Dskeleton group.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
csv_path (str or Path): Path to the input CSV file
|
|
260
|
+
h5_output_path (str or Path): Path for the output HDF5 file
|
|
261
|
+
fps (float): Frames per second for the video
|
|
262
|
+
"""
|
|
263
|
+
import pandas as pd
|
|
264
|
+
import numpy as np
|
|
265
|
+
import time
|
|
266
|
+
import os
|
|
267
|
+
|
|
268
|
+
# Read the CSV file
|
|
269
|
+
df = pd.read_csv(csv_path)
|
|
270
|
+
|
|
271
|
+
# Extract body parts from column names
|
|
272
|
+
# Expected format: {bodypart}_x, {bodypart}_y, {bodypart}_confidence
|
|
273
|
+
columns = df.columns.tolist()
|
|
274
|
+
|
|
275
|
+
# Identify unique body parts
|
|
276
|
+
body_parts = set()
|
|
277
|
+
for col in columns:
|
|
278
|
+
if '_' in col:
|
|
279
|
+
bp = '_'.join(col.split('_')[:-1]) # Get everything before the last underscore
|
|
280
|
+
if col.endswith(('_x', '_y', '_confidence')):
|
|
281
|
+
body_parts.add(bp)
|
|
282
|
+
|
|
283
|
+
body_parts = sorted(list(body_parts)) # Sort to ensure consistent order
|
|
284
|
+
|
|
285
|
+
# Prepare the skeleton data array
|
|
286
|
+
n_frames = len(df)
|
|
287
|
+
n_body_parts = len(body_parts)
|
|
288
|
+
|
|
289
|
+
# Create data in the format expected by the original script:
|
|
290
|
+
# data2D should be (n_frames, n_bodyparts*3) -> [x, y, likelihood] per bodypart
|
|
291
|
+
data2d = np.zeros((n_frames, n_body_parts * 3)) # x, y, confidence for each body part in flattened format
|
|
292
|
+
|
|
293
|
+
# Map body parts to indices
|
|
294
|
+
bp_to_idx = {bp: i for i, bp in enumerate(body_parts)}
|
|
295
|
+
|
|
296
|
+
# Fill the skeleton data in the expected format
|
|
297
|
+
for bp in body_parts:
|
|
298
|
+
bp_idx = bp_to_idx[bp]
|
|
299
|
+
x_col = f"{bp}_x"
|
|
300
|
+
y_col = f"{bp}_y"
|
|
301
|
+
conf_col = f"{bp}_confidence"
|
|
302
|
+
|
|
303
|
+
if x_col in df.columns and y_col in df.columns and conf_col in df.columns:
|
|
304
|
+
# Fill x, y, confidence in the flattened format
|
|
305
|
+
data2d[:, bp_idx * 3 + 0] = df[x_col].values # x coordinates
|
|
306
|
+
data2d[:, bp_idx * 3 + 1] = df[y_col].values # y coordinates
|
|
307
|
+
data2d[:, bp_idx * 3 + 2] = df[conf_col].values # confidence scores
|
|
308
|
+
|
|
309
|
+
# Create HDF5 file with retry mechanism for WSL file locking issues
|
|
310
|
+
max_retries = 5
|
|
311
|
+
retry_delay = 2 # seconds
|
|
312
|
+
|
|
313
|
+
for attempt in range(max_retries):
|
|
314
|
+
try:
|
|
315
|
+
# Ensure the output file doesn't exist to avoid locking issues
|
|
316
|
+
if os.path.exists(h5_output_path):
|
|
317
|
+
os.remove(h5_output_path)
|
|
318
|
+
time.sleep(0.5) # Brief pause after removal
|
|
319
|
+
|
|
320
|
+
# Create HDF5 file
|
|
321
|
+
with h5py.File(h5_output_path, 'w') as f:
|
|
322
|
+
# Create 2Dskeleton group
|
|
323
|
+
skel_group = f.create_group('2Dskeleton')
|
|
324
|
+
|
|
325
|
+
# Store body parts as a dataset (expected by original script)
|
|
326
|
+
skel_group.create_dataset('BodyParts', data=[bp.encode('utf-8') for bp in body_parts])
|
|
327
|
+
|
|
328
|
+
# Store the skeleton data in the expected format (data2D)
|
|
329
|
+
skel_group.create_dataset('data2D', data=data2d, compression='gzip')
|
|
330
|
+
|
|
331
|
+
# Also store in the original format as backup (some files seem to use this)
|
|
332
|
+
skeleton_data_backup = np.zeros((n_frames, n_body_parts, 3)) # x, y, confidence for each body part
|
|
333
|
+
for bp in body_parts:
|
|
334
|
+
bp_idx = bp_to_idx[bp]
|
|
335
|
+
x_col = f"{bp}_x"
|
|
336
|
+
y_col = f"{bp}_y"
|
|
337
|
+
conf_col = f"{bp}_confidence"
|
|
338
|
+
|
|
339
|
+
if x_col in df.columns and y_col in df.columns and conf_col in df.columns:
|
|
340
|
+
skeleton_data_backup[:, bp_idx, 0] = df[x_col].values # x coordinates
|
|
341
|
+
skeleton_data_backup[:, bp_idx, 1] = df[y_col].values # y coordinates
|
|
342
|
+
skeleton_data_backup[:, bp_idx, 2] = df[conf_col].values # confidence scores
|
|
343
|
+
|
|
344
|
+
skel_group.create_dataset('data', data=skeleton_data_backup, compression='gzip')
|
|
345
|
+
|
|
346
|
+
# Store frame count and fps as attributes
|
|
347
|
+
skel_group.attrs['frame_count'] = n_frames
|
|
348
|
+
skel_group.attrs['fps'] = fps
|
|
349
|
+
|
|
350
|
+
# Optionally add calibration info if available
|
|
351
|
+
cal_group = f.create_group('CalibrationInfo')
|
|
352
|
+
# Default to 1:1 pixel-to-mm ratio if not known
|
|
353
|
+
cal_group.create_dataset('px_mm_ratio_x', data=1.0)
|
|
354
|
+
cal_group.create_dataset('px_mm_ratio_y', data=1.0)
|
|
355
|
+
|
|
356
|
+
print(f" - Created HDF5 file from CSV: {h5_output_path}")
|
|
357
|
+
print(f" Body parts: {body_parts}")
|
|
358
|
+
print(f" Frames: {n_frames}")
|
|
359
|
+
print(f" FPS: {fps}")
|
|
360
|
+
|
|
361
|
+
# Verification: Try to read the file back to confirm it was written correctly
|
|
362
|
+
try:
|
|
363
|
+
with h5py.File(h5_output_path, 'r') as f:
|
|
364
|
+
if '2Dskeleton' not in f or 'data2D' not in f['2Dskeleton']:
|
|
365
|
+
raise Exception("File created but missing expected structure")
|
|
366
|
+
break # Success, exit retry loop
|
|
367
|
+
except Exception as verify_error:
|
|
368
|
+
print(f" - Verification failed, attempt {attempt + 1}: {verify_error}")
|
|
369
|
+
if attempt == max_retries - 1: # Last attempt
|
|
370
|
+
raise verify_error
|
|
371
|
+
time.sleep(retry_delay)
|
|
372
|
+
|
|
373
|
+
except Exception as e:
|
|
374
|
+
print(f" - Attempt {attempt + 1} failed: {e}")
|
|
375
|
+
if attempt == max_retries - 1: # Last attempt
|
|
376
|
+
raise e
|
|
377
|
+
time.sleep(retry_delay)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def run_generate_kinematic_parameter(h5_path, video_path=None, fps_default=30.0, ratio_default=1.0):
|
|
381
|
+
"""
|
|
382
|
+
Run the generate_kinematic_parameter.py script on the .h5 file
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
h5_path (str or Path): Path to the .h5 file
|
|
386
|
+
video_path (str or Path, optional): Path to associated video file
|
|
387
|
+
fps_default (float): Default FPS to use if not found elsewhere
|
|
388
|
+
ratio_default (float): Default pixel-to-mm ratio for calibration
|
|
389
|
+
"""
|
|
390
|
+
import subprocess
|
|
391
|
+
import os
|
|
392
|
+
import time
|
|
393
|
+
|
|
394
|
+
# Wait briefly before accessing the file to reduce locking conflicts
|
|
395
|
+
time.sleep(1)
|
|
396
|
+
|
|
397
|
+
# Get the path to the generate_kinematic_parameter.py script in the workspace
|
|
398
|
+
script_path = Path(__file__).parent / "generate_kinematic_parameter.py"
|
|
399
|
+
|
|
400
|
+
# If we have video info, we'll use the generate_kinematic_parameter script to add it,
|
|
401
|
+
# since that script already handles both video info and kinematic parameter generation
|
|
402
|
+
if video_path:
|
|
403
|
+
fps = get_fps_from_video(video_path)
|
|
404
|
+
# Use the actual FPS from video rather than default
|
|
405
|
+
fps_for_gen = fps
|
|
406
|
+
else:
|
|
407
|
+
fps_for_gen = fps_default
|
|
408
|
+
|
|
409
|
+
# Build the command
|
|
410
|
+
cmd = [
|
|
411
|
+
sys.executable, # Use the same Python interpreter
|
|
412
|
+
str(script_path),
|
|
413
|
+
"--h5", str(h5_path),
|
|
414
|
+
"--fps-default", str(fps_for_gen),
|
|
415
|
+
"--ratio-default", str(ratio_default),
|
|
416
|
+
"--overwrite" # Allow overwriting if needed
|
|
417
|
+
]
|
|
418
|
+
|
|
419
|
+
# Add video path if provided (this allows the script to potentially get more accurate FPS)
|
|
420
|
+
# and enables video info extraction
|
|
421
|
+
if video_path:
|
|
422
|
+
cmd.extend(["--video", str(video_path)])
|
|
423
|
+
else:
|
|
424
|
+
# Disable video search if no video path provided
|
|
425
|
+
cmd.append("--no-search-video")
|
|
426
|
+
|
|
427
|
+
# Execute the command with retry mechanism
|
|
428
|
+
max_retries = 3
|
|
429
|
+
retry_delay = 2
|
|
430
|
+
|
|
431
|
+
for attempt in range(max_retries):
|
|
432
|
+
try:
|
|
433
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) # 5 minute timeout
|
|
434
|
+
|
|
435
|
+
if result.returncode != 0:
|
|
436
|
+
raise RuntimeError(f"Failed to run generate_kinematic_parameter.py:\nSTDOUT: {result.stdout}\nSTDERR: {result.stderr}")
|
|
437
|
+
|
|
438
|
+
print(result.stdout)
|
|
439
|
+
if result.stderr:
|
|
440
|
+
print("STDERR:", result.stderr)
|
|
441
|
+
|
|
442
|
+
# As a fallback, if VideoInfo wasn't added by the script but we have video info,
|
|
443
|
+
# try to add it directly
|
|
444
|
+
if video_path:
|
|
445
|
+
# Wait before accessing file again
|
|
446
|
+
time.sleep(1)
|
|
447
|
+
|
|
448
|
+
# Check if VideoInfo was added by the script
|
|
449
|
+
import h5py
|
|
450
|
+
with h5py.File(str(h5_path), 'r') as f:
|
|
451
|
+
has_video_info = 'VideoInfo' in f and 'fps' in f['VideoInfo']
|
|
452
|
+
|
|
453
|
+
if not has_video_info:
|
|
454
|
+
print(" - VideoInfo not found after processing, adding directly...")
|
|
455
|
+
fps = get_fps_from_video(video_path)
|
|
456
|
+
add_video_info_to_h5(h5_path, video_path, fps)
|
|
457
|
+
|
|
458
|
+
break # Success, exit retry loop
|
|
459
|
+
|
|
460
|
+
except subprocess.TimeoutExpired:
|
|
461
|
+
print(f" - Command timed out on attempt {attempt + 1}, retrying...")
|
|
462
|
+
if attempt == max_retries - 1:
|
|
463
|
+
raise RuntimeError(f"Command timed out after {max_retries} attempts")
|
|
464
|
+
time.sleep(retry_delay)
|
|
465
|
+
except Exception as e:
|
|
466
|
+
print(f" - Attempt {attempt + 1} failed: {e}")
|
|
467
|
+
if attempt == max_retries - 1: # Last attempt
|
|
468
|
+
raise e
|
|
469
|
+
time.sleep(retry_delay)
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def process_single_file(h5_path, fps_default=30.0, ratio_default=1.0):
|
|
473
|
+
"""
|
|
474
|
+
Process a single .h5 file to check for KinematicParameter and generate if missing.
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
h5_path (str or Path): Path to the .h5 file
|
|
478
|
+
fps_default (float): Default FPS to use if not found elsewhere
|
|
479
|
+
ratio_default (float): Default pixel-to-mm ratio for calibration
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
bool: True if successful, False otherwise
|
|
483
|
+
"""
|
|
484
|
+
h5_path = Path(h5_path)
|
|
485
|
+
|
|
486
|
+
print(f"Processing file: {h5_path}")
|
|
487
|
+
|
|
488
|
+
try:
|
|
489
|
+
# Check if KinematicParameter already exists
|
|
490
|
+
with h5py.File(h5_path, 'r') as f:
|
|
491
|
+
has_kinematic_param = 'KinematicParameter' in f
|
|
492
|
+
has_2dskeleton = '2Dskeleton' in f
|
|
493
|
+
has_video_info = 'VideoInfo' in f
|
|
494
|
+
|
|
495
|
+
if has_kinematic_param:
|
|
496
|
+
print(f" - KinematicParameter already exists in {h5_path}")
|
|
497
|
+
return True
|
|
498
|
+
|
|
499
|
+
if not has_2dskeleton:
|
|
500
|
+
print(f" - ERROR: No 2Dskeleton data found in {h5_path}")
|
|
501
|
+
return False
|
|
502
|
+
|
|
503
|
+
# Look for associated video to get FPS
|
|
504
|
+
video_path = find_associated_video(h5_path)
|
|
505
|
+
if video_path:
|
|
506
|
+
print(f" - Found associated video: {video_path}")
|
|
507
|
+
fps = get_fps_from_video(video_path)
|
|
508
|
+
print(f" - Determined FPS from video: {fps}")
|
|
509
|
+
else:
|
|
510
|
+
print(f" - No associated video found. Using default FPS: {fps_default}")
|
|
511
|
+
fps = fps_default
|
|
512
|
+
|
|
513
|
+
# Run the generate_kinematic_parameter script with ratio parameter
|
|
514
|
+
run_generate_kinematic_parameter(h5_path, video_path, fps_default, ratio_default)
|
|
515
|
+
|
|
516
|
+
print(f" - Processing completed for {h5_path}")
|
|
517
|
+
return True
|
|
518
|
+
|
|
519
|
+
except Exception as e:
|
|
520
|
+
print(f" - ERROR processing {h5_path}: {e}")
|
|
521
|
+
import traceback
|
|
522
|
+
traceback.print_exc()
|
|
523
|
+
return False
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def process_csv_to_h5_and_then_kinematics(csv_path, fps_default=30.0, ratio_default=1.0):
|
|
527
|
+
"""
|
|
528
|
+
Convert a CSV file to HDF5 and then process it for kinematic parameters.
|
|
529
|
+
|
|
530
|
+
Args:
|
|
531
|
+
csv_path (str or Path): Path to the CSV file
|
|
532
|
+
fps_default (float): Default FPS to use
|
|
533
|
+
ratio_default (float): Default pixel-to-mm ratio for calibration
|
|
534
|
+
|
|
535
|
+
Returns:
|
|
536
|
+
bool: True if successful, False otherwise
|
|
537
|
+
"""
|
|
538
|
+
csv_path = Path(csv_path)
|
|
539
|
+
h5_path = csv_path.with_suffix('.h5')
|
|
540
|
+
|
|
541
|
+
print(f"Converting CSV to HDF5: {csv_path} -> {h5_path}")
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
# Convert CSV to HDF5
|
|
545
|
+
csv_to_h5(csv_path, h5_path, fps_default)
|
|
546
|
+
|
|
547
|
+
# Wait briefly to allow file system to settle before accessing the new file
|
|
548
|
+
import time
|
|
549
|
+
time.sleep(2)
|
|
550
|
+
|
|
551
|
+
# Now process the newly created HDF5 file with ratio parameter
|
|
552
|
+
success = process_single_file(h5_path, fps_default, ratio_default)
|
|
553
|
+
|
|
554
|
+
return success
|
|
555
|
+
except Exception as e:
|
|
556
|
+
print(f" - ERROR converting {csv_path} to HDF5: {e}")
|
|
557
|
+
import traceback
|
|
558
|
+
traceback.print_exc()
|
|
559
|
+
return False
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def main():
|
|
563
|
+
parser = argparse.ArgumentParser(description="Batch process .h5 files to check for KinematicParameter and generate if missing. If no .h5 files found, processes .csv files and converts them to .h5 first.")
|
|
564
|
+
parser.add_argument("--h5-path", type=str, help="Single .h5 file path to process")
|
|
565
|
+
parser.add_argument("--csv-path", type=str, help="Single .csv file path to convert and process")
|
|
566
|
+
parser.add_argument("--directory", type=str, help="Directory containing .h5 or .csv files to process")
|
|
567
|
+
parser.add_argument("--fps-default", type=float, default=30.0, help="Default FPS to use if not found elsewhere")
|
|
568
|
+
parser.add_argument("--ratio-default", type=float, default=1.0, help="Default pixel-to-mm ratio for calibration (default: 1.0)")
|
|
569
|
+
|
|
570
|
+
args = parser.parse_args()
|
|
571
|
+
|
|
572
|
+
if args.h5_path:
|
|
573
|
+
# Process single .h5 file
|
|
574
|
+
success = process_single_file(args.h5_path, args.fps_default, args.ratio_default)
|
|
575
|
+
if not success:
|
|
576
|
+
sys.exit(1)
|
|
577
|
+
elif args.csv_path:
|
|
578
|
+
# Process single .csv file
|
|
579
|
+
success = process_csv_to_h5_and_then_kinematics(args.csv_path, args.fps_default, args.ratio_default)
|
|
580
|
+
if not success:
|
|
581
|
+
sys.exit(1)
|
|
582
|
+
elif args.directory:
|
|
583
|
+
# Process directory - first check for .h5 files, then .csv files if no .h5 found
|
|
584
|
+
directory = Path(args.directory)
|
|
585
|
+
if not directory.exists():
|
|
586
|
+
print(f"Error: Directory {directory} does not exist")
|
|
587
|
+
sys.exit(1)
|
|
588
|
+
|
|
589
|
+
# Find all .h5 files in the directory
|
|
590
|
+
h5_files = list(directory.rglob('*.h5')) # Use rglob for recursive search
|
|
591
|
+
print(f"Found {len(h5_files)} .h5 files to process")
|
|
592
|
+
|
|
593
|
+
# If no .h5 files found, look for .csv files
|
|
594
|
+
if len(h5_files) == 0:
|
|
595
|
+
csv_files = list(directory.rglob('*.csv')) # Look for CSV files
|
|
596
|
+
print(f"No .h5 files found, found {len(csv_files)} .csv files to convert and process")
|
|
597
|
+
|
|
598
|
+
if len(csv_files) == 0:
|
|
599
|
+
print("No .h5 or .csv files found in the specified directory")
|
|
600
|
+
sys.exit(1)
|
|
601
|
+
|
|
602
|
+
# Process each CSV file
|
|
603
|
+
successful = 0
|
|
604
|
+
failed = 0
|
|
605
|
+
for i, csv_file in enumerate(csv_files):
|
|
606
|
+
print(f"\nProcessing CSV file {i+1}/{len(csv_files)}: {csv_file.name}")
|
|
607
|
+
success = process_csv_to_h5_and_then_kinematics(csv_file, args.fps_default, args.ratio_default)
|
|
608
|
+
if success:
|
|
609
|
+
successful += 1
|
|
610
|
+
else:
|
|
611
|
+
failed += 1
|
|
612
|
+
|
|
613
|
+
# Add delay between files to reduce file locking conflicts in WSL
|
|
614
|
+
if i < len(csv_files) - 1: # Don't sleep after the last file
|
|
615
|
+
import time
|
|
616
|
+
print(f"Waiting 3 seconds before processing next file...")
|
|
617
|
+
time.sleep(3)
|
|
618
|
+
|
|
619
|
+
print(f"\nCSV conversion and processing complete!")
|
|
620
|
+
print(f"Successful: {successful}")
|
|
621
|
+
print(f"Failed: {failed}")
|
|
622
|
+
print(f"Total: {len(csv_files)}")
|
|
623
|
+
|
|
624
|
+
if failed > 0:
|
|
625
|
+
print(f"Note: {failed} files failed due to WSL file locking issues. Consider re-running failed files individually.")
|
|
626
|
+
# Don't exit with error code if some files succeeded, as partial success is still valuable
|
|
627
|
+
if successful == 0:
|
|
628
|
+
sys.exit(1)
|
|
629
|
+
else:
|
|
630
|
+
# Process each .h5 file
|
|
631
|
+
successful = 0
|
|
632
|
+
failed = 0
|
|
633
|
+
for i, h5_file in enumerate(h5_files):
|
|
634
|
+
print(f"\nProcessing HDF5 file {i+1}/{len(h5_files)}: {h5_file.name}")
|
|
635
|
+
success = process_single_file(h5_file, args.fps_default, args.ratio_default)
|
|
636
|
+
if success:
|
|
637
|
+
successful += 1
|
|
638
|
+
else:
|
|
639
|
+
failed += 1
|
|
640
|
+
|
|
641
|
+
# Add delay between files to reduce file locking conflicts in WSL
|
|
642
|
+
if i < len(h5_files) - 1: # Don't sleep after the last file
|
|
643
|
+
import time
|
|
644
|
+
print(f"Waiting 2 seconds before processing next file...")
|
|
645
|
+
time.sleep(2)
|
|
646
|
+
|
|
647
|
+
print(f"\nProcessing complete!")
|
|
648
|
+
print(f"Successful: {successful}")
|
|
649
|
+
print(f"Failed: {failed}")
|
|
650
|
+
print(f"Total: {len(h5_files)}")
|
|
651
|
+
|
|
652
|
+
if failed > 0:
|
|
653
|
+
print(f"Note: {failed} files failed due to WSL file locking issues. Consider re-running failed files individually.")
|
|
654
|
+
# Don't exit with error code if some files succeeded, as partial success is still valuable
|
|
655
|
+
if successful == 0:
|
|
656
|
+
sys.exit(1)
|
|
657
|
+
else:
|
|
658
|
+
print("Error: Either --h5-path, --csv-path or --directory must be specified")
|
|
659
|
+
sys.exit(1)
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
if __name__ == "__main__":
|
|
663
|
+
main()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ethoclaw-kinematic-parameter-generator",
|
|
3
|
+
"description": "Checks if .h5 files contain KinematicParameter data, and if not, generates it from the 2Dskeleton data. Can process single files or batch process entire directories. Supports custom calibration parameters.",
|
|
4
|
+
"activation_keywords": ["kinematic", "h5", "parameter", "generate", "skeleton", "batch", "calibration", "ethoclaw"],
|
|
5
|
+
"files": [
|
|
6
|
+
"kinematic_generator.py",
|
|
7
|
+
"batch_kinematic_generator.py",
|
|
8
|
+
"generate_kinematic_parameter.py",
|
|
9
|
+
"SKILL.md",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"requirements": [
|
|
13
|
+
"h5py",
|
|
14
|
+
"numpy",
|
|
15
|
+
"ffmpeg",
|
|
16
|
+
"opencv-python"
|
|
17
|
+
],
|
|
18
|
+
"entry_point": "batch_kinematic_generator.py"
|
|
19
|
+
}
|