diff --git a/README.md b/README.md index 9e82be3..a350e4c 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ This repository offers a growing collection of computer vision tutorials. Learn |:------------:|:-------------------------------------------------:|:---------------------------:|:----------------------:| | [How to Track Objects with SORT Tracker](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-track-objects-with-sort-tracker.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-track-objects-with-sort-tracker.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-track-objects-with-sort-tracker.ipynb) | | [![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/roboflow/trackers) [![arXiv](https://img.shields.io/badge/arXiv-1602.00763-b31b1b.svg)](https://arxiv.org/abs/1602.00763)| | [How to Track Objects with DeepSORT Tracker](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-track-objects-with-deepsort-tracker.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-track-objects-with-deepsort-tracker.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-track-objects-with-deepsort-tracker.ipynb) | | [![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/roboflow/trackers) [![arXiv](https://img.shields.io/badge/arXiv-1703.07402-b31b1b.svg)](https://arxiv.org/abs/1703.07402)| -## 🛠️ computer vision skills (21 notebooks) +## 🛠️ computer vision skills (22 notebooks) | **notebook** | **open in colab / kaggle / sagemaker studio lab** | **complementary materials** | **repository / paper** | |:------------:|:-------------------------------------------------:|:---------------------------:|:----------------------:| | [Football AI](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/football-ai.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/football-ai.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/football-ai.ipynb) | [![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/camera-calibration-sports-computer-vision/) [![YouTube](https://badges.aleen42.com/src/youtube.svg)](https://youtu.be/aBVGKoNZQUw) | [![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/roboflow/sports) | @@ -150,6 +150,7 @@ This repository offers a growing collection of computer vision tutorials. Learn | [How to Use PolygonZone and Roboflow Supervision](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-use-polygonzone-annotate-and-supervision.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-use-polygonzone-annotate-and-supervision.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-use-polygonzone-annotate-and-supervision.ipynb) | [![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/polygonzone/) | | | [Train a Package Detector With Two Labeled Images](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/train-package-detector-two-labeled-images.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/train-package-detector-two-labeled-images.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/train-package-detector-two-labeled-images.ipynb) | [![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/package-detector/) | [![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/autodistill/autodistill-seggpt) | | [Image-to-Image Search with CLIP and faiss](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/image-to-image-search-clip-faiss.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/image-to-image-search-clip-faiss.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/image-to-image-search-clip-faiss.ipynb) | [![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/clip-image-search-faiss/) | | +| [Working with PPM Image Format in Autodistill](https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-work-with-ppm-images.ipynb) | [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-work-with-ppm-images.ipynb) [![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/roboflow-ai/notebooks/blob/main/notebooks/how-to-work-with-ppm-images.ipynb) | [![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/autodistill) | [![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/autodistill/autodistill) | ## 🎬 videos diff --git a/automation/autogenerate_notebooks_table.py b/automation/autogenerate_notebooks_table.py index 0ca4c7a..eba2113 100644 --- a/automation/autogenerate_notebooks_table.py +++ b/automation/autogenerate_notebooks_table.py @@ -98,12 +98,22 @@ def format(self) -> str: def read_lines_from_file(path: str) -> List[str]: - with open(path) as file: + encodings_to_try = ['utf-8', 'latin-1', 'cp1252'] + + for encoding in encodings_to_try: + try: + with open(path, encoding=encoding) as file: + return [line.rstrip() for line in file] + except UnicodeDecodeError: + continue + + # If all encodings fail, try with errors='replace' + with open(path, encoding='utf-8', errors='replace') as file: return [line.rstrip() for line in file] def save_lines_to_file(path: str, lines: List[str]) -> None: - with open(path, "w") as f: + with open(path, "w", encoding="utf-8") as f: for line in lines: f.write("%s\n" % line) diff --git a/automation/notebooks-table-data.csv b/automation/notebooks-table-data.csv index 881d4d2..96e9a72 100644 --- a/automation/notebooks-table-data.csv +++ b/automation/notebooks-table-data.csv @@ -72,3 +72,4 @@ Create Segmentation Masks with Roboflow, how-to-generate-segmentation-mask-with- How to Use PolygonZone and Roboflow Supervision, how-to-use-polygonzone-annotate-and-supervision.ipynb, https://blog.roboflow.com/polygonzone/, , , , False, skills Train a Package Detector With Two Labeled Images, train-package-detector-two-labeled-images.ipynb, https://blog.roboflow.com/package-detector/, , https://github.com/autodistill/autodistill-seggpt, , False, skills Image-to-Image Search with CLIP and faiss, image-to-image-search-clip-faiss.ipynb, https://blog.roboflow.com/clip-image-search-faiss/, , , , False, skills +Working with PPM Image Format in Autodistill, how-to-work-with-ppm-images.ipynb, https://blog.roboflow.com/autodistill, , https://github.com/autodistill/autodistill, , False, skills diff --git a/notebooks/how-to-work-with-ppm-images.ipynb b/notebooks/how-to-work-with-ppm-images.ipynb new file mode 100644 index 0000000..55d40f8 --- /dev/null +++ b/notebooks/how-to-work-with-ppm-images.ipynb @@ -0,0 +1,647 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6f3abae6", + "metadata": {}, + "source": [ + "[![Roboflow Notebooks](https://media.roboflow.com/notebooks/template/bannertest2-2.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672932710194)](https://github.com/roboflow/notebooks)\n", + "\n", + "# Working with PPM Image Format in Autodistill\n", + "\n", + "---\n", + "\n", + "## Steps in this Tutorial\n", + "\n", + "In this tutorial, we are going to cover:\n", + "\n", + "- Understanding PPM (Portable Pixmap Format) images\n", + "- Creating PPM images for testing\n", + "- Loading PPM images with Autodistill's `load_image` function\n", + "- Converting PPM images to other formats\n", + "- Using PPM images in an Autodistill workflow\n", + "\n", + "## Introduction to PPM Format\n", + "\n", + "PPM (Portable Pixmap Format) is a simple image format that stores RGB pixels in an array. It's part of the Netpbm family of image formats, which also includes PBM (Portable Bitmap) and PGM (Portable Graymap).\n", + "\n", + "PPM is a lossless format that doesn't use compression, which makes it ideal for testing and development. Files in PPM format can be either:\n", + "- ASCII format (P3) - Human readable but inefficient\n", + "- Binary format (P6) - More efficient storage\n", + "\n", + "While PPM files are larger than formats like JPEG or PNG due to lack of compression, they're useful in certain scientific and academic contexts where data integrity is crucial." + ] + }, + { + "cell_type": "markdown", + "id": "bf4a68f3", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "First, let's make sure we have the required libraries installed:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14862b4c", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install autodistill supervision numpy opencv-python pillow -q" + ] + }, + { + "cell_type": "markdown", + "id": "fa31e4c7", + "metadata": {}, + "source": [ + "## Import Required Libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "debb36e7", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import numpy as np\n", + "import cv2\n", + "from PIL import Image\n", + "import supervision as sv\n", + "from autodistill.helpers import load_image" + ] + }, + { + "cell_type": "markdown", + "id": "c390180a", + "metadata": {}, + "source": [ + "## Creating a PPM Image\n", + "\n", + "Let's start by creating a simple PPM image for testing purposes. We'll create both an ASCII (P3) format and a binary (P6) format PPM file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19087460", + "metadata": {}, + "outputs": [], + "source": [ + "def create_ascii_ppm(filepath=\"test_ascii.ppm\", width=100, height=100):\n", + " \"\"\"Create a simple ASCII PPM image file (P3 format)\"\"\"\n", + " with open(filepath, 'w') as f:\n", + " f.write('P3\\n') # ASCII format\n", + " f.write(f'{width} {height}\\n')\n", + " f.write('255\\n') # Max color value\n", + " \n", + " # Write RGB data as ASCII numbers\n", + " for y in range(height):\n", + " for x in range(width):\n", + " # Create a gradient\n", + " r = (x * 255) // width\n", + " g = (y * 255) // height\n", + " b = ((x+y) * 255) // (width+height)\n", + " f.write(f\"{r} {g} {b} \")\n", + " f.write('\\n')\n", + " \n", + " return filepath\n", + "\n", + "def create_binary_ppm(filepath=\"test_binary.ppm\", width=100, height=100):\n", + " \"\"\"Create a simple binary PPM image file (P6 format)\"\"\"\n", + " with open(filepath, 'wb') as f:\n", + " f.write(b'P6\\n')\n", + " f.write(f'{width} {height}\\n'.encode())\n", + " f.write(b'255\\n') # Max color value\n", + " \n", + " # Write RGB data as binary\n", + " for y in range(height):\n", + " for x in range(width):\n", + " # Create a gradient\n", + " r = (x * 255) // width\n", + " g = (y * 255) // height\n", + " b = ((x+y) * 255) // (width+height)\n", + " f.write(bytes([r, g, b]))\n", + " \n", + " return filepath\n", + "\n", + "# Create both types of PPM files\n", + "ascii_ppm = create_ascii_ppm()\n", + "binary_ppm = create_binary_ppm()\n", + "\n", + "print(f\"Created ASCII PPM: {ascii_ppm}\")\n", + "print(f\"Created Binary PPM: {binary_ppm}\")" + ] + }, + { + "cell_type": "markdown", + "id": "596b39a3", + "metadata": {}, + "source": [ + "## Loading PPM Images with Autodistill\n", + "\n", + "Autodistill's `load_image` function now supports PPM files directly. Let's load both of our test files:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a85fe10b", + "metadata": {}, + "outputs": [], + "source": [ + "# Load the ASCII PPM\n", + "ascii_image_pil = load_image(ascii_ppm, return_format=\"PIL\")\n", + "ascii_image_cv2 = load_image(ascii_ppm, return_format=\"cv2\")\n", + "ascii_image_numpy = load_image(ascii_ppm, return_format=\"numpy\")\n", + "\n", + "# Load the Binary PPM\n", + "binary_image_pil = load_image(binary_ppm, return_format=\"PIL\")\n", + "binary_image_cv2 = load_image(binary_ppm, return_format=\"cv2\")\n", + "binary_image_numpy = load_image(binary_ppm, return_format=\"numpy\")\n", + "\n", + "# Display information about the loaded images\n", + "print(\"ASCII PPM loaded as:\")\n", + "print(f\" PIL Image: {type(ascii_image_pil)} with size {ascii_image_pil.size} and mode {ascii_image_pil.mode}\")\n", + "print(f\" CV2 Image: {type(ascii_image_cv2)} with shape {ascii_image_cv2.shape}\")\n", + "print(f\" Numpy Array: {type(ascii_image_numpy)} with shape {ascii_image_numpy.shape}\")\n", + "print(\"\\nBinary PPM loaded as:\")\n", + "print(f\" PIL Image: {type(binary_image_pil)} with size {binary_image_pil.size} and mode {binary_image_pil.mode}\")\n", + "print(f\" CV2 Image: {type(binary_image_cv2)} with shape {binary_image_cv2.shape}\")\n", + "print(f\" Numpy Array: {type(binary_image_numpy)} with shape {binary_image_numpy.shape}\")" + ] + }, + { + "cell_type": "markdown", + "id": "db75ad20", + "metadata": {}, + "source": [ + "## Visualizing the PPM Images\n", + "\n", + "Let's visualize our PPM images using both Matplotlib and Supervision's `plot_image` function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4de6278", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 2, 1)\n", + "plt.title('ASCII PPM (P3 Format)')\n", + "plt.imshow(ascii_image_pil)\n", + "plt.axis('off')\n", + "\n", + "plt.subplot(1, 2, 2)\n", + "plt.title('Binary PPM (P6 Format)')\n", + "plt.imshow(binary_image_pil)\n", + "plt.axis('off')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "831264ec", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Using Supervision to display the PPM images:\")\n", + "print(\"\\nASCII PPM Image:\")\n", + "sv.plot_image(ascii_image_cv2, size=(6, 6))\n", + "\n", + "print(\"\\nBinary PPM Image:\")\n", + "sv.plot_image(binary_image_cv2, size=(6, 6))" + ] + }, + { + "cell_type": "markdown", + "id": "b9bb96e0", + "metadata": {}, + "source": [ + "## Converting Between PPM and Other Formats\n", + "\n", + "Autodistill and PIL make it easy to convert between PPM and other commonly used formats:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e4c154c", + "metadata": {}, + "outputs": [], + "source": [ + "# Convert PPM to JPEG\n", + "binary_image_pil.save(\"converted_from_ppm.jpg\")\n", + "\n", + "# Convert PPM to PNG\n", + "binary_image_pil.save(\"converted_from_ppm.png\")\n", + "\n", + "# Convert JPEG to PPM\n", + "test_jpg = Image.new('RGB', (100, 100), color='red')\n", + "test_jpg.save(\"test.jpg\")\n", + "jpg_image = Image.open(\"test.jpg\")\n", + "jpg_image.save(\"converted_to_ppm.ppm\")\n", + "\n", + "print(\"Conversion complete. Files created:\")\n", + "print(\"- converted_from_ppm.jpg\")\n", + "print(\"- converted_from_ppm.png\")\n", + "print(\"- test.jpg\")\n", + "print(\"- converted_to_ppm.ppm\")" + ] + }, + { + "cell_type": "markdown", + "id": "21acdb11", + "metadata": {}, + "source": [ + "## Using PPM Images in Autodistill Workflow\n", + "\n", + "Now let's demonstrate how to use PPM images directly in an Autodistill workflow. First, let's create a more complex test image that has enough features to detect:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23c104d6", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's create a PPM with some simple shapes\n", + "def create_shapes_ppm(filepath=\"shapes.ppm\", width=640, height=480):\n", + " # Create a blank canvas\n", + " img = np.zeros((height, width, 3), dtype=np.uint8)\n", + " \n", + " # Draw a red rectangle\n", + " img[50:150, 100:200] = [0, 0, 255] # Red in BGR\n", + " \n", + " # Draw a green circle\n", + " cv2.circle(img, (width//2, height//2), 100, (0, 255, 0), -1) # Green circle\n", + " \n", + " # Draw a blue triangle\n", + " pts = np.array([[450, 50], [550, 150], [400, 200]], np.int32)\n", + " pts = pts.reshape((-1, 1, 2))\n", + " cv2.fillPoly(img, [pts], (255, 0, 0)) # Blue triangle\n", + " \n", + " # Save as PPM\n", + " cv2_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", + " cv2_pil.save(filepath)\n", + " \n", + " return filepath\n", + "\n", + "# Create and display the shapes image\n", + "shapes_ppm = create_shapes_ppm()\n", + "shapes_img = load_image(shapes_ppm, return_format=\"cv2\")\n", + "print(f\"Created shapes PPM image: {shapes_ppm}\")\n", + "sv.plot_image(shapes_img, size=(10, 8))" + ] + }, + { + "cell_type": "markdown", + "id": "3baefaf0", + "metadata": {}, + "source": [ + "Now let's set up a simple Autodistill workflow using a mock model to demonstrate loading and processing PPM images:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96984bd7", + "metadata": {}, + "outputs": [], + "source": [ + "# Simple mock model to detect colored regions\n", + "# (In a real scenario, you would use a proper model like YOLO or GroundingDINO)\n", + "def detect_colored_regions(image_path):\n", + " # This is a mock implementation to simulate model detection\n", + " img = load_image(image_path, return_format=\"cv2\")\n", + " \n", + " # Convert to HSV for easier color detection\n", + " hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n", + " \n", + " # Define color thresholds\n", + " lower_red = np.array([0, 100, 100])\n", + " upper_red = np.array([10, 255, 255])\n", + " lower_green = np.array([50, 100, 100])\n", + " upper_green = np.array([70, 255, 255])\n", + " lower_blue = np.array([110, 100, 100])\n", + " upper_blue = np.array([130, 255, 255])\n", + " \n", + " # Create masks and find contours\n", + " detections = []\n", + " \n", + " # Red objects\n", + " red_mask = cv2.inRange(hsv, lower_red, upper_red)\n", + " red_contours, _ = cv2.findContours(red_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n", + " for cnt in red_contours:\n", + " if cv2.contourArea(cnt) > 1000: # Filter small contours\n", + " x, y, w, h = cv2.boundingRect(cnt)\n", + " detections.append(([x, y, x+w, y+h], 0.9, 0)) # class_id 0 for red\n", + " \n", + " # Green objects\n", + " green_mask = cv2.inRange(hsv, lower_green, upper_green)\n", + " green_contours, _ = cv2.findContours(green_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n", + " for cnt in green_contours:\n", + " if cv2.contourArea(cnt) > 1000: # Filter small contours\n", + " x, y, w, h = cv2.boundingRect(cnt)\n", + " detections.append(([x, y, x+w, y+h], 0.95, 1)) # class_id 1 for green\n", + " \n", + " # Blue objects\n", + " blue_mask = cv2.inRange(hsv, lower_blue, upper_blue)\n", + " blue_contours, _ = cv2.findContours(blue_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n", + " for cnt in blue_contours:\n", + " if cv2.contourArea(cnt) > 1000: # Filter small contours\n", + " x, y, w, h = cv2.boundingRect(cnt)\n", + " detections.append(([x, y, x+w, y+h], 0.85, 2)) # class_id 2 for blue\n", + " \n", + " return detections\n", + "\n", + "# Process our shapes PPM image\n", + "detections = detect_colored_regions(shapes_ppm)\n", + "\n", + "# Convert to Supervision Detections format\n", + "xyxy = np.array([det[0] for det in detections])\n", + "confidence = np.array([det[1] for det in detections])\n", + "class_id = np.array([det[2] for det in detections])\n", + "\n", + "sv_detections = sv.Detections(\n", + " xyxy=xyxy,\n", + " confidence=confidence,\n", + " class_id=class_id\n", + ")\n", + "\n", + "# Define class names\n", + "class_names = [\"red\", \"green\", \"blue\"]\n", + "\n", + "# Visualize the detections\n", + "box_annotator = sv.BoxAnnotator()\n", + "\n", + "# Create labels for each detection\n", + "labels = [f\"{class_names[class_id]} {confidence:.2f}\" for class_id, confidence in zip(sv_detections.class_id, sv_detections.confidence)]\n", + "\n", + "# Annotate the image\n", + "annotated_frame = box_annotator.annotate(\n", + " scene=shapes_img.copy(), \n", + " detections=sv_detections,\n", + " labels=labels\n", + ")\n", + "\n", + "# Display the result\n", + "sv.plot_image(annotated_frame, size=(10, 8))" + ] + }, + { + "cell_type": "markdown", + "id": "f63db1d6", + "metadata": {}, + "source": [ + "## Processing Multiple Images Including PPM Files\n", + "\n", + "Now let's demonstrate how to process a mixed directory containing PPM, JPG, and PNG files:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df0de565", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a directory to store mixed format images\n", + "import shutil\n", + "\n", + "if not os.path.exists('mixed_images'):\n", + " os.makedirs('mixed_images')\n", + "\n", + "# Copy existing files\n", + "shutil.copy(shapes_ppm, 'mixed_images/shapes.ppm')\n", + "shutil.copy('converted_from_ppm.jpg', 'mixed_images/gradient.jpg')\n", + "shutil.copy('converted_from_ppm.png', 'mixed_images/gradient.png')\n", + "\n", + "# Process all images in the directory\n", + "def process_image_directory(dir_path):\n", + " all_files = os.listdir(dir_path)\n", + " image_files = [f for f in all_files if f.lower().endswith(('.jpg', '.jpeg', '.png', '.ppm', '.pbm', '.pgm'))]\n", + " \n", + " print(f\"Found {len(image_files)} images in {dir_path}: {image_files}\")\n", + " \n", + " for image_file in image_files:\n", + " image_path = os.path.join(dir_path, image_file)\n", + " print(f\"\\nProcessing {image_file}...\")\n", + " \n", + " # Load the image using Autodistill's load_image function\n", + " try:\n", + " img = load_image(image_path, return_format=\"cv2\")\n", + " print(f\" Successfully loaded with shape {img.shape}\")\n", + " \n", + " # For demonstration purposes, just compute average color\n", + " avg_color = np.mean(img, axis=(0, 1))\n", + " print(f\" Average BGR color: {avg_color}\")\n", + " \n", + " # In a real application, you would run your model here\n", + " # detections = model.predict(img)\n", + " \n", + " except Exception as e:\n", + " print(f\" Error processing {image_file}: {e}\")\n", + "\n", + "# Process our mixed directory\n", + "process_image_directory('mixed_images')" + ] + }, + { + "cell_type": "markdown", + "id": "3faa57cc", + "metadata": {}, + "source": [ + "## Converting Between Image Formats in Autodistill\n", + "\n", + "Finally, let's implement a simple function to convert images between formats while preserving their contents:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e26aa68b", + "metadata": {}, + "outputs": [], + "source": [ + "def convert_image(input_path, output_path):\n", + " \"\"\"Convert an image from one format to another.\n", + " \n", + " Args:\n", + " input_path: Path to the input image\n", + " output_path: Path to the output image (extension determines format)\n", + " \"\"\"\n", + " # Use Autodistill's load_image to open the image (supports PPM)\n", + " img_pil = load_image(input_path, return_format=\"PIL\")\n", + " \n", + " # Save in the new format\n", + " img_pil.save(output_path)\n", + " \n", + " print(f\"Converted {input_path} to {output_path}\")\n", + " return output_path\n", + "\n", + "# Convert our shapes.ppm to PNG\n", + "convert_image(shapes_ppm, \"shapes_converted.png\")\n", + "\n", + "# Convert the binary PPM to JPEG\n", + "convert_image(binary_ppm, \"binary_converted.jpg\")\n", + "\n", + "# Load and display one of the converted images to confirm it works\n", + "converted_img = load_image(\"shapes_converted.png\", return_format=\"cv2\")\n", + "sv.plot_image(converted_img, size=(8, 6))" + ] + }, + { + "cell_type": "markdown", + "id": "dcd78a24", + "metadata": {}, + "source": [ + "## Working with PPM Format in `split_data` Function\n", + "\n", + "The Autodistill library's `split_data` function now supports PPM files. Let's demonstrate how it handles PPM images during dataset preparation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d53e8433", + "metadata": {}, + "outputs": [], + "source": [ + "from autodistill.helpers import split_data\n", + "\n", + "# Create a mini dataset with PPM images\n", + "if not os.path.exists('mini_dataset'):\n", + " os.makedirs('mini_dataset')\n", + " os.makedirs('mini_dataset/images')\n", + " os.makedirs('mini_dataset/annotations')\n", + "\n", + "# Create a few test PPM images\n", + "create_shapes_ppm('mini_dataset/images/shape1.ppm', 320, 240)\n", + "create_shapes_ppm('mini_dataset/images/shape2.ppm', 320, 240)\n", + "create_shapes_ppm('mini_dataset/images/shape3.ppm', 320, 240)\n", + "\n", + "# Create mock annotation files\n", + "for i in range(1, 4):\n", + " with open(f'mini_dataset/annotations/shape{i}.txt', 'w') as f:\n", + " f.write(f\"0 0.5 0.5 0.2 0.2\\n\") # Class 0, center x, center y, width, height\n", + "\n", + "# Create a data.yaml file\n", + "with open('mini_dataset/data.yaml', 'w') as f:\n", + " f.write(\"names:\\n - shape\\n\")\n", + "\n", + "# Now run split_data\n", + "split_data('mini_dataset', split_ratio=0.67)" + ] + }, + { + "cell_type": "markdown", + "id": "8ce8a3e3", + "metadata": {}, + "source": [ + "Let's verify what happened with our PPM files after running `split_data`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c21a5366", + "metadata": {}, + "outputs": [], + "source": [ + "# Check the directory structure\n", + "print(\"Directory structure after split_data:\")\n", + "!ls -R mini_dataset\n", + "\n", + "print(\"\\nNote that PPM files were converted to JPG format during the split_data process, which is expected behavior.\")\n", + "print(\"This conversion ensures compatibility with models that may not support PPM directly.\")" + ] + }, + { + "cell_type": "markdown", + "id": "1085aa1d", + "metadata": {}, + "source": [ + "## Cleanup\n", + "\n", + "Let's clean up the files we created:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3fa562f2", + "metadata": {}, + "outputs": [], + "source": [ + "# Remove created test files\n", + "import shutil\n", + "\n", + "files_to_remove = [\n", + " \"test_ascii.ppm\", \n", + " \"test_binary.ppm\", \n", + " \"converted_from_ppm.jpg\", \n", + " \"converted_from_ppm.png\",\n", + " \"test.jpg\", \n", + " \"converted_to_ppm.ppm\", \n", + " \"shapes.ppm\", \n", + " \"shapes_converted.png\", \n", + " \"binary_converted.jpg\"\n", + "]\n", + "\n", + "for file in files_to_remove:\n", + " if os.path.exists(file):\n", + " os.remove(file)\n", + " print(f\"Removed {file}\")\n", + "\n", + "# Remove directories\n", + "dirs_to_remove = [\"mixed_images\", \"mini_dataset\"]\n", + "\n", + "for dir_path in dirs_to_remove:\n", + " if os.path.exists(dir_path):\n", + " shutil.rmtree(dir_path)\n", + " print(f\"Removed directory {dir_path}\")" + ] + }, + { + "cell_type": "markdown", + "id": "40e33ab1", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "In this tutorial, we've demonstrated how to work with PPM image format in Autodistill:\n", + "\n", + "1. We created PPM images in both ASCII (P3) and binary (P6) formats\n", + "2. We loaded PPM images using Autodistill's `load_image` function with various return formats (PIL, cv2, numpy)\n", + "3. We visualized PPM images using both Matplotlib and Supervision's `plot_image`\n", + "4. We converted PPM images to other formats (JPEG, PNG) and vice versa\n", + "5. We used PPM images in a simple object detection workflow\n", + "6. We processed a directory containing mixed image formats including PPM files\n", + "7. We demonstrated how `split_data` handles PPM files by converting them to JPG\n", + "\n", + "The PPM format is now fully supported throughout the Autodistill library, making it possible to work with this format alongside more common formats like JPEG and PNG." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}