{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.10.12"
  },
  "colab": {
   "provenance": [],
   "gpuType": "T4"
  },
  "accelerator": "GPU"
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UztshO9lgL_a"
   },
   "source": "# 🍅 Topraksız Domates – Çoklu Kamera Böcek & Parazit Tespit Sistemi\n## Google Colab + RTSP + YOLOv8/YOLO11 + TensorRT (Opsiyonel)\n\n**Özellikler:**\n- Birden fazla RTSP kamera desteği (merkezi yönetim)\n- Ultralytics multi-stream inference\n- TensorRT ile hızlandırma desteği\n- Tespit loglama, görüntü kaydetme ve uyarı sistemi\n- Colab uyumlu görüntü gösterimi\n- Eğitim ve prototip geliştirme için hazır yapı\n\n**Kullanım Öncesi:**\n1. Runtime → Change runtime type → **GPU** (T4 önerilir) seçin\n2. Aşağıdaki **Ayarlar** hücresinde kamera listesini ve model yolunu güncelleyin\n3. Kendi eğittiğiniz modeli yükleyebilirsiniz\n\n---",
   "id": "UztshO9lgL_a"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Uj5Hj03DgL_g"
   },
   "source": "## 1. Gerekli Kütüphanelerin Kurulumu",
   "id": "Uj5Hj03DgL_g"
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "-YlAq4UwgL_h",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786966530479,
     "user_tz": -180,
     "elapsed": 11241,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "c1ffeb67-a95d-4bc7-a496-de9cf6c5b624"
   },
   "source": "!pip install -q ultralytics opencv-python-headless pillow\n\n# TensorRT kullanmak isterseniz (opsiyonel, Colab T4'te çalışabilir)\n# !pip install -q tensorrt\n\nprint(\"✅ Kurulum tamamlandı.\")",
   "execution_count": 1,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m45.5/45.5 kB\u001b[0m \u001b[31m3.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m36.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m63.9/63.9 kB\u001b[0m \u001b[31m5.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25h✅ Kurulum tamamlandı.\n"
     ]
    }
   ],
   "id": "-YlAq4UwgL_h"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "l3Owkx-3gL_j"
   },
   "source": "## 2. Kütüphaneleri İçe Aktarma ve Merkezi Ayarlar",
   "id": "l3Owkx-3gL_j"
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "8ZapHmGFgL_k",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1786966538780,
     "user_tz": -180,
     "elapsed": 8151,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "09e20f68-70d5-413c-d939-0311f3b63ce2"
   },
   "source": "import cv2\nimport time\nimport os\nimport json\nfrom datetime import datetime\nfrom pathlib import Path\nfrom ultralytics import YOLO\nfrom IPython.display import display, clear_output\nfrom PIL import Image as PILImage\nimport numpy as np\n\n# ====================== MERKEZİ AYARLAR ======================\n\n# Kamera listesi (RTSP adresleri)\n# Format: \"kamera_adi\": \"rtsp_url\"\nCAMERAS = {\n    \"sera_bolum_1\": \"rtsp://kullanici:sifre@192.168.1.101:554/stream1\",\n    \"sera_bolum_2\": \"rtsp://kullanici:sifre@192.168.1.102:554/stream1\",\n    \"sticky_trap_1\": \"rtsp://kullanici:sifre@192.168.1.103:554/stream1\",\n    # \"sera_bolum_3\": \"rtsp://...\",\n    # İstediğiniz kadar kamera ekleyebilirsiniz\n}\n\n# Model ayarları\nMODEL_PATH = \"yolov8n.pt\"          # Kendi modeliniz: \"best.pt\" veya \"best.engine\" (TensorRT)\nUSE_TENSORRT = False               # True yaparsanız .engine dosyası bekler\nCONF_THRESHOLD = 0.45\nIMGSZ = 640\nIOU_THRESHOLD = 0.5\n\n# Çalışma ayarları\nSAVE_DETECTIONS = True\nLOG_FILE = \"pest_log.jsonl\"        # JSON Lines formatı (kolay parse edilir)\nDISPLAY_EVERY_N_FRAMES = 5         # Colab performans için\nMAX_RUNTIME_MINUTES = 45           # Güvenlik limiti\nVID_STRIDE = 2                     # Her N karede bir işle (hız için)\n\n# Klasörler\nos.makedirs(\"detections\", exist_ok=True)\nos.makedirs(\"logs\", exist_ok=True)\n\nprint(\"✅ Ayarlar yüklendi.\")\nprint(f\"📹 Kamera sayısı: {len(CAMERAS)}\")\nfor name, url in CAMERAS.items():\n    print(f\"   - {name}\")",
   "execution_count": 2,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Creating new Ultralytics Settings v0.0.7 file ✅ \n",
      "View Ultralytics Settings with 'yolo settings' or at '/root/.config/Ultralytics/settings.json'\n",
      "Update Settings with 'yolo settings key=value', i.e. 'yolo settings runs_dir=path/to/dir'. For help see https://docs.ultralytics.com/quickstart/#ultralytics-settings.\n",
      "✅ Ayarlar yüklendi.\n",
      "📹 Kamera sayısı: 3\n",
      "   - sera_bolum_1\n",
      "   - sera_bolum_2\n",
      "   - sticky_trap_1\n"
     ]
    }
   ],
   "id": "8ZapHmGFgL_k"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "eNCT6RPngL_l"
   },
   "source": "## 3. (Opsiyonel) Kendi Modelinizi Yükleyin",
   "id": "eNCT6RPngL_l"
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 52
    },
    "id": "_xN3uqcjgL_m",
    "outputId": "2769fccb-f06d-48c7-b173-b5bdca3c89e0"
   },
   "source": "from google.colab import files\n\nprint(\"Model dosyanızı seçin (.pt veya .engine)...\")\nuploaded = files.upload()\n\nif uploaded:\n    MODEL_PATH = list(uploaded.keys())[0]\n    print(f\"✅ Model yüklendi: {MODEL_PATH}\")\n    if MODEL_PATH.endswith(\".engine\"):\n        USE_TENSORRT = True\n        print(\"⚡ TensorRT engine tespit edildi.\")\nelse:\n    print(\"Dosya yüklenmedi. Varsayılan model kullanılacak.\")",
   "execution_count": null,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Model dosyanızı seçin (.pt veya .engine)...\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "\n",
       "     <input type=\"file\" id=\"files-8df2fce3-9809-42f3-8651-781c516fdb17\" name=\"files[]\" multiple disabled\n",
       "        style=\"border:none\" />\n",
       "     <output id=\"result-8df2fce3-9809-42f3-8651-781c516fdb17\">\n",
       "      Upload widget is only available when the cell has been executed in the\n",
       "      current browser session. Please rerun this cell to enable.\n",
       "      </output>\n",
       "      <script>// Copyright 2017 Google LLC\n",
       "//\n",
       "// Licensed under the Apache License, Version 2.0 (the \"License\");\n",
       "// you may not use this file except in compliance with the License.\n",
       "// You may obtain a copy of the License at\n",
       "//\n",
       "//      http://www.apache.org/licenses/LICENSE-2.0\n",
       "//\n",
       "// Unless required by applicable law or agreed to in writing, software\n",
       "// distributed under the License is distributed on an \"AS IS\" BASIS,\n",
       "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
       "// See the License for the specific language governing permissions and\n",
       "// limitations under the License.\n",
       "\n",
       "/**\n",
       " * @fileoverview Helpers for google.colab Python module.\n",
       " */\n",
       "(function(scope) {\n",
       "function span(text, styleAttributes = {}) {\n",
       "  const element = document.createElement('span');\n",
       "  element.textContent = text;\n",
       "  for (const key of Object.keys(styleAttributes)) {\n",
       "    element.style[key] = styleAttributes[key];\n",
       "  }\n",
       "  return element;\n",
       "}\n",
       "\n",
       "// Max number of bytes which will be uploaded at a time.\n",
       "const MAX_PAYLOAD_SIZE = 100 * 1024;\n",
       "\n",
       "function _uploadFiles(inputId, outputId) {\n",
       "  const steps = uploadFilesStep(inputId, outputId);\n",
       "  const outputElement = document.getElementById(outputId);\n",
       "  // Cache steps on the outputElement to make it available for the next call\n",
       "  // to uploadFilesContinue from Python.\n",
       "  outputElement.steps = steps;\n",
       "\n",
       "  return _uploadFilesContinue(outputId);\n",
       "}\n",
       "\n",
       "// This is roughly an async generator (not supported in the browser yet),\n",
       "// where there are multiple asynchronous steps and the Python side is going\n",
       "// to poll for completion of each step.\n",
       "// This uses a Promise to block the python side on completion of each step,\n",
       "// then passes the result of the previous step as the input to the next step.\n",
       "function _uploadFilesContinue(outputId) {\n",
       "  const outputElement = document.getElementById(outputId);\n",
       "  const steps = outputElement.steps;\n",
       "\n",
       "  const next = steps.next(outputElement.lastPromiseValue);\n",
       "  return Promise.resolve(next.value.promise).then((value) => {\n",
       "    // Cache the last promise value to make it available to the next\n",
       "    // step of the generator.\n",
       "    outputElement.lastPromiseValue = value;\n",
       "    return next.value.response;\n",
       "  });\n",
       "}\n",
       "\n",
       "/**\n",
       " * Generator function which is called between each async step of the upload\n",
       " * process.\n",
       " * @param {string} inputId Element ID of the input file picker element.\n",
       " * @param {string} outputId Element ID of the output display.\n",
       " * @return {!Iterable<!Object>} Iterable of next steps.\n",
       " */\n",
       "function* uploadFilesStep(inputId, outputId) {\n",
       "  const inputElement = document.getElementById(inputId);\n",
       "  inputElement.disabled = false;\n",
       "\n",
       "  const outputElement = document.getElementById(outputId);\n",
       "  outputElement.innerHTML = '';\n",
       "\n",
       "  const pickedPromise = new Promise((resolve) => {\n",
       "    inputElement.addEventListener('change', (e) => {\n",
       "      resolve(e.target.files);\n",
       "    });\n",
       "  });\n",
       "\n",
       "  const cancel = document.createElement('button');\n",
       "  inputElement.parentElement.appendChild(cancel);\n",
       "  cancel.textContent = 'Cancel upload';\n",
       "  const cancelPromise = new Promise((resolve) => {\n",
       "    cancel.onclick = () => {\n",
       "      resolve(null);\n",
       "    };\n",
       "  });\n",
       "\n",
       "  // Wait for the user to pick the files.\n",
       "  const files = yield {\n",
       "    promise: Promise.race([pickedPromise, cancelPromise]),\n",
       "    response: {\n",
       "      action: 'starting',\n",
       "    }\n",
       "  };\n",
       "\n",
       "  cancel.remove();\n",
       "\n",
       "  // Disable the input element since further picks are not allowed.\n",
       "  inputElement.disabled = true;\n",
       "\n",
       "  if (!files) {\n",
       "    return {\n",
       "      response: {\n",
       "        action: 'complete',\n",
       "      }\n",
       "    };\n",
       "  }\n",
       "\n",
       "  for (const file of files) {\n",
       "    const li = document.createElement('li');\n",
       "    li.append(span(file.name, {fontWeight: 'bold'}));\n",
       "    li.append(span(\n",
       "        `(${file.type || 'n/a'}) - ${file.size} bytes, ` +\n",
       "        `last modified: ${\n",
       "            file.lastModifiedDate ? file.lastModifiedDate.toLocaleDateString() :\n",
       "                                    'n/a'} - `));\n",
       "    const percent = span('0% done');\n",
       "    li.appendChild(percent);\n",
       "\n",
       "    outputElement.appendChild(li);\n",
       "\n",
       "    const fileDataPromise = new Promise((resolve) => {\n",
       "      const reader = new FileReader();\n",
       "      reader.onload = (e) => {\n",
       "        resolve(e.target.result);\n",
       "      };\n",
       "      reader.readAsArrayBuffer(file);\n",
       "    });\n",
       "    // Wait for the data to be ready.\n",
       "    let fileData = yield {\n",
       "      promise: fileDataPromise,\n",
       "      response: {\n",
       "        action: 'continue',\n",
       "      }\n",
       "    };\n",
       "\n",
       "    // Use a chunked sending to avoid message size limits. See b/62115660.\n",
       "    let position = 0;\n",
       "    do {\n",
       "      const length = Math.min(fileData.byteLength - position, MAX_PAYLOAD_SIZE);\n",
       "      const chunk = new Uint8Array(fileData, position, length);\n",
       "      position += length;\n",
       "\n",
       "      const base64 = btoa(String.fromCharCode.apply(null, chunk));\n",
       "      yield {\n",
       "        response: {\n",
       "          action: 'append',\n",
       "          file: file.name,\n",
       "          data: base64,\n",
       "        },\n",
       "      };\n",
       "\n",
       "      let percentDone = fileData.byteLength === 0 ?\n",
       "          100 :\n",
       "          Math.round((position / fileData.byteLength) * 100);\n",
       "      percent.textContent = `${percentDone}% done`;\n",
       "\n",
       "    } while (position < fileData.byteLength);\n",
       "  }\n",
       "\n",
       "  // All done.\n",
       "  yield {\n",
       "    response: {\n",
       "      action: 'complete',\n",
       "    }\n",
       "  };\n",
       "}\n",
       "\n",
       "scope.google = scope.google || {};\n",
       "scope.google.colab = scope.google.colab || {};\n",
       "scope.google.colab._files = {\n",
       "  _uploadFiles,\n",
       "  _uploadFilesContinue,\n",
       "};\n",
       "})(self);\n",
       "</script> "
      ]
     },
     "metadata": {}
    }
   ],
   "id": "_xN3uqcjgL_m"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "KxRaYLpRgL_n"
   },
   "source": "## 4. Model Yükleme ve TensorRT Export (Opsiyonel)",
   "id": "KxRaYLpRgL_n"
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "lM6aaOJ3gL_n"
   },
   "source": "print(\"Model yükleniyor...\")\nmodel = YOLO(MODEL_PATH)\nprint(f\"✅ Model yüklendi: {MODEL_PATH}\")\nprint(f\"Sınıflar: {model.names}\")\n\n# TensorRT export yapmak isterseniz (sadece .pt dosyası için)\n# Dikkat: Colab T4'te export 5-15 dakika sürebilir ve engine cihaza özeldir.\nif False:  # True yaparak aktif edin\n    print(\"\\n⚡ TensorRT export başlıyor (FP16)...\")\n    model.export(\n        format=\"engine\",\n        imgsz=IMGSZ,\n        half=True,          # FP16\n        dynamic=False,\n        workspace=4,\n        verbose=True\n    )\n    print(\"✅ TensorRT engine oluşturuldu. MODEL_PATH'i .engine olarak güncelleyin.\")",
   "execution_count": null,
   "outputs": [],
   "id": "lM6aaOJ3gL_n"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "D0hcOkOwgL_o"
   },
   "source": "## 5. Yardımcı Fonksiyonlar (Log, Kayıt, Durum)",
   "id": "D0hcOkOwgL_o"
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "eKCDbFgFgL_o"
   },
   "source": "def log_detection(camera_name, results, timestamp, frame=None):\n    \"\"\"Tespit edilen zararlıları JSONL formatında loglar\"\"\"\n    detections = []\n    for r in results:\n        if r.boxes is None:\n            continue\n        for box in r.boxes:\n            conf = float(box.conf[0])\n            if conf >= CONF_THRESHOLD:\n                cls_id = int(box.cls[0])\n                name = model.names[cls_id]\n                detections.append({\n                    \"class\": name,\n                    \"confidence\": round(conf, 3),\n                    \"bbox\": box.xyxy[0].tolist()\n                })\n\n    if detections:\n        log_entry = {\n            \"timestamp\": timestamp,\n            \"camera\": camera_name,\n            \"detections\": detections,\n            \"count\": len(detections)\n        }\n        with open(LOG_FILE, \"a\", encoding=\"utf-8\") as f:\n            f.write(json.dumps(log_entry, ensure_ascii=False) + \"\\n\")\n\n        if SAVE_DETECTIONS and frame is not None:\n            safe_name = camera_name.replace(\" \", \"_\")\n            filename = f\"detections/{safe_name}_{timestamp.replace(':', '-').replace(' ', '_')}.jpg\"\n            cv2.imwrite(filename, frame)\n\n        print(f\"⚠️  [{camera_name}] {timestamp} → {len(detections)} tespit: {[d['class'] for d in detections]}\")\n        return True\n    return False\n\n\ndef create_streams_file(cameras_dict, filename=\"cameras.streams\"):\n    \"\"\"Ultralytics multi-stream için .streams dosyası oluşturur\"\"\"\n    with open(filename, \"w\") as f:\n        for url in cameras_dict.values():\n            f.write(url + \"\\n\")\n    print(f\"✅ {filename} oluşturuldu ({len(cameras_dict)} kamera)\")\n    return filename\n\n\ndef print_status(camera_stats, start_time, frame_count):\n    \"\"\"Merkezi durum özeti\"\"\"\n    elapsed = time.time() - start_time\n    print(\"\\n\" + \"=\"*60)\n    print(f\"📊 MERKEZİ DURUM | Geçen süre: {elapsed/60:.1f} dk | Toplam kare: {frame_count}\")\n    for cam, stats in camera_stats.items():\n        print(f\"   {cam}: {stats['detections']} tespit | Son: {stats['last_detection'] or 'Yok'}\")\n    print(\"=\"*60)\n\nprint(\"✅ Yardımcı fonksiyonlar hazır.\")",
   "execution_count": null,
   "outputs": [],
   "id": "eKCDbFgFgL_o"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6sHyjRVkgL_p"
   },
   "source": "## 6. Çoklu Kamera – Merkezi Tespit Motoru\n\nBu hücre ana çalışma motorudur.  \nUltralytics multi-stream kullanarak tüm kameraları paralel işler.\n\n**Durdurmak için:** Runtime → Interrupt execution",
   "id": "6sHyjRVkgL_p"
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "YQ4weGS8gL_p"
   },
   "source": "# .streams dosyası oluştur\nstreams_file = create_streams_file(CAMERAS)\ncamera_names = list(CAMERAS.keys())\n\n# İstatistikler\ncamera_stats = {name: {\"detections\": 0, \"last_detection\": None} for name in camera_names}\n\nstart_time = time.time()\nframe_count = 0\nlast_status_time = time.time()\n\nprint(\"\\n🚀 Çoklu kamera analiz motoru başlatılıyor...\")\nprint(f\"📹 Kameralar: {', '.join(camera_names)}\")\nprint(\"Durdurmak için Runtime → Interrupt execution kullanın.\\n\")\n\ntry:\n    # Multi-stream inference (Ultralytics resmi yöntem)\n    results_generator = model.predict(\n        source=streams_file,\n        stream=True,\n        conf=CONF_THRESHOLD,\n        iou=IOU_THRESHOLD,\n        imgsz=IMGSZ,\n        vid_stride=VID_STRIDE,\n        verbose=False,\n        device=0\n    )\n\n    for results in results_generator:\n        # Maksimum süre kontrolü\n        if (time.time() - start_time) > MAX_RUNTIME_MINUTES * 60:\n            print(\"⏱️  Maksimum çalışma süresine ulaşıldı.\")\n            break\n\n        frame_count += 1\n        timestamp = datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n\n        # results bir liste olabilir (multi-stream) veya tek Results\n        if not isinstance(results, list):\n            results = [results]\n\n        for idx, r in enumerate(results):\n            if idx >= len(camera_names):\n                break\n            cam_name = camera_names[idx]\n\n            # Orijinal kareyi al (varsa)\n            frame = r.orig_img if hasattr(r, \"orig_img\") else None\n\n            # Log ve kayıt\n            has_det = log_detection(cam_name, [r], timestamp, frame)\n            if has_det:\n                camera_stats[cam_name][\"detections\"] += 1\n                camera_stats[cam_name][\"last_detection\"] = timestamp\n\n            # Görüntü göster (sadece belirli aralıklarla + tespit olduğunda)\n            if (frame_count % DISPLAY_EVERY_N_FRAMES == 0 or has_det) and frame is not None:\n                clear_output(wait=True)\n                annotated = r.plot()\n                display_frame = cv2.resize(annotated, (800, 450))\n                display_frame = cv2.cvtColor(display_frame, cv2.COLOR_BGR2RGB)\n                pil_img = PILImage.fromarray(display_frame)\n                display(pil_img)\n                print(f\"Kamera: {cam_name} | Kare: {frame_count} | Zaman: {timestamp}\")\n\n        # Periyodik durum özeti (her 30 saniyede bir)\n        if time.time() - last_status_time > 30:\n            print_status(camera_stats, start_time, frame_count)\n            last_status_time = time.time()\n\nexcept KeyboardInterrupt:\n    print(\"\\n🛑 Kullanıcı tarafından durduruldu.\")\nexcept Exception as e:\n    print(f\"\\n❌ Hata oluştu: {e}\")\n    import traceback\n    traceback.print_exc()\nfinally:\n    print(\"\\n\" + \"=\"*60)\n    print(\"🏁 Analiz sonlandırıldı.\")\n    print_status(camera_stats, start_time, frame_count)\n    print(f\"📄 Log dosyası: {LOG_FILE}\")\n    print(f\"🖼️  Tespit görüntüleri: detections/ klasörü\")\n    print(\"=\"*60)",
   "execution_count": null,
   "outputs": [],
   "id": "YQ4weGS8gL_p"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qEB7_f3fgL_q"
   },
   "source": "## 7. Alternatif: Thread Tabanlı Çoklu Kamera (Daha Esnek Kontrol)\n\nYukarıdaki multi-stream yöntemi yeterli gelmezse veya her kamerayı ayrı thread ile yönetmek isterseniz bu hücreyi kullanabilirsiniz.",
   "id": "qEB7_f3fgL_q"
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "WgMrLl-tgL_r"
   },
   "source": "import threading\nfrom queue import Queue\n\ndef process_camera(cam_name, rtsp_url, model, stop_event):\n    \"\"\"Tek bir kamerayı ayrı thread'de işler\"\"\"\n    print(f\"[{cam_name}] Bağlanıyor...\")\n    cap = cv2.VideoCapture(rtsp_url)\n    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)\n\n    if not cap.isOpened():\n        print(f\"[{cam_name}] ❌ Bağlantı başarısız\")\n        return\n\n    print(f\"[{cam_name}] ✅ Bağlandı\")\n    local_frame_count = 0\n\n    while not stop_event.is_set():\n        ret, frame = cap.read()\n        if not ret:\n            print(f\"[{cam_name}] Kare alınamadı, yeniden deneniyor...\")\n            time.sleep(2)\n            cap.release()\n            cap = cv2.VideoCapture(rtsp_url)\n            continue\n\n        local_frame_count += 1\n        if local_frame_count % VID_STRIDE != 0:\n            continue\n\n        results = model.predict(frame, conf=CONF_THRESHOLD, imgsz=IMGSZ, verbose=False, device=0)\n        timestamp = datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n        log_detection(cam_name, results, timestamp, frame)\n\n        time.sleep(0.01)  # CPU yükünü azalt\n\n    cap.release()\n    print(f\"[{cam_name}] Thread sonlandırıldı.\")\n\n\n# Thread tabanlı çalıştırmak için aşağıdaki kodu aktif edin (yorum satırlarını kaldırın)\n\"\"\"\nstop_event = threading.Event()\nthreads = []\n\nfor name, url in CAMERAS.items():\n    t = threading.Thread(target=process_camera, args=(name, url, model, stop_event), daemon=True)\n    t.start()\n    threads.append(t)\n\nprint(f\"{len(threads)} kamera thread'i başlatıldı. Durdurmak için Interrupt kullanın.\")\n\ntry:\n    while True:\n        time.sleep(5)\n        # İsterseniz burada durum yazdırabilirsiniz\nexcept KeyboardInterrupt:\n    print(\"Durduruluyor...\")\n    stop_event.set()\n    for t in threads:\n        t.join(timeout=3)\n    print(\"Tüm thread'ler sonlandırıldı.\")\n\"\"\"\n\nprint(\"Thread tabanlı kod hazır (yorum satırlarını kaldırarak aktif edebilirsiniz).\")",
   "execution_count": null,
   "outputs": [],
   "id": "WgMrLl-tgL_r"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YYZ5PcuHgL_s"
   },
   "source": "## 8. Sonuçları İndirme ve Analiz",
   "id": "YYZ5PcuHgL_s"
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "BDhCIQgWgL_s"
   },
   "source": "from google.colab import files\nimport shutil\n\n# Tespit görüntülerini indir\nif os.path.exists(\"detections\") and len(os.listdir(\"detections\")) > 0:\n    shutil.make_archive(\"detections\", \"zip\", \"detections\")\n    files.download(\"detections.zip\")\n    print(\"✅ detections.zip indirildi.\")\nelse:\n    print(\"Henüz kaydedilmiş tespit görüntüsü yok.\")\n\n# Log dosyasını indir\nif os.path.exists(LOG_FILE):\n    files.download(LOG_FILE)\n    print(f\"✅ {LOG_FILE} indirildi.\")\nelse:\n    print(\"Log dosyası henüz oluşturulmadı.\")",
   "execution_count": null,
   "outputs": [],
   "id": "BDhCIQgWgL_s"
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "JT_yo5pkgL_t"
   },
   "source": "# Log dosyasını özetle (basit analiz)\nif os.path.exists(LOG_FILE):\n    from collections import Counter\n    total = 0\n    class_counter = Counter()\n    camera_counter = Counter()\n\n    with open(LOG_FILE, \"r\", encoding=\"utf-8\") as f:\n        for line in f:\n            entry = json.loads(line)\n            total += entry[\"count\"]\n            camera_counter[entry[\"camera\"]] += entry[\"count\"]\n            for d in entry[\"detections\"]:\n                class_counter[d[\"class\"]] += 1\n\n    print(\"📊 Tespit Özeti\")\n    print(f\"Toplam tespit: {total}\")\n    print(\"\\nKameraya göre:\")\n    for cam, cnt in camera_counter.most_common():\n        print(f\"  {cam}: {cnt}\")\n    print(\"\\nSınıfa göre:\")\n    for cls, cnt in class_counter.most_common():\n        print(f\"  {cls}: {cnt}\")\nelse:\n    print(\"Log dosyası bulunamadı.\")",
   "execution_count": null,
   "outputs": [],
   "id": "JT_yo5pkgL_t"
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aVT-TbX6gL_u"
   },
   "source": "## 9. Kullanım Notları ve İpuçları\n\n### Kamera Ekleme / Çıkarma\n`CAMERAS` sözlüğüne yeni satır ekleyerek istediğiniz kadar kamera tanımlayabilirsiniz.\n\n### TensorRT Kullanımı\n1. `.pt` modelinizi yükleyin\n2. 4. hücredeki `if False:` kısmını `if True:` yapın ve export edin\n3. Oluşan `.engine` dosyasını MODEL_PATH olarak kullanın\n\n### Performans İpuçları\n- `VID_STRIDE = 2` veya `3` → her kareyi işlemeyerek hız artar\n- `IMGSZ = 640` yerine `416` deneyebilirsiniz (daha hızlı, biraz daha az doğru)\n- TensorRT FP16 ile 2-3× hız kazanabilirsiniz\n- Colab oturumu uzun sürerse kesilebilir → `MAX_RUNTIME_MINUTES` ile sınır koyun\n\n### Gerçek Ortama Geçiş\n- Bu notebook prototip / eğitim içindir\n- Production için: Jetson + DeepStream veya kendi thread/process mimariniz önerilir\n- Logları veritabanına (SQLite/PostgreSQL) yazabilirsiniz\n- Telegram / e-posta uyarı ekleyebilirsiniz\n\n---\n**Hazırlayan:** Grok (xAI)  \nTopraksız tarım domates böcek/parazit çoklu kamera tespit sistemi – Colab sürümü\n\nSorularınız veya ek özellik istekleriniz için notebook’u güncelleyebilirim.",
   "id": "aVT-TbX6gL_u"
  }
 ]
}