{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":70203,"databundleVersionId":8068726,"sourceType":"competition"}],"dockerImageVersionId":30474,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Use Librosa to generate some Mel Spectrograms!\n### Maybe use these to train an ImageNet...\n\n#### This version generates images directly (not using matplotlib) - much faster!\n* Generating complete data set this time...","metadata":{}},{"cell_type":"code","source":"import os\n\nimport pandas as pd\nimport numpy as np\n\nimport librosa\nimport librosa.display\n\nfrom IPython.display import Audio\n\nfrom PIL import Image, ImageOps\n\nimport matplotlib.cm as cm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-09T02:23:39.907080Z","iopub.execute_input":"2024-04-09T02:23:39.907687Z","iopub.status.idle":"2024-04-09T02:23:39.971140Z","shell.execute_reply.started":"2024-04-09T02:23:39.907643Z","shell.execute_reply":"2024-04-09T02:23:39.969857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# File paths","metadata":{}},{"cell_type":"code","source":"audio_input_folder = \"/kaggle/input/birdclef-2024/train_audio\"\nimage_output_folder = \"/kaggle/working/train_images\"\nmeta_data = pd.read_csv(\"/kaggle/input/birdclef-2024/eBird_Taxonomy_v2021.csv\")\n\n","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:23:39.974433Z","iopub.execute_input":"2024-04-09T02:23:39.974980Z","iopub.status.idle":"2024-04-09T02:23:40.113065Z","shell.execute_reply.started":"2024-04-09T02:23:39.974931Z","shell.execute_reply":"2024-04-09T02:23:40.111662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Settings","metadata":{}},{"cell_type":"code","source":"#generates spectrograms are generated on audio clips this long\n#audio clips shorter than this are ignored\naudio_duration = 5.0\n\n#generates up to this many clips per file (multiples of audio_duration)\n#remainders of audio clip length / audio_duration are ignored\nmax_clips_per_audio_file = 1000\n\n#image size (image_size x image_size)\nimage_size = 224\n\n#processes up to this many audio files per species\nmax_audio_input_per_species = 1000\n\n#setting this above 0 will cause processing to start at a folder after the first\n#useful for restarting / continuing in case of running out of time / crash (folders are processed alphabetically)\nstart_at_folder_offset = 0","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:33:16.730292Z","iopub.execute_input":"2024-04-09T02:33:16.730726Z","iopub.status.idle":"2024-04-09T02:33:16.738200Z","shell.execute_reply.started":"2024-04-09T02:33:16.730691Z","shell.execute_reply":"2024-04-09T02:33:16.736865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Function to lookup bird species","metadata":{}},{"cell_type":"code","source":"def bird_species_from_folder(path):\n    if path.endswith('/'):\n        path = path[:-1]\n\n    last_folder = os.path.basename(path)\n    primary_com_name = meta_data.loc[meta_data['SPECIES_CODE'] == last_folder, 'PRIMARY_COM_NAME']\n    primary_com_name_str = primary_com_name.iloc[0] if not primary_com_name.empty else ''    \n    return f\"{primary_com_name_str} ({last_folder})\"","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:23:40.128796Z","iopub.execute_input":"2024-04-09T02:23:40.130052Z","iopub.status.idle":"2024-04-09T02:23:40.144602Z","shell.execute_reply.started":"2024-04-09T02:23:40.130004Z","shell.execute_reply":"2024-04-09T02:23:40.143039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save spectrograms to disk (or preview)","metadata":{}},{"cell_type":"code","source":"def spectrograms_for_audio(dirname, filename, preview=False):\n    # Calculate total duration of the audio file\n    audio_path = os.path.join(dirname, filename)\n    audio_data, sr = librosa.load(audio_path, sr=None)\n    total_duration = librosa.get_duration(path=audio_path)\n    \n    # Determine how many full segments of audio_duration fit in the audio file\n    num_segments = int(total_duration // audio_duration)\n    if num_segments == 0: return 0\n    if num_segments > max_clips_per_audio_file: num_segments = max_clips_per_audio_file\n        \n    for segment in range(num_segments):\n\n        offset_samples = int(segment * audio_duration * sr)\n        end_samples = int(offset_samples + audio_duration * sr)\n        \n        segment_data = audio_data[offset_samples:end_samples]\n        \n        S = librosa.feature.melspectrogram(y=segment_data, sr=sr, n_mels=128)\n        S_db = librosa.amplitude_to_db(S, ref=np.max)\n                \n        #convert spectrogram data into directly into image (much faster than matplotlib)\n        normalized_array = (S_db - np.min(S_db)) / (np.max(S_db) - np.min(S_db))\n        \n        #set color mapping \n        spectrogram_image = cm.magma(normalized_array)[:, :, :3]\n        spectrogram_image = (spectrogram_image * 255).astype(np.uint8)\n        spectrogram_image = Image.fromarray(spectrogram_image)\n        \n        #resize and flip (so consistent with original dataset)\n        spectrogram_image = spectrogram_image.resize((image_size, image_size), Image.ANTIALIAS)\n        spectrogram_image = ImageOps.flip(spectrogram_image)\n        \n        if preview == True:\n            display(Audio(data=segment_data, rate=sr))\n            return spectrogram_image\n        \n        output_folder = os.path.join(image_output_folder, os.path.basename(os.path.normpath(dirname)))\n        if not os.path.exists(output_folder):\n            os.makedirs(output_folder)\n\n        # Naming files with an offset to indicate seconds offset\n        base_filename = filename.replace('.ogg', '')\n        output_filename = os.path.join(output_folder, f\"{base_filename}_{int((segment + 1) * audio_duration):02d}.png\")\n        \n        spectrogram_image.save(output_filename)\n\n    return num_segments","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:27:52.416027Z","iopub.execute_input":"2024-04-09T02:27:52.416433Z","iopub.status.idle":"2024-04-09T02:27:52.431383Z","shell.execute_reply.started":"2024-04-09T02:27:52.416404Z","shell.execute_reply":"2024-04-09T02:27:52.430168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# A few demos\n### Note: If you've started generating spectrograms - you won't be able to generate more previews without restarting the notebook","metadata":{}},{"cell_type":"code","source":"spectrograms_for_audio(\"/kaggle/input/birdclef-2024/train_audio/zitcis1/\", \"XC655341.ogg\", preview=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:27:55.317771Z","iopub.execute_input":"2024-04-09T02:27:55.318527Z","iopub.status.idle":"2024-04-09T02:27:55.440477Z","shell.execute_reply.started":"2024-04-09T02:27:55.318487Z","shell.execute_reply":"2024-04-09T02:27:55.438767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nspectrograms_for_audio(\"/kaggle/input/birdclef-2024/train_audio/bkcbul1/\", \"XC129030.ogg\", preview=True)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:28:06.851575Z","iopub.execute_input":"2024-04-09T02:28:06.852042Z","iopub.status.idle":"2024-04-09T02:28:06.952527Z","shell.execute_reply.started":"2024-04-09T02:28:06.852000Z","shell.execute_reply":"2024-04-09T02:28:06.950931Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"spectrograms_for_audio(\"/kaggle/input/birdclef-2024/train_audio/asikoe2/\", \"XC138196.ogg\", preview=True)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:28:17.180154Z","iopub.execute_input":"2024-04-09T02:28:17.180581Z","iopub.status.idle":"2024-04-09T02:28:17.275489Z","shell.execute_reply.started":"2024-04-09T02:28:17.180535Z","shell.execute_reply":"2024-04-09T02:28:17.273751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generate the spectrograms!\n### 'X' is displayed for any file not processed due to being shorter than audio_duration","metadata":{}},{"cell_type":"code","source":"# List everything in the audio input folder\nentries = os.listdir(audio_input_folder)\n\n# Filter to get only directories\nsubdirectories = [entry for entry in entries if os.path.isdir(os.path.join(audio_input_folder, entry))]\n\n# Sort the directories\nsubdirectories.sort()\n\n#to start processing at a certain folder offset\nsubdirectories = subdirectories[start_at_folder_offset:]\n\nfolder_count = len(subdirectories)\nfolders_processed = 0\n\n# Iterate through each sorted directory\ntotal_images = 0\nfor subdir in subdirectories:\n    subdir_path = os.path.join(audio_input_folder, subdir)\n    folders_processed += 1\n    print(\"\\n\", bird_species_from_folder(subdir_path), folders_processed, \"/\", folder_count)\n\n    # List files in the current directory (in any order)\n    filenames = os.listdir(subdir_path)\n    \n    # Process up to max_audio_input_per_species files\n    images_this_species = 0\n    for filename in filenames[:max_audio_input_per_species]:\n        images_generated = spectrograms_for_audio(subdir_path, filename)\n        if images_generated > 0:\n            images_this_species += images_generated\n            print(\".\", end = \"\")\n        else:\n            print(\"X\", end = \"\")\n    print (f\"({images_this_species} images generated)\")\n    total_images += images_this_species\n\nprint (\"\\n\", total_images, \"total images generated\")\n                ","metadata":{"execution":{"iopub.status.busy":"2024-04-09T02:33:20.805140Z","iopub.execute_input":"2024-04-09T02:33:20.805568Z","iopub.status.idle":"2024-04-09T02:38:34.594052Z","shell.execute_reply.started":"2024-04-09T02:33:20.805520Z","shell.execute_reply":"2024-04-09T02:38:34.589011Z"},"trusted":true},"execution_count":null,"outputs":[]}]}