{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91249,"databundleVersionId":11294684,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport re\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image, ImageDraw\n\ndef normalize_image(image):\n    # Convert image to numpy array\n    img_array = np.array(image)\n    \n    # Calculate the lower and upper percentiles\n    lower_percentile = np.percentile(img_array, 2)\n    upper_percentile = np.percentile(img_array, 98)\n    \n    # Clip the values\n    img_array = np.clip(img_array, lower_percentile, upper_percentile)\n    \n    # Normalize to 0-255\n    img_array = ((img_array - lower_percentile) / (upper_percentile - lower_percentile) * 255).astype(np.uint8)\n    \n    return Image.fromarray(img_array)\n\ndef draw_circle(image, position, radius, color):\n    # Create a transparent overlay for drawing\n    overlay = Image.new(\"RGBA\", image.size, (0, 0, 0, 0))\n    overlay_draw = ImageDraw.Draw(overlay)\n    \n    # Draw a circle on the overlay\n    x, y = position\n    overlay_draw.ellipse((x - radius, y - radius, x + radius, y + radius), fill=color)\n    \n    # Composite the overlay with the original image\n    combined = Image.alpha_composite(image.convert(\"RGBA\"), overlay)\n    \n    return combined\n\ndef calculate_radius(distance):\n    # Scale the radius based on the distance from the motor position\n    if distance <= 10:\n        return 10  # Small radius for the exact slice\n    elif distance <= 25:\n        # Linear interpolation for radius between 10 and 50\n        return int(10 + (50 - 10) * (distance - 10) / (25 - 10))\n    else:\n        return 50  # Maximum radius for slices beyond 25\n\ndef create_gif_from_slices(directory, output_filename, duration, labels):\n    # Get a list of all image files in the directory matching the pattern\n    images = []\n    pattern = re.compile(r'slice_\\d{4}\\.jpg$')  # Regex pattern for slice_XXXX.jpg\n    \n    # Get all matching files and sort them\n    matching_files = sorted([f for f in os.listdir(directory) if pattern.match(f)])\n    \n    # Find the index where slice_0295.jpg would be\n    start_index = 0\n    for i, filename in enumerate(matching_files):\n        slice_num = int(filename.split('_')[1].split('.')[0])\n        if slice_num >= 295:\n            start_index = i\n            break\n    \n    # Process files starting from slice 295\n    for filename in matching_files[start_index:]:\n        filepath = os.path.join(directory, filename)\n        img = Image.open(filepath)\n        normalized_img = normalize_image(img)  # Normalize the image\n        \n        # Draw circles on the normalized image\n        slice_index = int(filename.split('_')[1].split('.')[0])  # Extract slice number from filename\n        \n        for _, row in labels.iterrows():\n            if row['tomo_id'] == 'tomo_6cf2df':\n                motor_axis_0 = row['Motor axis 0']\n                motor_axis_1 = row['Motor axis 1']\n                motor_axis_2 = row['Motor axis 2']\n                \n                # Calculate the distance from the current slice to the motor position\n                distance = abs(slice_index - motor_axis_0)\n                \n                # Check if the current slice is within 25 slices of the motor position\n                if distance <= 25:\n                    radius = calculate_radius(distance)  # Calculate the radius based on distance\n                    color = (255, 215, 0, 56)  # Gold color with alpha 56\n                    \n                    # Draw the circle at the specified position\n                    normalized_img = draw_circle(normalized_img, (motor_axis_2, motor_axis_1), radius, color)\n\n        images.append(normalized_img)\n\n    if images:\n        # Save the images as a GIF with adjustable duration\n        images[0].save(output_filename, save_all=True, append_images=images[1:], loop=0, duration=duration)\n        print(f\"GIF saved as {output_filename}\")\n    else:\n        print(\"No images found in the directory matching the pattern.\")\n\nif __name__ == \"__main__\":\n    directory = '/kaggle/input/byu-locating-bacterial-flagellar-motors-2025/train/tomo_6cf2df'  # Use the current working directory\n    output_filename = \"output/slices.gif\"  # Change this to your desired output filename\n    frame_duration = 100  # Duration in milliseconds (100 ms = 0.1 seconds)\n\n    # Load the labels from the CSV file\n    labels = pd.read_csv('/kaggle/input/byu-locating-bacterial-flagellar-motors-2025/train_labels.csv')\n\n    # Ensure the output directory exists\n    os.makedirs(os.path.dirname(output_filename), exist_ok=True)\n\n    create_gif_from_slices(directory, output_filename, frame_duration, labels)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-20T21:35:35.054690Z","iopub.execute_input":"2025-03-20T21:35:35.055029Z","iopub.status.idle":"2025-03-20T21:36:07.010633Z","shell.execute_reply.started":"2025-03-20T21:35:35.055000Z","shell.execute_reply":"2025-03-20T21:36:07.009271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}