Analyse automatique de chants dâoiseaux â Filtrage FIR, STFT, spectrogrammes et classification par segments
Ce projet a Ă©tĂ© rĂ©alisĂ© dans le cadre dâun travail de Ma2 de l'ECAM et consiste en une analyse de signaux audio appliquĂ© aux chants dâoiseaux.
Lâobjectif principal est de construire un pipeline complet, reproductible et documentĂ© permettant de :
- Charger automatiquement des enregistrements
.wavdâoiseaux dĂ©posĂ©s dansdata/raw/. - Appliquer un filtre passe-bande FIR Ă phase linĂ©aire (bande de rĂ©fĂ©rence 400 Hz â 8 kHz).
- Calculer un spectrogramme STFT et lâenregistrer sous forme dâimages.
- DĂ©tecter automatiquement les segments contenant de lâactivitĂ© acoustique (chant).
- Sauvegarder ces segments dans un fichier
segments.csv. - Extraire des caractéristiques audio (MFCC, descripteurs spectraux, F0) pour chaque segment.
- Entraßner un classifieur par segments (Random Forest) afin de distinguer différentes espÚces.
- Utiliser ce modĂšle pour prĂ©dire lâespĂšce dominante dâun nouvel enregistrement
.wav.
Le but étant à partir de fichiers audio bruts, de créer :
- des figures (spectrogrammes simples et annotés),
- des tables (
segments.csv,features.csv,predictions_segments.csv), - un modĂšle appris (
rf_segments.joblib), - et un script de prédiction pour de nouveaux fichiers.
Ce README sert de rapport et d'évaluation : il résume la méthode, la structure du dépÎt, les choix techniques et présente des exemples de résultats.
-
Installation et environnement
2.1. Cloner le dépÎt
2.2. Créer un environnement virtuel (Windows PowerShell)
2.3. Installer les dépendances Python -
Méthodes et choix de traitement du signal
4.1. Filtrage passe-bande FIR (0,4 â 8 kHz)
4.2. STFT et spectrogrammes
4.3. DĂ©tection dâactivitĂ© par flux spectral
4.4. Extraction de features par segment
4.5. Classification par segments (RandomForest) -
Exécution du pipeline : scripts et exemples
5.1. Ătape 1 â PrĂ©traitement et dĂ©tection de segments
5.2. Ătape 2 â Extraction de features par segment
5.3. Ătape 3 â EntraĂźnement du classifieur
5.4. Ătape 4 â PrĂ©diction des segments du dataset
5.5. Ătape 5 â Visualisation des segments annotĂ©s
5.6. Ătape 6 â PrĂ©dire lâespĂšce dominante dâun nouveau fichier.wav
git clone https://github.com/DiegoRadigues/Biodiversity-Monitoring-Project.git
cd Biodiversity-Monitoring-Projectpython -m venv .venv
.venv\Scripts\activateLes dépendances principales (détails dans docs/choix_outils.md et requirements.txt) sont :
numpy,scipy: calculs numériques, filtrage FIR, STFTlibrosa,soundfile: I/O audio, MFCC, spectrogrammesmatplotlib: figures, spectrogrammes, matrice de confusionpandas: tables (segments.csv,features.csv,predictions_segments.csv)scikit-learn: classification, métriquestqdm,joblib,numba: confort et performances (facultatif)
Installation :
pip install --upgrade pip pip install -r requirements.txt
Version recommandée de Python : 3.10 ou plus récent.
Le projet est structurĂ© pour sĂ©parer clairement donnĂ©es, code rĂ©utilisable, scripts dâentrĂ©e et rĂ©sultats dâexpĂ©riences.
Biodiversity-Monitoring-Project/
âââ README.md # Ce document
âââ requirements.txt
âââ docs/
â âââ analyse_filtrage.md # Choix du FIR, paramĂštres STFT
â âââ choix_outils.md # Justification des outils Python
â âââ Analyses_des_chants_d_oiseaux_presentation.pdf
âââ project_plan/
â âââ ARBORESCENCE.md # SpĂ©cification de lâarchitecture
â âââ WBS.md # Work Breakdown Structure dĂ©taillĂ©
âââ data/
â âââ raw/ # Fichiers .wav dâorigine
â â âââ Bird songs/
â â âââ grive.wav
â â âââ merle.wav
â â âââ mĂ©sange charbonniĂšre.wav
â â âââ pic vert.wav
â â âââ pie.wav
â â âââ pigeon.wav
â â âââ pinson.wav
â â âââ rouge-gorge.wav
â â âââ sitelle torchepot.wav
â â âââ tourterelle.wav
â âââ processed/ # Audios filtrĂ©s (FIR) gĂ©nĂ©rĂ©s par le pipeline
â âââ Bird songs/
â âââ grive_bandpass.wav
â âââ merle_bandpass.wav
â âââ ...
âââ assets/
â âââ figures/ # Spectrogrammes simples + matrice de confusion
â â âââ Bird songs/
â â â âââ grive_spectrogram.png
â â â âââ merle_spectrogram.png
â â â âââ ...
â â âââ rf_segments_confusion_matrix.png
â âââ figures_annotated/ # Spectrogrammes annotĂ©s (segments)
â âââ grive_segments.png
â âââ merle_segments.png
â âââ ...
âââ src/ # Code rĂ©utilisable (package)
â âââ __init__.py
â âââ config.py # ParamĂštres centraux (chemins, FIR, STFT, SR)
â âââ io/
â â âââ __init__.py
â â âââ load_audio.py # Lecture, normalisation, resampling
â â âââ save_audio.py # Sauvegarde wav
â âââ signal/
â â âââ __init__.py
â â âââ fir_bandpass.py # Conception + application du FIR linĂ©aire
â â âââ stft.py # STFT + sauvegarde de spectrogrammes
â â âââ noise_reduction.py # RĂ©servĂ© pour des amĂ©liorations futures
â âââ detection/
â â âââ __init__.py
â â âââ vad_spectral_flux.py # DĂ©tection dâactivitĂ© par flux spectral
â â âââ segmentation_2d.py # Squelette pour segmentation 2D (non utilisĂ©)
â âââ features/
â âââ __init__.py
â âââ mfcc.py # MFCC + statistiques (mean, std, min, max)
â âââ spectral_stats.py # Centroid, bandwidth, rolloff, flatness, entropie
â âââ f0.py # Estimation de F0 (YIN) + statistiques
âââ scripts/ # Scripts dâentrĂ©e (cliquables)
â âââ run_pipeline.py # Pipeline complet jusquâaux segments
â âââ extract_features.py # Extraction des features par segment
â âââ train_classifier.py # EntraĂźnement RandomForest + rapport + figures
â âââ predict_segments.py # PrĂ©diction de chaque segment du dataset
â âââ inspect_segments.py # GĂ©nĂ©ration des spectrogrammes annotĂ©s
â âââ predict_file.py # PrĂ©diction de lâespĂšce dominante dâun nouveau .wav
âââ experiments/
âââ exp1/
âââ segments.csv # Segments dĂ©tectĂ©s (fichier, t_onset, t_offset)
âââ features.csv # Features agrĂ©gĂ©es par segment
âââ metrics.json # (optionnel) mĂ©triques de dĂ©tection
âââ predictions_segments.csv # PrĂ©dictions du modĂšle sur les segments
âââ models/
â âââ rf_segments.joblib # ModĂšle RandomForest sauvegardĂ©
âââ reports/
âââ rf_segments_report.txt# Rapport de classification (sklearn)
Pour des détails supplémentaires, se référer à project_plan/ARBORESCENCE.md qui décrit le contenu minimum par dossier.
Les choix méthodologiques et les justifications théoriques sont détaillés dans :
Cette section résume les points principaux.
Les chants dâoiseaux Ă©tudiĂ©s sont principalement situĂ©s entre 1 kHz et 8 kHz. Afin de :
- rejeter les bruits graves (vent, trafic, manipulations de micro, etc.),
- ne pas conserver des fréquences trÚs aiguës généralement peu informatives,
un filtre passe-bande FIR à phase linéaire est utilisé, avec :
- coupure basse :
BANDPASS_LOW = 400.0Hz - coupure haute :
BANDPASS_HIGH = 8000.0Hz - nombre de taps :
FIR_NUMTAPS = 1025
Implémentation : src/signal/fir_bandpass.py
from src.signal.fir_bandpass import apply_fir_bandpass y_filt = apply_fir_bandpass( y, fs=sr, lowcut=BANDPASS_LOW, highcut=BANDPASS_HIGH, numtaps=FIR_NUMTAPS, )
Le filtrage est appliquĂ© hors temps rĂ©el, via scipy.signal.filtfilt, ce qui garantit une phase globale nulle (pas de dĂ©calage temporel) et conserve lâenveloppe des cris.
Les paramÚtres STFT sont centralisés dans src/config.py :
TARGET_SR = 22050HzSTFT_N_FFT = 1024STFT_HOP_LENGTH = 256STFT_WINDOW = "hann"
Calcul et sauvegarde dâun spectrogramme typique (dans scripts/run_pipeline.py) :
from src.signal.stft import compute_spectrogram, save_spectrogram_figure S_db, freqs, times = compute_spectrogram( y_filt, sr=sr, n_fft=STFT_N_FFT, hop_length=STFT_HOP_LENGTH, window=STFT_WINDOW, ) save_spectrogram_figure( S_db, sr=sr, hop_length=STFT_HOP_LENGTH, out_path=fig_out_path, )
Les figures générées sont stockées dans assets/figures/Bird%20songs/*_spectrogram.png.
La dĂ©tection dâactivitĂ© (VAD "aviaire") repose sur le flux spectral :
- Calcul de la magnitude STFT.
- Différence entre frames successives.
- On ne garde que les augmentations (partie positive).
- Seuil adaptatif basĂ© sur la mĂ©diane et lâĂ©cart-type :
seuil = mĂ©diane + k·Ï. - Conversion en segments temporels et fusion des segments proches.
Implémentation principale : src/detection/vad_spectral_flux.py
Fonction utilisée dans le pipeline de base :
from src.detection.vad_spectral_flux import detect_activity segments = detect_activity( y_filt, sr=sr, n_fft=STFT_N_FFT, hop_length=STFT_HOP_LENGTH, k=0.6, min_duration_s=0.03, )
Chaque segment est ensuite converti en intervalle temporel (t_onset_s, t_offset_s) et stocké dans experiments/exp1/segments.csv.
Les features sont calculées pour chaque segment audio détecté (voir scripts/extract_features.py).
Lors de lâextraction, on charge dâabord lâaudio filtrĂ© complet (*_bandpass.wav), puis on dĂ©coupe selon les timestamps des segments.
Pour chaque segment, on calcule :
-
MFCC (
src/features/mfcc.py)- 20 coefficients MFCC
- Agrégation : moyenne, écart-type, min, max pour chaque coefficient
â environ 80 colonnes au total pour les MFCC
-
Descripteurs spectraux (
src/features/spectral_stats.py)- centroid spectral
- bande passante
- rolloff (95 %)
- flatness
- entropie spectrale moyenne
â moyenne et Ă©cart-type pour certains, soit plusieurs colonnes additionnelles
-
Fréquence fondamentale F0 (
src/features/f0.py)- estimation par lâalgorithme YIN (
librosa.yin) f0_mean_hz,f0_std_hz,f0_min_hz,f0_max_hzf0_voiced_ratio(proportion de frames voisées)
- estimation par lâalgorithme YIN (
Extrait du code dâagrĂ©gation (simplifiĂ©) :
from src.features.mfcc import compute_mfcc_stats from src.features.spectral_stats import compute_spectral_stats from src.features.f0 import compute_f0_stats def extract_features_for_segment(y, sr): features = {} features.update(compute_mfcc_stats(y, sr, n_mfcc=20, n_fft=STFT_N_FFT, hop_length=STFT_HOP_LENGTH)) features.update(compute_spectral_stats(y, sr, n_fft=STFT_N_FFT, hop_length=STFT_HOP_LENGTH)) features.update(compute_f0_stats(y, sr, fmin=300.0, fmax=8000.0, frame_length=STFT_N_FFT, hop_length=STFT_HOP_LENGTH)) return features
Les résultats sont sauvegardés dans experiments/exp1/features.csv avec au minimum les colonnes :
file,segment_id,t_onset_s,t_offset_s,duration_smfcc_01_mean,mfcc_01_std, ...,mfcc_20_maxspec_centroid_hz_mean,spec_centroid_hz_std, etc.f0_mean_hz,f0_std_hz,f0_voiced_ratio, etc.
Un classifieur standard de type RandomForest est entraßné à partir des features.
Script : scripts/train_classifier.py
Pipeline utilisé :
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.ensemble import RandomForestClassifier clf = Pipeline( steps=[ ("scaler", StandardScaler()), ("rf", RandomForestClassifier( n_estimators=300, random_state=42, n_jobs=-1, )), ] )
- Construction de la colonne
speciesĂ partir du nom de fichier (ex.Bird songs/grive.wavâgrive). - SĂ©paration en train / test (25 % test, stratifiĂ© par espĂšce).
- EntraĂźnement du modĂšle.
- Calcul dâun rapport de classification (F1, prĂ©cision, rappel par classe).
- Calcul et sauvegarde dâune matrice de confusion dans
assets/figures/rf_segments_confusion_matrix.png. - Sauvegarde du modĂšle dans
experiments/exp1/models/rf_segments.joblibavec la liste des colonnes de features (feature_cols).
Le rapport texte complet est enregistré dans :
experiments/exp1/reports/rf_segments_report.txt.
Commandes :
# Ă la racine du projet python scripts/run_pipeline.py
Effets principaux :
- lecture des 10 fichiers
.wavdansdata/raw/Bird songs/ - filtrage passe-bande FIR et sauvegarde des audios filtrés dans
data/processed/Bird songs/*_bandpass.wav - calcul et sauvegarde des spectrogrammes dans
assets/figures/Bird songs/*_spectrogram.png - détection des segments et création de
experiments/exp1/segments.csv
Sur ce dataset, on obtient au total 115 segments détectés, répartis par fichier comme suit :
grive.wav: 12 segments (durĂ©e â 11.46 s)merle.wav: 8 segments (durĂ©e â 13.62 s)mĂ©sange charbonniĂšre.wav: 23 segments (durĂ©e â 13.20 s)pic vert.wav: 5 segments (durĂ©e â 13.10 s)pie.wav: 12 segments (durĂ©e â 14.06 s)pigeon.wav: 15 segments (durĂ©e â 12.95 s)pinson.wav: 5 segments (durĂ©e â 14.30 s)rouge-gorge.wav: 7 segments (durĂ©e â 13.12 s)sitelle torchepot.wav: 10 segments (durĂ©e â 14.49 s)tourterelle.wav: 18 segments (durĂ©e â 13.31 s)
Contenu de segments.csv :
file,segment_id,t_onset_s,t_offset_s Bird songs\grive.wav,0,1.660,2.055 Bird songs\grive.wav,1,2.635,3.042 Bird songs\merle.wav,0,2.194,2.345 Bird songs\merle.wav,1,2.473,2.961 Bird songs\mésange charbonniÚre.wav,0,2.113,2.322 Bird songs\mésange charbonniÚre.wav,1,2.461,2.682 ...
Commandes :
python scripts/extract_features.pyCe script :
- lit
experiments/exp1/segments.csv(ici 115 segments), - charge les audios filtrés correspondants (
*_bandpass.wav), - découpe les segments, calcule les features,
- sauvegarde le résultat dans
experiments/exp1/features.csv(115 lignes et 99 colonnes).
La structure de features.csv :
file,segment_id,t_onset_s,t_offset_s,duration_s,mfcc_01_mean,mfcc_01_std,...,f0_mean_hz,f0_voiced_ratio Bird songs\merle.wav,0,2.194,2.345,0.151,-245.1,12.3,...,3200.5,0.92 Bird songs\merle.wav,1,2.473,2.961,0.488,-240.8,11.7,...,3150.7,0.89
Commandes :
python scripts/train_classifier.pyCe script :
- lit
experiments/exp1/features.csv, - crée la colonne
species, - sépare train / test,
- entraĂźne un RandomForest,
- génÚre :
experiments/exp1/reports/rf_segments_report.txtassets/figures/rf_segments_confusion_matrix.pngexperiments/exp1/models/rf_segments.joblib
Chargement des features depuis : experiments\exp1\features.csv
Nombre de segments par espĂšce :
species
mésange charbonniÚre 23
tourterelle 18
pigeon 15
grive 12
pie 12
sitelle torchepot 10
merle 8
rouge-gorge 7
pic vert 5
pinson 5
Name: count, dtype: int64
Nombre de features : 95
Nombre total d'échantillons : 115
Taille train : 86
Taille test : 29
EntraĂźnement du modĂšle...
=== Rapport de classification (test) ===
precision recall f1-score support
grive 1.00 1.00 1.00 3
merle 1.00 1.00 1.00 2
mésange charbonniÚre 1.00 1.00 1.00 6
pic vert 1.00 1.00 1.00 1
pie 1.00 1.00 1.00 3
pigeon 1.00 0.75 0.86 4
pinson 0.50 1.00 0.67 1
rouge-gorge 1.00 0.50 0.67 2
sitelle torchepot 1.00 1.00 1.00 2
tourterelle 0.83 1.00 0.91 5
accuracy 0.93 29
macro avg 0.93 0.93 0.91 29
weighted avg 0.95 0.93 0.93 29
Rapport sauvegardé -> experiments\exp1\reports\rf_segments_report.txt
Matrice de confusion sauvegardée -> assets\figures\rf_segments_confusion_matrix.png
ModÚle sauvegardé -> experiments\exp1\models\rf_segments.joblib
Une fois le modĂšle entraĂźnĂ©, on peut prĂ©dire lâespĂšce pour tous les segments de features.csv :
python scripts/predict_segments.pyCe script :
- charge
features.csvainsi que le modĂšlerf_segments.joblib, - applique le classifieur sur chaque ligne,
- calcule une prĂ©cision globale sur lâensemble du dataset,
- enregistre les prédictions dans
experiments/exp1/predictions_segments.csv.
Extrait de sortie console :
Accuracy sur l'ensemble des segments : 0.920
Quelques lignes :
file segment_id t_onset_s t_offset_s species pred_species pred_confidence
0 Bird songs/merle.wav 0 0.350 0.720 merle merle 0.98
1 Bird songs/merle.wav 1 0.900 1.250 merle merle 0.95
...
Pour mieux comprendre la détection, on peut générer des spectrogrammes avec les segments surlignés :
python scripts/inspect_segments.pyCe script produit des images dans assets/figures_annotated/, par exemple :
assets/figures_annotated/merle_segments.pngassets/figures_annotated/grive_segments.png
Ces figures montrent les zones détectées (segments) en superposition sur le spectrogramme.
Enfin, on peut appliquer le pipeline Ă un nouveau fichier (hors dataset de base) :
python scripts/predict_file.py pathïżœers
ouvel_enregistrement.wavLe script effectue :
- chargement et resampling du fichier audio,
- filtrage FIR passe-bande,
- détection des segments par VAD,
- extraction des features pour chaque segment,
- prĂ©diction de lâespĂšce pour chaque segment,
- vote majoritaire pour dĂ©terminer lâespĂšce dominante.
Exemple de sortie (simplifiée) :
=== Analyse de nouveau_fichier.wav ===
Audio chargé : durée = 12.34 s, sr = 22050 Hz
8 segments détectés
- segment 0: 0.32s â 0.71s â merle (conf=0.96)
- segment 1: 0.90s â 1.20s â merle (conf=0.93)
...
=== EspÚce dominante prédite ===
merle
Les figures les plus importantes générées par le projet sont :
-
Spectrogrammes de base (filtrés) pour chaque espÚce, par exemple :
assets/figures/Bird songs/merle_spectrogram.pngassets/figures/Bird songs/grive_spectrogram.png- etc.
-
Spectrogrammes annotés par segments :
assets/figures_annotated/merle_segments.pngassets/figures_annotated/grive_segments.png- ...
-
Matrice de confusion du classifieur par segments :
assets/figures/rf_segments_confusion_matrix.png
Ces figures sont mobilisées dans le fichier Analyses_des_chants_d_oiseaux_presentation.pdf pour illustrer les résultats.
Ce projet constitue un MVP (Minimum Viable Product) pour la dĂ©tection et la classification de chants dâoiseaux. Plusieurs limitations et pistes dâamĂ©lioration sont identifiĂ©es dans project_plan/WBS.md et rĂ©sumĂ©es ici :
-
Nombre dâespĂšces limitĂ© : le dataset travaille sur un petit ensemble dâespĂšces (grive, merle, mĂ©sange, etc.).
â Extension possible vers plus dâespĂšces et plus dâenregistrements. -
Pas de segmentation 2D complĂšte : le module
segmentation_2d.pyest présent mais non implémenté.
â AmĂ©lioration envisageable avec des techniques de segmentation sur le plan tempsâfrĂ©quence (masques binaires, composantes connexes, etc.). -
Réduction de bruit optionnelle non utilisée :
noise_reduction.pyest prĂ©vu pour une Ă©ventuelle soustraction spectrale ou filtre mĂ©dian 2D, mais nâest pas activement utilisĂ© dans la version actuelle.
â IntĂ©grer une rĂ©duction de bruit contrĂŽlĂ©e pour amĂ©liorer la robustesse en conditions rĂ©elles (vent, pluie, insectes). -
ModĂšle de classification simple : le RandomForest sur features classiques fonctionne correctement, mais :
â des modĂšles plus avancĂ©s (SVM, gradient boosting, CNN avec spectrogrammes log-Mel) pourraient ĂȘtre explorĂ©s si lâon Ă©largit le jeu de donnĂ©es. -
Pas de temps réel : tout le pipeline est hors ligne, comme prévu dans les hypothÚses de départ.
â Une version temps rĂ©el nĂ©cessiterait un filtrage IIR et une gestion des buffers en streaming.
Malgré ces limites, le projet met en place une base solide pour des travaux futures en bioacoustique : pipeline reproductible, code organisé, documentation et premiers résultats quantitatifs.
Pour aller plus loin, les fichiers internes suivants documentent le projet :
docs/analyse_filtrage.md: justification des paramĂštres du filtre FIR et de la STFT.docs/choix_outils.md: choix techniques (Python, librairies) et installation.project_plan/ARBORESCENCE.md: spĂ©cification initiale de lâarchitecture du dĂ©pĂŽt.project_plan/WBS.md: dĂ©coupage du travail, jalons, checklist de validation.
Les résultats chiffrés détaillés sont disponibles dans :
experiments/exp1/reports/rf_segments_report.txtexperiments/exp1/predictions_segments.csvexperiments/exp1/metrics.json(si renseigné)
Projet réalisé par :
- Diego de Radigues
- Arthur Dufour
- Ange Simpalingabo