397 lines
15 KiB
Plaintext
397 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",
|
||
"\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Овај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције [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:46+00:00",
|
||
"source_file": "examples/03-image-classifier.ipynb",
|
||
"language_code": "sr"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
} |