395 lines
15 KiB
Plaintext
395 lines
15 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Прост класификатор на изображения\n",
|
||
"\n",
|
||
"Този ноутбук показва как да класифицирате изображения, използвайки предварително обучена невронна мрежа.\n",
|
||
"\n",
|
||
"**Какво ще научите:**\n",
|
||
"- Как да заредите и използвате предварително обучен модел\n",
|
||
"- Предварителна обработка на изображения\n",
|
||
"- Правене на прогнози върху изображения\n",
|
||
"- Разбиране на оценките за увереност\n",
|
||
"\n",
|
||
"**Приложение:** Идентифициране на обекти в изображения (като \"котка\", \"куче\", \"кола\" и т.н.)\n",
|
||
"\n",
|
||
"---\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Стъпка 1: Импортиране на необходимите библиотеки\n",
|
||
"\n",
|
||
"Нека импортираме инструментите, които са ни нужни. Не се притеснявайте, ако все още не разбирате всички тях!\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Core libraries\n",
|
||
"import numpy as np\n",
|
||
"from PIL import Image\n",
|
||
"import requests\n",
|
||
"from io import BytesIO\n",
|
||
"\n",
|
||
"# TensorFlow for deep learning\n",
|
||
"try:\n",
|
||
" import tensorflow as tf\n",
|
||
" from tensorflow.keras.applications import MobileNetV2\n",
|
||
" from tensorflow.keras.applications.mobilenet_v2 import preprocess_input, decode_predictions\n",
|
||
" print(\"✅ TensorFlow loaded successfully!\")\n",
|
||
" print(f\" Version: {tf.__version__}\")\n",
|
||
"except ImportError:\n",
|
||
" print(\"❌ Please install TensorFlow: pip install tensorflow\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Стъпка 2: Зареждане на предварително обучен модел\n",
|
||
"\n",
|
||
"Ще използваме **MobileNetV2**, невронна мрежа, която вече е обучена върху милиони изображения.\n",
|
||
"\n",
|
||
"Това се нарича **Трансферно обучение** - използване на модел, който някой друг е обучил!\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"print(\"📦 Loading pre-trained MobileNetV2 model...\")\n",
|
||
"print(\" This may take a minute on first run (downloading weights)...\")\n",
|
||
"\n",
|
||
"# Load the model\n",
|
||
"# include_top=True means we use the classification layer\n",
|
||
"# weights='imagenet' means it was trained on ImageNet dataset\n",
|
||
"model = MobileNetV2(weights='imagenet', include_top=True)\n",
|
||
"\n",
|
||
"print(\"✅ Model loaded!\")\n",
|
||
"print(f\" The model can recognize 1000 different object categories\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Стъпка 3: Помощни функции\n",
|
||
"\n",
|
||
"Нека създадем функции за зареждане и подготовка на изображения за нашия модел.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"def load_image_from_url(url):\n",
|
||
" \"\"\"\n",
|
||
" Load an image from a URL.\n",
|
||
" \n",
|
||
" Args:\n",
|
||
" url: Web address of the image\n",
|
||
" \n",
|
||
" Returns:\n",
|
||
" PIL Image object\n",
|
||
" \"\"\"\n",
|
||
" response = requests.get(url)\n",
|
||
" img = Image.open(BytesIO(response.content))\n",
|
||
" return img\n",
|
||
"\n",
|
||
"\n",
|
||
"def prepare_image(img):\n",
|
||
" \"\"\"\n",
|
||
" Prepare an image for the model.\n",
|
||
" \n",
|
||
" Steps:\n",
|
||
" 1. Resize to 224x224 (model's expected size)\n",
|
||
" 2. Convert to array\n",
|
||
" 3. Add batch dimension\n",
|
||
" 4. Preprocess for MobileNetV2\n",
|
||
" \n",
|
||
" Args:\n",
|
||
" img: PIL Image\n",
|
||
" \n",
|
||
" Returns:\n",
|
||
" Preprocessed image array\n",
|
||
" \"\"\"\n",
|
||
" # Resize to 224x224 pixels\n",
|
||
" img = img.resize((224, 224))\n",
|
||
" \n",
|
||
" # Convert to numpy array\n",
|
||
" img_array = np.array(img)\n",
|
||
" \n",
|
||
" # Add batch dimension (model expects multiple images)\n",
|
||
" img_array = np.expand_dims(img_array, axis=0)\n",
|
||
" \n",
|
||
" # Preprocess for MobileNetV2\n",
|
||
" img_array = preprocess_input(img_array)\n",
|
||
" \n",
|
||
" return img_array\n",
|
||
"\n",
|
||
"\n",
|
||
"def classify_image(img):\n",
|
||
" \"\"\"\n",
|
||
" Classify an image and return top predictions.\n",
|
||
" \n",
|
||
" Args:\n",
|
||
" img: PIL Image\n",
|
||
" \n",
|
||
" Returns:\n",
|
||
" List of (class_name, confidence) tuples\n",
|
||
" \"\"\"\n",
|
||
" # Prepare the image\n",
|
||
" img_array = prepare_image(img)\n",
|
||
" \n",
|
||
" # Make prediction\n",
|
||
" predictions = model.predict(img_array, verbose=0)\n",
|
||
" \n",
|
||
" # Decode predictions to human-readable labels\n",
|
||
" # top=5 means we get the top 5 most likely classes\n",
|
||
" decoded = decode_predictions(predictions, top=5)[0]\n",
|
||
" \n",
|
||
" # Convert to simpler format\n",
|
||
" results = [(label, float(confidence)) for (_, label, confidence) in decoded]\n",
|
||
" \n",
|
||
" return results\n",
|
||
"\n",
|
||
"\n",
|
||
"print(\"✅ Helper functions ready!\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Стъпка 4: Тест върху примерни изображения\n",
|
||
"\n",
|
||
"Нека опитаме да класифицираме някои изображения от интернет!\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Sample images to classify\n",
|
||
"# These are from Unsplash (free stock photos)\n",
|
||
"test_images = [\n",
|
||
" {\n",
|
||
" \"url\": \"https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=400\",\n",
|
||
" \"description\": \"A cat\"\n",
|
||
" },\n",
|
||
" {\n",
|
||
" \"url\": \"https://images.unsplash.com/photo-1552053831-71594a27632d?w=400\",\n",
|
||
" \"description\": \"A dog\"\n",
|
||
" },\n",
|
||
" {\n",
|
||
" \"url\": \"https://images.unsplash.com/photo-1511919884226-fd3cad34687c?w=400\",\n",
|
||
" \"description\": \"A car\"\n",
|
||
" },\n",
|
||
"]\n",
|
||
"\n",
|
||
"print(f\"🧪 Testing on {len(test_images)} images...\")\n",
|
||
"print(\"=\" * 70)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Класифицирайте всяко изображение\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i, img_data in enumerate(test_images, 1):\n",
|
||
" print(f\"\\n📸 Image {i}: {img_data['description']}\")\n",
|
||
" print(\"-\" * 70)\n",
|
||
" \n",
|
||
" try:\n",
|
||
" # Load image\n",
|
||
" img = load_image_from_url(img_data['url'])\n",
|
||
" \n",
|
||
" # Display image\n",
|
||
" display(img.resize((200, 200))) # Show smaller version\n",
|
||
" \n",
|
||
" # Classify\n",
|
||
" results = classify_image(img)\n",
|
||
" \n",
|
||
" # Show predictions\n",
|
||
" print(\"\\n🎯 Top 5 Predictions:\")\n",
|
||
" for rank, (label, confidence) in enumerate(results, 1):\n",
|
||
" # Create a visual bar\n",
|
||
" bar_length = int(confidence * 50)\n",
|
||
" bar = \"█\" * bar_length\n",
|
||
" \n",
|
||
" print(f\" {rank}. {label:20s} {confidence*100:5.2f}% {bar}\")\n",
|
||
" \n",
|
||
" except Exception as e:\n",
|
||
" print(f\"❌ Error: {e}\")\n",
|
||
"\n",
|
||
"print(\"\\n\" + \"=\" * 70)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Стъпка 5: Опитайте със свои изображения!\n",
|
||
"\n",
|
||
"Заменете URL адреса по-долу с който и да е URL адрес на изображение, което искате да класифицирате.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Try your own image!\n",
|
||
"# Replace this URL with any image URL\n",
|
||
"custom_image_url = \"https://images.unsplash.com/photo-1472491235688-bdc81a63246e?w=400\" # A flower\n",
|
||
"\n",
|
||
"print(\"🖼️ Classifying your custom image...\")\n",
|
||
"print(\"=\" * 70)\n",
|
||
"\n",
|
||
"try:\n",
|
||
" # Load and show image\n",
|
||
" img = load_image_from_url(custom_image_url)\n",
|
||
" display(img.resize((300, 300)))\n",
|
||
" \n",
|
||
" # Classify\n",
|
||
" results = classify_image(img)\n",
|
||
" \n",
|
||
" # Show results\n",
|
||
" print(\"\\n🎯 Top 5 Predictions:\")\n",
|
||
" print(\"-\" * 70)\n",
|
||
" for rank, (label, confidence) in enumerate(results, 1):\n",
|
||
" bar_length = int(confidence * 50)\n",
|
||
" bar = \"█\" * bar_length\n",
|
||
" print(f\" {rank}. {label:20s} {confidence*100:5.2f}% {bar}\")\n",
|
||
" \n",
|
||
" # Highlight top prediction\n",
|
||
" top_label, top_confidence = results[0]\n",
|
||
" print(\"\\n\" + \"=\" * 70)\n",
|
||
" print(f\"\\n🏆 Best guess: {top_label} ({top_confidence*100:.2f}% confident)\")\n",
|
||
" \n",
|
||
"except Exception as e:\n",
|
||
" print(f\"❌ Error: {e}\")\n",
|
||
" print(\" Make sure the URL points to a valid image!\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 💡 Какво се случи?\n",
|
||
"\n",
|
||
"1. **Заредихме предварително обучен модел** - MobileNetV2 е обучен върху милиони изображения\n",
|
||
"2. **Предварително обработихме изображенията** - Преоразмерихме и форматирахме ги за модела\n",
|
||
"3. **Моделът направи прогнози** - Той изведе вероятности за 1000 категории обекти\n",
|
||
"4. **Декодирахме резултатите** - Превърнахме числата в разбираеми за хората етикети\n",
|
||
"\n",
|
||
"### Разбиране на оценките за увереност\n",
|
||
"\n",
|
||
"- **90-100%**: Много уверен (почти сигурно правилно)\n",
|
||
"- **70-90%**: Уверен (вероятно правилно)\n",
|
||
"- **50-70%**: Донякъде уверен (може би правилно)\n",
|
||
"- **Под 50%**: Не много уверен (несигурно)\n",
|
||
"\n",
|
||
"### Защо прогнозите може да са грешни?\n",
|
||
"\n",
|
||
"- **Необичаен ъгъл или осветление** - Моделът е обучен върху типични снимки\n",
|
||
"- **Множество обекти** - Моделът очаква един основен обект\n",
|
||
"- **Редки обекти** - Моделът познава само 1000 категории\n",
|
||
"- **Ниско качество на изображението** - Размазаните или пикселизирани изображения са по-трудни\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 🚀 Следващи стъпки\n",
|
||
"\n",
|
||
"1. **Опитайте с различни изображения:**\n",
|
||
" - Намерете изображения на [Unsplash](https://unsplash.com)\n",
|
||
" - Десен бутон → „Копирай адреса на изображението“, за да получите URL\n",
|
||
"\n",
|
||
"2. **Експериментирайте:**\n",
|
||
" - Какво се случва с абстрактно изкуство?\n",
|
||
" - Може ли да разпознава обекти от различни ъгли?\n",
|
||
" - Как се справя с множество обекти?\n",
|
||
"\n",
|
||
"3. **Научете повече:**\n",
|
||
" - Разгледайте [уроците за компютърно зрение](../lessons/4-ComputerVision/README.md)\n",
|
||
" - Научете как да обучите собствен класификатор на изображения\n",
|
||
" - Разберете как работят CNNs (Конволюционни невронни мрежи)\n",
|
||
"\n",
|
||
"---\n",
|
||
"\n",
|
||
"## 🎉 Поздравления!\n",
|
||
"\n",
|
||
"Току-що създадохте класификатор на изображения, използвайки съвременна невронна мрежа!\n",
|
||
"\n",
|
||
"Същата техника се използва за:\n",
|
||
"- Google Photos (организиране на вашите снимки)\n",
|
||
"- Автономни автомобили (разпознаване на обекти)\n",
|
||
"- Медицинска диагностика (анализ на рентгенови снимки)\n",
|
||
"- Контрол на качеството (откриване на дефекти)\n",
|
||
"\n",
|
||
"Продължавайте да изследвате и учите! 🚀\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n---\n\n**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.8.0"
|
||
},
|
||
"coopTranslator": {
|
||
"original_hash": "1d472141d9df46b751542b3c29f88677",
|
||
"translation_date": "2025-10-03T11:53:21+00:00",
|
||
"source_file": "examples/03-image-classifier.ipynb",
|
||
"language_code": "bg"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
} |