Browse Source

初使提交

master
WangGuangYuan 1 month ago
commit
e77f1d727c
43 changed files with 2172 additions and 0 deletions
  1. +23
    -0
      Dockerfile
  2. +116
    -0
      README_API.md
  3. +168
    -0
      app/README_API.md
  4. BIN
      app/TioTech.mp4
  5. +851
    -0
      app/main.py
  6. BIN
      app/model/Floating/best.pt
  7. BIN
      app/model/Floating/train4/BoxF1_curve.png
  8. BIN
      app/model/Floating/train4/BoxPR_curve.png
  9. BIN
      app/model/Floating/train4/BoxP_curve.png
  10. BIN
      app/model/Floating/train4/BoxR_curve.png
  11. +106
    -0
      app/model/Floating/train4/args.yaml
  12. BIN
      app/model/Floating/train4/confusion_matrix.png
  13. BIN
      app/model/Floating/train4/confusion_matrix_normalized.png
  14. BIN
      app/model/Floating/train4/labels.jpg
  15. +287
    -0
      app/model/Floating/train4/results.csv
  16. BIN
      app/model/Floating/train4/results.png
  17. BIN
      app/model/Floating/train4/train_batch0.jpg
  18. BIN
      app/model/Floating/train4/train_batch1.jpg
  19. BIN
      app/model/Floating/train4/train_batch2.jpg
  20. BIN
      app/model/Floating/train4/val_batch0_labels.jpg
  21. BIN
      app/model/Floating/train4/val_batch0_pred.jpg
  22. BIN
      app/model/Floating/train4/val_batch1_labels.jpg
  23. BIN
      app/model/Floating/train4/val_batch1_pred.jpg
  24. BIN
      app/model/Floating/train4/val_batch2_labels.jpg
  25. BIN
      app/model/Floating/train4/val_batch2_pred.jpg
  26. BIN
      app/model/Floating/train4/weights/best.pt
  27. BIN
      app/model/Floating/train4/weights/last.pt
  28. BIN
      app/model/gate_model/best.pt
  29. BIN
      app/model/shore_garbage_model/best.pt
  30. BIN
      app/model/water_gauge_model/best.pt
  31. +51
    -0
      app/model_registry.py
  32. +285
    -0
      app/tasks.py
  33. +96
    -0
      app/tasks_scene_01.py
  34. BIN
      app/test.jpg
  35. BIN
      app/test1.mp4
  36. BIN
      app/test2.mp4
  37. BIN
      app/yolov8n.pt
  38. +39
    -0
      docker-compose.yml
  39. +32
    -0
      docker-compose.yml.v1.cpu
  40. +47
    -0
      docker-compose.yml.v1.gpu
  41. +61
    -0
      readme.txt
  42. +10
    -0
      requirements.txt
  43. BIN
      test.jpg

+ 23
- 0
Dockerfile View File

@ -0,0 +1,23 @@
# 使用 Python 3.9 轻量版
FROM python:3.9-slim
# 安装系统级依赖 (OpenCV 和 YOLO 运行必须)
RUN apt-get update && apt-get install -y \
libgl1 \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 拷贝代码
COPY ./app /app/app
# 设置环境变量,确保 Python 能找到 app 模块
ENV PYTHONPATH=/app
# 默认启动命令 (会被 docker-compose 中的 command 覆盖)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "18005"]

+ 116
- 0
README_API.md View File

@ -0,0 +1,116 @@
# 水库智能算法云服务接口文档
## 服务概述
基于 FastAPI 构建的水库智能算法云服务,提供视频流分析和图像识别功能,支持多种 YOLO 模型场景检测。
**服务地址**: `http://33.36.139.134.254:18005`
---
## 接口列表
### 1. 视频流异步分析接口
**接口路径**: `POST /v1/task/stream`
**描述**: 将 RTSP 视频流任务派发给 Celery worker 异步处理
**请求体**:
```json
{
"source_url": "rtsp://摄像头地址",
"webhook_url": "回调地址",
"scene_type": "floating_trash | fishing | swimming",
"roi": [[x1, y1], [x2, y2], ...]
}
```
**参数说明**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| source_url | string | 是 | 摄像头 RTSP 流地址 |
| webhook_url | string | 是 | 业务系统回调地址 |
| scene_type | string | 是 | 场景类型 |
| roi | array | 否 | 电子围栏坐标点集 |
**响应示例**:
```json
{
"code": 200,
"msg": "任务已下发至计算集群",
"task_type": "floating_trash"
}
```
---
### 2. 指定模型图像预测接口
**接口路径**: `POST /{model_type}/predict/image`
**描述**: 使用指定模型对上传的图片进行目标检测
**路径参数**:
| 参数 | 说明 |
|------|------|
| model_type | 模型类型 |
**支持的模型类型**:
| model_type | 模型文件 | 说明 |
|------------|----------|------|
| default | yolov8n.pt | 默认预训练模型 |
| bati | model/Bati/best.pt | 坝体检测模型 |
| buildings | model/buildings/best.pt | 建筑物检测模型 |
| disaster | model/disaster/best.pt | 灾害检测模型 |
| fire-smoke | model/fire-smoke/best.pt | 烟火检测模型 |
| Floating | model/Floating/best.pt | 漂浮物检测模型 |
| ship | model/ship/best.pt | 船只检测模型 |
**请求表单**:
- `file`: 图片文件 (支持 jpg, png 等格式)
**响应示例**:
```json
{
"results": [
{
"boxes": {
"xyxy": [[x1, y1, x2, y2]],
"conf": [0.95],
"cls": [0]
},
"names": { "0": "目标类别" }
}
]
}
```
---
### 3. 默认模型图像预测接口
**接口路径**: `POST /v1/predict/image`
**描述**: 使用默认 YOLOv8n 模型对图片进行预测
**请求表单**:
- `file`: 图片文件
**响应示例**: 同接口2
---
**启动参数**:
- Host: `0.0.0.0`
- Port: `8000`
---
## 错误处理
| HTTP 状态码 | 说明 |
|-------------|------|
| 400 | 请求参数错误 |
| 500 | 服务器内部错误 |

+ 168
- 0
app/README_API.md View File

@ -0,0 +1,168 @@
# 延寿水库智能识别服务接口说明
## 1. 项目概述
本服务基于 FastAPI 和 YOLO 模型,为延寿水库项目提供按场景划分的智能识别能力。当前支持两类能力:
- 图像识别:上传单张图片并返回识别结果。
- 视频流识别:提交 RTSP 或本地视频流地址,系统异步分析并通过回调地址推送结果。
服务中的 `model_type` 对应具体业务场景,每个场景绑定一个独立模型文件。
## 2. 支持场景
- `floating`:水面漂浮物识别。用于识别水面漂浮垃圾、杂物等目标。
- `gate`:闸口场景识别。用于识别闸口、闸门区域中的目标和异常情况。
- `shore_garbage`:岸边垃圾识别。用于识别岸线附近堆积或散落的垃圾目标。
- `water_gauge`:水尺识别。用于识别水尺、水位尺等目标,服务于水位监测场景。
## 3. 接口列表
- `POST /{model_type}/predict/image`:按场景执行图片识别。
- `POST /{model_type}/predict/stream`:按场景提交视频流识别任务。
- `POST /v1/task/stream`:兼容旧版视频流接口,通过 `scene_type` 指定场景。
- `POST /v1/predict/image`:旧版图片接口说明入口,当前会返回引导信息,请改用新接口。
## 4. 图片识别接口
### 4.1 请求地址
`POST /{model_type}/predict/image`
### 4.2 路径参数
- `model_type`:场景类型,可选值为 `floating`、`gate`、`shore_garbage`、`water_gauge`。
### 4.3 请求方式
`multipart/form-data`
### 4.4 请求参数
- `file`:待识别图片文件,支持常见图片格式。
### 4.5 调用示例
```bash
curl -X POST "http://localhost:8000/floating/predict/image" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "file=@test.jpg;type=image/jpeg"
```
### 4.6 返回示例
```json
{
"results": [
{
"name": "floating_object",
"class": 0,
"confidence": 0.93,
"box": {
"x1": 102.4,
"y1": 55.2,
"x2": 260.8,
"y2": 188.6
}
}
]
}
```
## 5. 视频流识别接口
### 5.1 新版接口
`POST /{model_type}/predict/stream`
### 5.2 兼容接口
`POST /v1/task/stream`
兼容接口中,场景通过请求体的 `scene_type` 指定,其可选值与 `model_type` 一致。
### 5.3 请求体参数
- `source_url`:视频流地址,支持 `rtsp://...`、本地视频文件路径等 OpenCV 可读取地址。
- `webhook_url`:识别结果回调地址,必须是服务端可访问的 `HTTP/HTTPS POST` 接口。
- `roi`:可选电子围栏,多边形坐标数组,格式为 `[[x1, y1], [x2, y2], ...]`。不传时默认检测整幅画面。
### 5.4 请求体示例
```json
{
"source_url": "rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream",
"webhook_url": "https://example.com/api/reservoir/webhook",
"roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]]
}
```
### 5.5 调用示例
```bash
curl -X POST "http://localhost:8000/floating/predict/stream" \
-H "Content-Type: application/json" \
-d '{
"source_url": "rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream",
"webhook_url": "https://example.com/api/reservoir/webhook",
"roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]]
}'
```
### 5.6 提交成功返回示例
```json
{
"code": 200,
"msg": "task submitted",
"task_type": "floating"
}
```
## 6. webhook_url 参数说明
- `webhook_url` 必须是业务系统提供的接收地址。
- 请求方法为 `POST`
- 请求体格式为 `application/json`
- 当视频流识别到目标时才会触发回调;未识别到目标时不会持续推送空结果。
- 业务系统应保证该地址可被算法服务访问,并能在超时时间内返回。
## 7. 视频流回调数据格式
### 7.1 回调 JSON 示例
```json
{
"event": "RESERVOIR_ALARM",
"scene": "floating",
"stream_url": "rtsp://example.com/live",
"details": [
{
"label": "floating_object",
"confidence": 0.93,
"bbox": [102.4, 55.2, 260.8, 188.6]
}
],
"msg": "detected floating event"
}
```
### 7.2 字段说明
- `event`:事件类型,当前为 `RESERVOIR_ALARM`
- `scene`:触发识别的场景类型,对应接口中的 `model_type`
- `stream_url`:本次识别的视频流地址。
- `details`:识别结果数组。
- `label`:识别类别名称。
- `confidence`:识别置信度,范围通常为 0 到 1。
- `bbox`:目标框坐标,格式为 `[x1, y1, x2, y2]`
- `msg`:简要告警说明。
## 8. 使用建议
- 视频流接口为异步提交接口,请结合业务系统的 `webhook_url` 接收识别结果。
- 若需要限定检测区域,建议传入 `roi`,减少无关区域误报。
- 推荐通过 FastAPI 自带文档页面查看接口:
- Swagger UI:`/docs`
- ReDoc:`/redoc`

BIN
app/TioTech.mp4 View File


+ 851
- 0
app/main.py View File

@ -0,0 +1,851 @@
import json
import os
import tempfile
from typing import List, Optional
import cv2
import numpy as np
from fastapi import FastAPI, File, HTTPException, Path, UploadFile, Form
from pydantic import BaseModel, Field
from celery.result import AsyncResult
from app.model_registry import MODEL_MAP, SCENE_INFO, iter_models, load_model
from app.tasks import celery_app, analyze_video_stream, analyze_video_file
# 共享上传目录(API 和 Worker 容器通过 volume 共享)
UPLOAD_DIR = os.getenv("UPLOAD_DIR", "/tmp")
UPLOAD_DIR = os.getenv("UPLOAD_DIR", "/tmp")
from app.tasks import celery_app, analyze_video_stream, analyze_video_file
AUTO_SCENE_TASK_TYPE = "auto_scene"
SCENE_MARKDOWN = "\n".join(
f"- `{model_type}`: {scene['name']},{scene['description']}"
for model_type, scene in SCENE_INFO.items()
)
SUPPORTED_MODEL_TYPES = ", ".join(MODEL_MAP.keys())
WEBHOOK_PAYLOAD_EXAMPLE = {
"event": "RESERVOIR_ALARM",
"scene": "floating",
"stream_url": "rtsp://example.com/live",
"details": [
{
"label": "floating_object",
"confidence": 0.93,
"bbox": [102.4, 55.2, 260.8, 188.6],
}
],
"msg": "detected floating event",
}
WEBHOOK_CALLBACK_SCHEMA = {
"type": "object",
"required": ["event", "scene", "stream_url", "details", "msg"],
"properties": {
"event": {
"type": "string",
"description": "事件类型,当前固定为 `RESERVOIR_ALARM`。",
"example": "RESERVOIR_ALARM",
},
"scene": {
"type": "string",
"description": "触发识别的场景类型,例如 `floating`、`gate`、`shore_garbage`、`water_gauge`。",
"example": "floating",
},
"stream_url": {
"type": "string",
"description": "原始视频流地址。",
"example": "rtsp://example.com/live",
},
"details": {
"type": "array",
"description": "识别结果列表。",
"items": {
"type": "object",
"required": ["label", "confidence", "bbox"],
"properties": {
"label": {
"type": "string",
"description": "识别类别名称。",
"example": "floating_object",
},
"confidence": {
"type": "number",
"format": "float",
"description": "识别置信度。",
"example": 0.93,
},
"bbox": {
"type": "array",
"description": "目标框坐标数组,格式为 `[x1, y1, x2, y2]`。",
"items": {"type": "number", "format": "float"},
"example": [102.4, 55.2, 260.8, 188.6],
},
},
},
},
"msg": {
"type": "string",
"description": "告警说明。",
"example": "detected floating event",
},
},
}
WEBHOOK_CALLBACK_OPENAPI = {
"onWebhookResult": {
"{$request.body#/webhook_url}": {
"post": {
"summary": "识别结果 webhook 回调",
"description": "当视频流识别到目标后,算法服务会向请求体中的 `webhook_url` 发送 HTTP POST 回调。",
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": WEBHOOK_CALLBACK_SCHEMA,
"example": WEBHOOK_PAYLOAD_EXAMPLE,
}
},
},
"responses": {
"200": {
"description": "业务方成功接收回调。"
}
},
}
}
}
}
LEGACY_STREAM_REQUEST_EXAMPLE = {
"source_url": "rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream",
"webhook_url": "https://example.com/api/reservoir/webhook",
"scene_type": "floating",
"roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]],
}
STREAM_REQUEST_EXAMPLE = {
"source_url": "rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream",
"webhook_url": "https://example.com/api/reservoir/webhook",
"roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]],
}
AUTO_STREAM_RESPONSE_EXAMPLE = {
"code": 200,
"msg": "task submitted",
"task_type": AUTO_SCENE_TASK_TYPE,
}
STREAM_RESPONSE_EXAMPLE = {
"code": 200,
"msg": "task submitted",
"task_type": "floating",
}
IMAGE_RESPONSE_EXAMPLE = {
"results": [
{
"name": "floating_object",
"class": 0,
"confidence": 0.93,
"box": {
"x1": 102.4,
"y1": 55.2,
"x2": 260.8,
"y2": 188.6,
},
}
]
}
AUTO_IMAGE_RESPONSE_EXAMPLE = {
"task_type": AUTO_SCENE_TASK_TYPE,
"results": [
{
"scene": "floating",
"name": "floating_object",
"class": 0,
"confidence": 0.93,
"box": {
"x1": 102.4,
"y1": 55.2,
"x2": 260.8,
"y2": 188.6,
},
}
],
}
WEBHOOK_FIELD_DESCRIPTION = (
"识别结果回调地址,算法服务会以 HTTP POST 方式回调该地址。"
"回调 JSON 参数说明:`event` 为事件类型,`scene` 为场景类型,"
"`stream_url` 为视频流地址,`details` 为识别结果列表,`msg` 为告警说明。"
)
WEBHOOK_CALLBACK_PARAMETER_DESCRIPTION = (
"回调参数中文说明:\n"
"- `event`:事件类型,当前固定为告警事件 `RESERVOIR_ALARM`。\n"
"- `scene`:本次识别命中的场景类型,例如 `floating`、`gate`、`shore_garbage`、`water_gauge`。\n"
"- `stream_url`:触发识别的视频流地址,即调用接口时传入的原始流地址。\n"
"- `details`:识别结果列表。\n"
"- `details[].label`:识别出的目标类别名称。\n"
"- `details[].confidence`:识别结果的置信度。\n"
"- `details[].bbox`:目标框坐标,格式为 `[x1, y1, x2, y2]`。\n"
"- `msg`:告警说明文本,用于描述当前识别事件。"
)
APP_DESCRIPTION = f"""
寿 YOLO
{SCENE_MARKDOWN}
- `POST /v1/predict/image`
- `POST /v1/predict/stream`
- `POST /v1/predict/video-file`MP4文件识别
- `POST /{{model_type}}/predict/image`
- `POST /{{model_type}}/predict/stream`
- `POST /v1/task/stream`
"""
app = FastAPI(
title="延寿水库智能识别服务",
description=APP_DESCRIPTION,
version="1.2.0",
openapi_tags=[
{"name": "图像识别", "description": "支持自动场景识别,也支持按指定场景模型执行图片识别。推荐优先使用 `/v1/predict/image`。"},
{"name": "视频流识别", "description": "支持自动场景识别,也支持按指定场景模型提交视频流异步识别任务。推荐优先使用 `/v1/predict/stream`。"},
{"name": "视频文件识别", "description": "支持上传MP4文件进行离线识别分析。推荐优先使用 `/v1/predict/video-file`。"},
{"name": "任务管理", "description": "查询异步任务状态。"},
{"name": "兼容接口", "description": "兼容旧调用方式的接口,建议逐步迁移到自动场景识别接口。"},
],
)
class TaskRequest(BaseModel):
source_url: str = Field(
...,
description="视频流地址,支持 RTSP、本地视频文件路径等 OpenCV 可读取的地址。",
example="rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream",
)
webhook_url: str = Field(
...,
description=WEBHOOK_FIELD_DESCRIPTION,
example="https://example.com/api/reservoir/webhook",
)
scene_type: Optional[str] = Field(
default=None,
description=f"兼容旧字段。传值时按指定场景识别;不传时自动遍历全部场景模型。可选值:{SUPPORTED_MODEL_TYPES}",
example="floating",
)
roi: Optional[List[List[int]]] = Field(
default=None,
description="可选电子围栏,多边形坐标数组,格式为 [[x1, y1], [x2, y2], ...];不传时默认检测整幅画面。",
example=[[0, 0], [1920, 0], [1920, 1080], [0, 1080]],
)
class StreamPredictRequest(BaseModel):
source_url: str = Field(
...,
description="视频流地址,支持 RTSP、本地视频文件路径等 OpenCV 可读取的地址。",
example="rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream",
)
webhook_url: str = Field(
...,
description=WEBHOOK_FIELD_DESCRIPTION,
example="https://example.com/api/reservoir/webhook",
)
roi: Optional[List[List[int]]] = Field(
default=None,
description="可选电子围栏,多边形坐标数组,格式为 [[x1, y1], [x2, y2], ...];不传时默认检测整幅画面。",
example=[[0, 0], [1920, 0], [1920, 1080], [0, 1080]],
)
class VideoFileRequest(BaseModel):
webhook_url: str = Field(
...,
description="识别结果回调地址",
example="https://example.com/api/reservoir/webhook",
)
roi: Optional[List[List[int]]] = Field(
default=None,
description="可选电子围栏",
example=[[0, 0], [1920, 0], [1920, 1080], [0, 1080]],
)
scene_type: Optional[str] = Field(
default=None,
description=f"指定场景类型,可选值:{SUPPORTED_MODEL_TYPES}",
)
class StreamTaskResponse(BaseModel):
code: int = Field(..., description="业务状态码,`200` 表示任务提交成功。", example=200)
msg: str = Field(..., description="接口返回说明信息。", example="task submitted")
task_type: str = Field(
...,
description=f"实际提交的任务类型。自动识别时为 `{AUTO_SCENE_TASK_TYPE}`,指定场景时为对应模型类型。",
example=AUTO_SCENE_TASK_TYPE,
)
class VideoFileTaskResponse(BaseModel):
code: int = Field(..., description="业务状态码,`200` 表示任务提交成功。", example=200)
msg: str = Field(..., description="接口返回说明信息。", example="video file task submitted")
task_id: str = Field(..., description="任务ID,用于查询任务状态。", example="abc123def456")
task_type: str = Field(
...,
description=f"实际提交的任务类型。自动识别时为 `{AUTO_SCENE_TASK_TYPE}`,指定场景时为对应模型类型。",
example=AUTO_SCENE_TASK_TYPE,
)
class DetectionBox(BaseModel):
x1: float = Field(..., description="检测框左上角 X 坐标。", example=102.4)
y1: float = Field(..., description="检测框左上角 Y 坐标。", example=55.2)
x2: float = Field(..., description="检测框右下角 X 坐标。", example=260.8)
y2: float = Field(..., description="检测框右下角 Y 坐标。", example=188.6)
class ImageDetectionItem(BaseModel):
name: str = Field(..., description="检测类别名称。", example="floating_object")
class_id: int = Field(..., alias="class", description="检测类别 ID。", example=0)
confidence: float = Field(..., description="检测置信度。", example=0.93)
box: DetectionBox = Field(..., description="目标框坐标。")
class AutoImageDetectionItem(ImageDetectionItem):
scene: str = Field(..., description="命中的场景模型类型。", example="floating")
class ImagePredictResponse(BaseModel):
results: List[ImageDetectionItem] = Field(
...,
description="识别结果列表。每个元素为模型输出的目标信息,通常包含类别名、类别 ID、置信度和检测框坐标。",
example=IMAGE_RESPONSE_EXAMPLE["results"],
)
class AutoImagePredictResponse(BaseModel):
task_type: str = Field(
...,
description=f"任务类型,固定为 `{AUTO_SCENE_TASK_TYPE}`。",
example=AUTO_SCENE_TASK_TYPE,
)
results: List[AutoImageDetectionItem] = Field(
...,
description="自动场景识别结果列表。每个元素额外包含 `scene` 字段,表示命中的场景模型。",
example=AUTO_IMAGE_RESPONSE_EXAMPLE["results"],
)
class WebhookDetectionItem(BaseModel):
label: str = Field(..., description="识别类别名称。", example="floating_object")
confidence: float = Field(..., description="识别置信度。", example=0.93)
bbox: List[float] = Field(..., description="目标框坐标数组,格式为 `[x1, y1, x2, y2]`。", example=[102.4, 55.2, 260.8, 188.6])
class WebhookPayload(BaseModel):
event: str = Field(..., description="事件类型。", example="RESERVOIR_ALARM")
scene: str = Field(..., description="触发识别的场景类型。", example="floating")
stream_url: str = Field(..., description="视频流地址。", example="rtsp://example.com/live")
details: List[WebhookDetectionItem] = Field(..., description="识别结果列表。")
msg: str = Field(..., description="告警说明。", example="detected floating event")
def validate_model_type(model_type: str) -> None:
if model_type not in MODEL_MAP:
raise HTTPException(
status_code=400,
detail=f"Unsupported model type: {model_type}. Supported types: {SUPPORTED_MODEL_TYPES}",
)
def decode_image(contents: bytes):
nparr = np.frombuffer(contents, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
raise HTTPException(status_code=400, detail="Invalid image file")
return img
def run_single_model_image_detection(img, model_type: str) -> list:
model = load_model(model_type)
results = model.predict(img, conf=0.6, verbose=False)
return json.loads(results[0].to_json())
def run_auto_image_detection(img) -> dict:
detections = []
for current_model_type, model in iter_models():
results = model.predict(img, conf=0.6, verbose=False)
for item in json.loads(results[0].to_json()):
item["scene"] = current_model_type
detections.append(item)
return {"task_type": AUTO_SCENE_TASK_TYPE, "results": detections}
def submit_stream_task(
source_url: str,
webhook_url: str,
roi: Optional[List[List[int]]],
model_type: Optional[str] = None,
):
if model_type is not None:
validate_model_type(model_type)
task = analyze_video_stream.delay(source_url, webhook_url, model_type, roi)
return {"code": 200, "msg": "task submitted", "task_type": model_type or AUTO_SCENE_TASK_TYPE, "task_id": task.id}
def submit_video_file_task(
video_path: str,
webhook_url: str,
roi: Optional[List[List[int]]],
model_type: Optional[str] = None,
original_filename: str = None,
):
"""提交视频文件识别任务"""
if model_type is not None:
validate_model_type(model_type)
task = analyze_video_file.delay(video_path, webhook_url, model_type, roi, original_filename)
return {
"code": 200,
"msg": "video file task submitted",
"task_id": task.id,
"task_type": model_type or AUTO_SCENE_TASK_TYPE
}
@app.post(
"/v1/task/stream",
tags=["兼容接口", "视频流识别"],
summary="兼容模式提交视频流识别任务",
description=(
"兼容旧调用方式提交视频流识别任务。\n\n"
"入参说明:\n"
"- `source_url`:视频流地址。\n"
"- `webhook_url`:识别结果回调地址。\n"
f"- `scene_type`:兼容旧字段,传值时按指定场景识别,不传时自动识别全部场景;可选值:{SUPPORTED_MODEL_TYPES}。\n"
"- `roi`:可选电子围栏。\n\n"
"模拟入参示例:\n"
f"```json\n{json.dumps(LEGACY_STREAM_REQUEST_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"出参说明:\n"
"- `code`:业务状态码,200 表示提交成功。\n"
"- `msg`:返回说明信息。\n"
f"- `task_type`:实际提交的任务类型,自动识别时为 `{AUTO_SCENE_TASK_TYPE}`。\n\n"
"模拟出参示例:\n"
f"```json\n{json.dumps(AUTO_STREAM_RESPONSE_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"说明:\n"
"- 建议新接入统一改用 `POST /v1/predict/stream`。\n"
"- 自动识别模式下,worker 会遍历全部已注册场景模型。\n"
"- Swagger 文档中的 Callbacks 区域可查看 `webhook_url` 的回调参数结构。\n\n"
f"{WEBHOOK_CALLBACK_PARAMETER_DESCRIPTION}\n"
),
response_model=StreamTaskResponse,
responses={
200: {
"description": "任务提交成功",
"content": {"application/json": {"example": AUTO_STREAM_RESPONSE_EXAMPLE}},
},
400: {"description": "请求参数错误或场景类型不支持。"},
},
deprecated=True,
openapi_extra={
"requestBody": {
"content": {
"application/json": {
"example": LEGACY_STREAM_REQUEST_EXAMPLE
}
}
},
"callbacks": WEBHOOK_CALLBACK_OPENAPI,
},
)
async def start_stream_task(req: TaskRequest):
return submit_stream_task(req.source_url, req.webhook_url, req.roi, req.scene_type)
@app.post(
"/v1/predict/stream",
tags=["视频流识别"],
summary="自动场景视频流识别任务",
description=(
"自动遍历所有已注册场景模型,对视频流执行异步识别任务。\n\n"
"入参说明:\n"
"- `source_url`:视频流地址。\n"
"- `webhook_url`:识别结果回调地址。\n"
"- `roi`:可选电子围栏。\n\n"
"模拟入参示例:\n"
f"```json\n{json.dumps(STREAM_REQUEST_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"出参说明:\n"
"- `code`:业务状态码,200 表示提交成功。\n"
"- `msg`:返回说明信息。\n"
f"- `task_type`:固定返回 `{AUTO_SCENE_TASK_TYPE}`。\n\n"
"模拟出参示例:\n"
f"```json\n{json.dumps(AUTO_STREAM_RESPONSE_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"检测到目标后会向 `webhook_url` 发送 POST 回调,回调数据示例:\n"
f"```json\n{json.dumps(WEBHOOK_PAYLOAD_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"回调说明:\n"
"- 自动识别模式下,如果同一帧命中多个场景,会按场景分别回调。\n"
"- `scene` 字段表示当前这条 webhook 对应的场景模型。\n"
"- Swagger 文档中的 Callbacks 区域可查看完整回调参数结构。\n\n"
f"{WEBHOOK_CALLBACK_PARAMETER_DESCRIPTION}\n"
),
response_model=StreamTaskResponse,
responses={
200: {
"description": "任务提交成功",
"content": {"application/json": {"example": AUTO_STREAM_RESPONSE_EXAMPLE}},
},
400: {"description": "请求参数错误。"},
},
openapi_extra={
"requestBody": {
"content": {
"application/json": {
"example": STREAM_REQUEST_EXAMPLE
}
}
},
"callbacks": WEBHOOK_CALLBACK_OPENAPI,
},
)
async def predict_stream_v1(req: StreamPredictRequest):
return submit_stream_task(req.source_url, req.webhook_url, req.roi, None)
@app.post(
"/{model_type}/predict/stream",
tags=["视频流识别"],
summary="按场景提交视频流识别任务",
description=(
"根据路径中的 `model_type` 选择对应场景模型,异步提交视频流识别任务。\n\n"
"入参说明:\n"
"- `model_type`:路径参数,场景模型类型。\n"
"- `source_url`:视频流地址。\n"
"- `webhook_url`:识别结果回调地址。\n"
"- `roi`:可选电子围栏。\n\n"
"模拟入参示例:\n"
f"```json\n{json.dumps(STREAM_REQUEST_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"出参说明:\n"
"- `code`:业务状态码,200 表示提交成功。\n"
"- `msg`:返回说明信息。\n"
"- `task_type`:实际提交的场景类型。\n\n"
"模拟出参示例:\n"
f"```json\n{json.dumps(STREAM_RESPONSE_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"检测到目标后会向 `webhook_url` 发送 POST 回调,回调数据示例:\n"
f"```json\n{json.dumps(WEBHOOK_PAYLOAD_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"回调说明:\n"
"- 指定场景模式下,只会使用路径里的 `model_type` 对应模型。\n"
"- webhook 的 `scene` 字段与路径中的 `model_type` 一致。\n"
"- Swagger 文档中的 Callbacks 区域可查看完整回调参数结构。\n\n"
f"{WEBHOOK_CALLBACK_PARAMETER_DESCRIPTION}\n"
),
response_model=StreamTaskResponse,
responses={
200: {
"description": "任务提交成功",
"content": {"application/json": {"example": STREAM_RESPONSE_EXAMPLE}},
},
400: {"description": "场景类型不支持或请求参数错误。"},
},
openapi_extra={
"requestBody": {
"content": {
"application/json": {
"example": STREAM_REQUEST_EXAMPLE
}
}
},
"callbacks": WEBHOOK_CALLBACK_OPENAPI,
},
)
async def predict_stream(
model_type: str = Path(..., description=f"场景模型类型。可选值:{SUPPORTED_MODEL_TYPES}"),
req: StreamPredictRequest = ...,
):
return submit_stream_task(req.source_url, req.webhook_url, req.roi, model_type)
@app.post(
"/v1/predict/video-file",
tags=["视频文件识别"],
summary="上传MP4文件进行识别",
description=(
"支持上传本地MP4文件进行视频识别分析。\n\n"
"入参说明:\n"
"- `file`:上传的MP4视频文件\n"
"- `webhook_url`:识别结果回调地址\n"
"- `roi`:可选电子围栏(JSON字符串格式)\n"
"- `scene_type`:可选指定场景类型,不传则自动识别\n\n"
"模拟入参示例:\n"
"```bash\n"
"curl -X POST http://localhost:8000/v1/predict/video-file \\\n"
" -H \"accept: application/json\" \\\n"
" -F \"file=@test.mp4;type=video/mp4\" \\\n"
" -F \"webhook_url=https://example.com/api/webhook\" \\\n"
" -F \"roi=[[0,0],[1920,0],[1920,1080],[0,1080]]\" \\\n"
" -F \"scene_type=floating\"\n"
"```\n\n"
"出参说明:\n"
"- `code`:业务状态码,200表示提交成功\n"
"- `msg`:返回说明信息\n"
"- `task_id`:任务ID,用于查询任务状态\n"
"- `task_type`:实际提交的任务类型\n\n"
"模拟出参示例:\n"
"```json\n"
"{\n"
" \"code\": 200,\n"
" \"msg\": \"video file task submitted\",\n"
" \"task_id\": \"abc123def456\",\n"
" \"task_type\": \"auto_scene\"\n"
"}\n"
"```\n\n"
"检测完成或检测到目标后会向 `webhook_url` 发送回调。\n"
"文件大小限制:500MB\n"
),
response_model=VideoFileTaskResponse,
responses={
200: {"description": "任务提交成功"},
400: {"description": "文件格式错误、大小超限或参数错误"},
500: {"description": "服务器内部错误"},
},
)
async def predict_video_file(
file: UploadFile = File(..., description="MP4视频文件", media_type="video/mp4"),
webhook_url: str = Form(..., description="识别结果回调地址"),
roi: Optional[str] = Form(default="[[0,0],[1920,0],[1920,1080],[0,1080]]", description="电子围栏JSON字符串"),
scene_type: Optional[str] = Form(default=None, description=f"场景类型,可选值:{SUPPORTED_MODEL_TYPES}"),
):
# 验证文件格式
if not file.filename.endswith(('.mp4', '.MP4')):
raise HTTPException(status_code=400, detail="Only MP4 files are supported")
# 验证文件大小(限制500MB)
file_size = 0
temp_file_path = None
try:
# 创建临时文件保存上传的视频(存入共享目录,确保 Worker 容器也能读取)
os.makedirs(UPLOAD_DIR, exist_ok=True)
with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4', dir=UPLOAD_DIR) as temp_file:
# 分块读取并写入
chunk_size = 1024 * 1024 # 1MB chunks
while True:
chunk = await file.read(chunk_size)
if not chunk:
break
temp_file.write(chunk)
file_size += len(chunk)
# 限制文件大小为500MB
if file_size > 500 * 1024 * 1024:
raise HTTPException(status_code=400, detail="File size exceeds 500MB limit")
temp_file_path = temp_file.name
# 解析ROI参数
roi_list = None
if roi:
try:
roi_list = json.loads(roi)
if not isinstance(roi_list, list):
raise ValueError("ROI must be a list")
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="Invalid ROI format, must be valid JSON")
# 提交任务
result = submit_video_file_task(
video_path=temp_file_path,
webhook_url=webhook_url,
roi=roi_list,
model_type=scene_type,
original_filename=file.filename
)
return result
except HTTPException:
# 清理临时文件
if temp_file_path and os.path.exists(temp_file_path):
os.unlink(temp_file_path)
raise
except Exception as exc:
if temp_file_path and os.path.exists(temp_file_path):
os.unlink(temp_file_path)
raise HTTPException(status_code=500, detail=f"Failed to process video file: {str(exc)}") from exc
@app.get(
"/v1/task/status/{task_id}",
tags=["任务管理"],
summary="查询异步任务状态",
description="通过任务ID查询视频识别任务的执行状态和进度",
)
async def get_task_status(
task_id: str = Path(..., description="任务ID,从提交接口返回的task_id")
):
"""查询任务状态"""
try:
task = AsyncResult(task_id, app=celery_app)
if task.state == 'PENDING':
response = {
"state": "PENDING",
"progress": 0,
"message": "Task is waiting to be processed"
}
elif task.state == 'PROCESSING':
response = {
"state": "PROCESSING",
"progress": task.info.get('progress', 0) if task.info else 0,
"message": task.info.get('message', 'Processing video') if task.info else 'Processing',
"frame": task.info.get('frame', 0) if task.info else 0,
"total_frames": task.info.get('total_frames', 0) if task.info else 0
}
elif task.state == 'SUCCESS':
response = {
"state": "SUCCESS",
"result": task.result,
"message": "Task completed successfully"
}
elif task.state == 'FAILURE':
response = {
"state": "FAILURE",
"error": str(task.info),
"message": "Task failed"
}
else:
response = {
"state": task.state,
"message": "Unknown task state"
}
return response
except Exception as exc:
raise HTTPException(
status_code=500,
detail=f"Failed to query task status: {str(exc)}",
) from exc
@app.post(
"/v1/predict/image",
tags=["图像识别"],
summary="自动场景图片识别",
description=(
"不再需要指定 `model_type`,接口会自动遍历所有已注册场景模型,对上传图片执行场景识别。\n\n"
"入参说明:\n"
"- `file`:上传的待识别图片文件。\n\n"
"模拟入参示例:\n"
"```bash\n"
"curl -X POST http://localhost:8000/v1/predict/image \\\n"
" -H \"accept: application/json\" \\\n"
" -H \"Content-Type: multipart/form-data\" \\\n"
" -F \"file=@test.jpg;type=image/jpeg\"\n"
"```\n\n"
"出参说明:\n"
f"- `task_type`:固定返回 `{AUTO_SCENE_TASK_TYPE}`。\n"
"- `results`:识别结果列表。\n"
"- `results[].scene`:命中的场景模型类型。\n"
"- `results[].name`:类别名称。\n"
"- `results[].class`:类别 ID。\n"
"- `results[].confidence`:置信度。\n"
"- `results[].box`:目标框坐标。\n\n"
"模拟出参示例:\n"
f"```json\n{json.dumps(AUTO_IMAGE_RESPONSE_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"说明:\n"
"- 该接口会遍历全部已注册模型并合并命中结果。\n"
"- 若没有检测到目标,`results` 返回空数组。\n"
),
response_model=AutoImagePredictResponse,
responses={
200: {
"description": "图片自动场景识别成功",
"content": {"application/json": {"example": AUTO_IMAGE_RESPONSE_EXAMPLE}},
},
400: {"description": "上传文件不是有效图片。"},
},
)
async def predict_image_v1(
file: UploadFile = File(..., description="待识别图片文件,示例:file=@test.jpg"),
):
try:
contents = await file.read()
img = decode_image(contents)
return run_auto_image_detection(img)
except HTTPException:
raise
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@app.post(
"/{model_type}/predict/image",
tags=["图像识别"],
summary="按场景执行图片识别",
description=(
"根据路径中的 `model_type` 选择对应场景模型,对上传图片执行识别。\n\n"
"入参说明:\n"
"- `model_type`:路径参数,场景模型类型。\n"
"- `file`:上传的待识别图片文件。\n\n"
"模拟入参示例:\n"
"```bash\n"
"curl -X POST http://localhost:8000/floating/predict/image \\\n"
" -H \"accept: application/json\" \\\n"
" -H \"Content-Type: multipart/form-data\" \\\n"
" -F \"file=@test.jpg;type=image/jpeg\"\n"
"```\n\n"
"出参说明:\n"
"- `results`:识别结果列表。\n"
"- `results[].name`:类别名称。\n"
"- `results[].class`:类别 ID。\n"
"- `results[].confidence`:置信度。\n"
"- `results[].box`:目标框坐标。\n\n"
"模拟出参示例:\n"
f"```json\n{json.dumps(IMAGE_RESPONSE_EXAMPLE, ensure_ascii=False, indent=2)}\n```\n\n"
"说明:\n"
"- 该接口只使用路径中的 `model_type` 对应模型。\n"
"- 若没有检测到目标,`results` 返回空数组。\n"
),
response_model=ImagePredictResponse,
responses={
200: {
"description": "图片识别成功",
"content": {"application/json": {"example": IMAGE_RESPONSE_EXAMPLE}},
},
400: {"description": "场景类型不支持,或上传文件不是有效图片。"},
},
)
async def predict_image(
model_type: str = Path(..., description=f"场景模型类型。可选值:{SUPPORTED_MODEL_TYPES}"),
file: UploadFile = File(..., description="待识别图片文件,示例:file=@test.jpg"),
):
validate_model_type(model_type)
try:
contents = await file.read()
img = decode_image(contents)
return {"results": run_single_model_image_detection(img, model_type)}
except HTTPException:
raise
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

BIN
app/model/Floating/best.pt View File


BIN
app/model/Floating/train4/BoxF1_curve.png View File

Before After
Width: 2250  |  Height: 1500  |  Size: 235 KiB

BIN
app/model/Floating/train4/BoxPR_curve.png View File

Before After
Width: 2250  |  Height: 1500  |  Size: 228 KiB

BIN
app/model/Floating/train4/BoxP_curve.png View File

Before After
Width: 2250  |  Height: 1500  |  Size: 190 KiB

BIN
app/model/Floating/train4/BoxR_curve.png View File

Before After
Width: 2250  |  Height: 1500  |  Size: 225 KiB

+ 106
- 0
app/model/Floating/train4/args.yaml View File

@ -0,0 +1,106 @@
task: detect
mode: train
model: ./yolo11n.pt
data: ./Conf/Conf_River_Floating.yaml
epochs: 1000
time: null
patience: 100
batch: 64
imgsz: 1280
save: true
save_period: -1
cache: false
device: 0,1,2,3
workers: 0
project: null
name: train4
exist_ok: false
pretrained: true
optimizer: auto
verbose: true
seed: 0
deterministic: true
single_cls: false
rect: false
cos_lr: false
close_mosaic: 10
resume: false
amp: true
fraction: 1.0
profile: false
freeze: null
multi_scale: false
compile: false
overlap_mask: true
mask_ratio: 4
dropout: 0.0
val: true
split: val
save_json: false
conf: 0.25
iou: 0.7
max_det: 300
half: false
dnn: false
plots: true
source: null
vid_stride: 1
stream_buffer: false
visualize: false
augment: false
agnostic_nms: false
classes: null
retina_masks: false
embed: null
show: false
save_frames: false
save_txt: false
save_conf: false
save_crop: false
show_labels: true
show_conf: true
show_boxes: true
line_width: null
format: torchscript
keras: false
optimize: false
int8: false
dynamic: false
simplify: true
opset: null
workspace: null
nms: false
lr0: 0.005
lrf: 0.01
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 5.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
box: 10.0
cls: 1.0
dfl: 2.0
pose: 12.0
kobj: 1.0
nbs: 64
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
degrees: 0.0
translate: 0.1
scale: 0.5
shear: 0.0
perspective: 0.0
flipud: 0.0
fliplr: 0.5
bgr: 0.0
mosaic: 1.0
mixup: 0.0
cutmix: 0.0
copy_paste: 0.3
copy_paste_mode: flip
auto_augment: randaugment
erasing: 0.4
cfg: null
tracker: botsort.yaml
save_dir: /home/sutai/wsj/reservoir_train/runs/detect/train4

BIN
app/model/Floating/train4/confusion_matrix.png View File

Before After
Width: 3000  |  Height: 2250  |  Size: 189 KiB

BIN
app/model/Floating/train4/confusion_matrix_normalized.png View File

Before After
Width: 3000  |  Height: 2250  |  Size: 214 KiB

BIN
app/model/Floating/train4/labels.jpg View File

Before After
Width: 1600  |  Height: 1600  |  Size: 148 KiB

+ 287
- 0
app/model/Floating/train4/results.csv View File

@ -0,0 +1,287 @@
epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2
1,33.4112,2.39509,12.7977,2.40188,0,0,0,0,2.27359,6.71089,2.315,0.00191304,0.00191304,0.00191304
2,64.2582,2.07809,11.1844,2.14679,0,0,0,0,2.05492,6.40927,2.19038,0.00390917,0.00390917,0.00390917
3,93.9997,2.13405,9.95756,2.0733,0,0,0,0,2.32995,5.81948,2.3064,0.00590134,0.00590134,0.00590134
4,124.124,2.14439,8.38493,2.09449,0.21935,0.04898,0.13296,0.08116,2.68573,5.4136,2.59843,0.00788954,0.00788954,0.00788954
5,154.595,2.15373,7.53047,2.07161,0.3287,0.02175,0.01744,0.00849,4.06277,61.594,4.65705,0.00987379,0.00987379,0.00987379
6,184.83,2.35596,6.29438,2.20575,0.30012,0.05055,0.00988,0.00401,3.64732,63.492,4.78298,0.0099505,0.0099505,0.0099505
7,215.234,2.32979,5.48792,2.2124,0.02745,0.1158,0.02721,0.01222,3.10734,76.9508,4.06168,0.0099406,0.0099406,0.0099406
8,246.436,2.20819,4.8594,2.13989,0.05636,0.12391,0.03385,0.01423,3.67411,79.0338,4.45235,0.0099307,0.0099307,0.0099307
9,276.644,2.34735,4.8601,2.26271,0.12236,0.09724,0.0489,0.02414,3.44567,32.4887,3.97067,0.0099208,0.0099208,0.0099208
10,306.629,2.18417,4.3116,2.12706,0.08194,0.11332,0.05886,0.03163,3.01061,18.4977,3.46095,0.0099109,0.0099109,0.0099109
11,337.44,2.24794,4.11155,2.19118,0.91429,0.08774,0.14738,0.06394,3.57315,16.992,3.77222,0.009901,0.009901,0.009901
12,367.739,2.21728,4.28225,2.14579,0.17374,0.24812,0.23883,0.10971,2.70124,8.64248,2.87378,0.0098911,0.0098911,0.0098911
13,398.69,2.122,3.72056,2.05907,0.32906,0.1768,0.23621,0.12543,3.10642,8.50599,3.34959,0.0098812,0.0098812,0.0098812
14,430.028,2.14693,3.75207,2.05125,0.38129,0.26288,0.22819,0.11014,2.93184,16.773,3.11998,0.0098713,0.0098713,0.0098713
15,463.024,2.09661,3.69645,2.03073,0.14062,0.18945,0.16836,0.10019,2.69815,8.34905,3.00178,0.0098614,0.0098614,0.0098614
16,493.901,2.08116,3.56176,2.01431,0.50214,0.31571,0.37123,0.25045,2.329,4.88796,2.464,0.0098515,0.0098515,0.0098515
17,525.635,2.09936,3.42418,2.06,0.54816,0.33883,0.43483,0.26709,2.35196,4.61267,2.41869,0.0098416,0.0098416,0.0098416
18,556.277,2.08124,3.33558,2.06297,0.33882,0.33369,0.30326,0.18066,2.33899,5.059,2.40794,0.0098317,0.0098317,0.0098317
19,587.236,2.07934,3.32083,1.99435,0.41651,0.33028,0.38173,0.2342,2.39637,4.99267,2.50897,0.0098218,0.0098218,0.0098218
20,617.592,2.06915,3.29678,2.01635,0.51635,0.31763,0.31925,0.16276,2.56906,5.58749,2.58507,0.0098119,0.0098119,0.0098119
21,648.875,2.04413,3.28848,2.01841,0.33072,0.37199,0.33934,0.19054,2.52337,6.12432,2.55929,0.009802,0.009802,0.009802
22,679.869,2.0087,3.17607,2.00152,0.565,0.39026,0.38868,0.24235,2.22558,4.71118,2.28477,0.0097921,0.0097921,0.0097921
23,711.071,2.01974,3.14653,1.99325,0.40441,0.44287,0.43841,0.27109,2.28724,4.44453,2.30748,0.0097822,0.0097822,0.0097822
24,742.425,1.99648,2.94497,1.96764,0.5725,0.09721,0.1631,0.10733,2.92534,9.01378,3.25484,0.0097723,0.0097723,0.0097723
25,772.62,2.06885,3.02058,2.07763,0.52202,0.29904,0.38437,0.23816,2.3859,5.48165,2.54243,0.0097624,0.0097624,0.0097624
26,803.858,1.96085,2.90528,1.96232,0.51233,0.46149,0.4758,0.29387,2.27896,4.43162,2.36984,0.0097525,0.0097525,0.0097525
27,835.037,2.02208,2.77857,1.99893,0.33515,0.28609,0.31683,0.19602,2.50066,6.15903,2.66507,0.0097426,0.0097426,0.0097426
28,865.592,2.03301,2.73448,1.98963,0.49659,0.34141,0.42276,0.25157,2.47269,4.63183,2.51185,0.0097327,0.0097327,0.0097327
29,896.588,1.96476,2.79753,1.9813,0.5388,0.36579,0.44584,0.28486,2.21644,3.75674,2.28506,0.0097228,0.0097228,0.0097228
30,926.881,1.86472,2.637,1.88481,0.45209,0.45108,0.46248,0.29419,2.11763,3.88376,2.20945,0.0097129,0.0097129,0.0097129
31,958.149,1.90774,2.75392,1.9023,0.68001,0.44477,0.56639,0.38166,2.05275,3.37761,2.17998,0.009703,0.009703,0.009703
32,988.295,1.89363,2.71563,1.88663,0.45637,0.32381,0.3727,0.22422,2.28483,5.12807,2.44161,0.0096931,0.0096931,0.0096931
33,1018.61,1.89589,2.6815,1.95134,0.57547,0.49996,0.57094,0.36593,2.06348,3.37383,2.1709,0.0096832,0.0096832,0.0096832
34,1049.64,1.91796,2.61283,1.93174,0.6023,0.48813,0.596,0.38649,2.15059,3.67912,2.29399,0.0096733,0.0096733,0.0096733
35,1080.83,1.85469,2.48279,1.84625,0.62724,0.49087,0.59102,0.3457,2.27444,3.47772,2.34883,0.0096634,0.0096634,0.0096634
36,1111.71,1.90011,2.74844,1.9341,0.5392,0.51061,0.54571,0.35343,2.06851,3.35112,2.18239,0.0096535,0.0096535,0.0096535
37,1142.77,1.86612,2.53197,1.90013,0.69213,0.5854,0.6807,0.43885,1.99116,2.91807,2.11319,0.0096436,0.0096436,0.0096436
38,1173.46,1.8645,2.43429,1.94447,0.42449,0.32249,0.37815,0.21983,2.48945,4.83547,2.5625,0.0096337,0.0096337,0.0096337
39,1204.19,1.86851,2.59506,1.93904,0.56418,0.50811,0.56633,0.35308,2.0772,4.00271,2.16946,0.0096238,0.0096238,0.0096238
40,1235.52,1.88343,2.41743,1.8683,0.6036,0.53553,0.54392,0.33,2.06793,3.40566,2.16109,0.0096139,0.0096139,0.0096139
41,1266.54,1.8789,2.46718,1.85799,0.65278,0.54068,0.6073,0.38942,2.03905,2.75934,2.11769,0.009604,0.009604,0.009604
42,1296.91,1.87415,2.35517,1.89317,0.52272,0.58573,0.60708,0.39084,1.99974,2.75824,2.09871,0.0095941,0.0095941,0.0095941
43,1327.15,1.8065,2.36363,1.85676,0.5696,0.5635,0.59166,0.35549,2.11079,2.9944,2.2015,0.0095842,0.0095842,0.0095842
44,1358.15,1.71217,2.25062,1.834,0.62599,0.58271,0.6454,0.3944,2.05505,2.76048,2.14881,0.0095743,0.0095743,0.0095743
45,1388.44,1.79958,2.41177,1.86353,0.61154,0.62068,0.65499,0.4053,2.04121,2.62992,2.12149,0.0095644,0.0095644,0.0095644
46,1419.65,1.73793,2.27744,1.80536,0.61744,0.61691,0.64451,0.40388,2.03083,2.58909,2.11498,0.0095545,0.0095545,0.0095545
47,1449.87,1.8252,2.32864,1.86931,0.6701,0.52481,0.59996,0.38251,2.13468,3.18874,2.15855,0.0095446,0.0095446,0.0095446
48,1481.18,1.83037,2.23891,1.84423,0.67257,0.56493,0.63626,0.40492,1.94322,2.77078,2.09522,0.0095347,0.0095347,0.0095347
49,1512.32,1.84992,2.27421,1.86811,0.544,0.58535,0.56303,0.34566,2.03373,3.10096,2.14207,0.0095248,0.0095248,0.0095248
50,1542.63,1.80004,2.29197,1.8501,0.52113,0.61851,0.56774,0.36182,1.98226,2.68201,2.06094,0.0095149,0.0095149,0.0095149
51,1573.04,1.8649,2.39088,1.86625,0.65926,0.62994,0.6645,0.4108,2.02379,2.62625,2.08539,0.009505,0.009505,0.009505
52,1604.28,1.86099,2.4067,1.94229,0.70243,0.5713,0.66193,0.40454,2.0489,2.62656,2.09965,0.0094951,0.0094951,0.0094951
53,1634.67,1.78459,2.32641,1.83533,0.73297,0.58992,0.69743,0.43403,2.00523,2.55661,2.07352,0.0094852,0.0094852,0.0094852
54,1665.87,1.77479,2.12097,1.78918,0.69575,0.63374,0.69585,0.44632,1.93363,2.34394,2.03032,0.0094753,0.0094753,0.0094753
55,1696.11,1.79447,2.21309,1.83822,0.5633,0.65643,0.6702,0.43464,1.97186,2.53811,2.09247,0.0094654,0.0094654,0.0094654
56,1727.31,1.68976,1.99661,1.71081,0.51058,0.64818,0.60448,0.37644,2.05012,2.96843,2.11168,0.0094555,0.0094555,0.0094555
57,1759.1,1.8444,2.09752,1.85829,0.6798,0.60319,0.66547,0.41173,2.06851,2.52008,2.14515,0.0094456,0.0094456,0.0094456
58,1789.29,1.75257,2.17528,1.79767,0.61557,0.49712,0.57502,0.38081,2.05903,3.38497,2.26234,0.0094357,0.0094357,0.0094357
59,1820.52,1.68272,2.09344,1.73428,0.66689,0.65765,0.70093,0.44305,1.96759,2.44041,2.03783,0.0094258,0.0094258,0.0094258
60,1851.04,1.77978,2.06757,1.83414,0.63963,0.56241,0.60656,0.39329,1.9806,2.82047,2.09751,0.0094159,0.0094159,0.0094159
61,1882.16,1.75469,2.09708,1.79083,0.59296,0.64927,0.66399,0.41516,1.99071,2.44924,2.07691,0.009406,0.009406,0.009406
62,1912.36,1.70839,2.04093,1.79552,0.74807,0.60526,0.70708,0.44594,1.96958,2.39755,2.08955,0.0093961,0.0093961,0.0093961
63,1943.6,1.81063,2.19109,1.84124,0.66267,0.4528,0.55566,0.3723,2.10637,3.51489,2.16723,0.0093862,0.0093862,0.0093862
64,1975.31,1.70494,2.0312,1.72613,0.5446,0.54828,0.5729,0.34781,2.18312,2.95821,2.22275,0.0093763,0.0093763,0.0093763
65,2006.76,1.76029,2.07565,1.82239,0.68439,0.664,0.68646,0.42555,1.97151,2.46188,2.06572,0.0093664,0.0093664,0.0093664
66,2037.79,1.77601,2.12044,1.7961,0.66993,0.56461,0.64771,0.42386,1.95281,2.62522,2.05802,0.0093565,0.0093565,0.0093565
67,2069.4,1.74463,2.0228,1.79756,0.65292,0.65017,0.67845,0.42438,1.99285,2.39774,2.07101,0.0093466,0.0093466,0.0093466
68,2100.6,1.71478,2.01086,1.75777,0.6551,0.61315,0.66482,0.42935,1.95567,2.65237,2.06196,0.0093367,0.0093367,0.0093367
69,2131.65,1.63584,1.88907,1.69358,0.71733,0.60653,0.69224,0.44323,1.95981,2.30105,2.06106,0.0093268,0.0093268,0.0093268
70,2162.02,1.72051,2.04873,1.77628,0.65249,0.61395,0.66324,0.4259,1.93983,2.41967,2.05242,0.0093169,0.0093169,0.0093169
71,2192.89,1.76786,2.04439,1.84533,0.67327,0.64307,0.65415,0.42308,1.98153,2.79006,2.10905,0.009307,0.009307,0.009307
72,2224.13,1.71305,2.07611,1.79724,0.63173,0.73438,0.72691,0.46752,1.91868,2.25964,2.00855,0.0092971,0.0092971,0.0092971
73,2257.71,1.73477,1.96634,1.77488,0.69453,0.65354,0.6967,0.43337,2.02486,2.36749,2.12102,0.0092872,0.0092872,0.0092872
74,2290.59,1.7476,2.03874,1.86815,0.63041,0.74416,0.74136,0.49011,1.90481,2.19541,1.99289,0.0092773,0.0092773,0.0092773
75,2321.78,1.65999,2.04063,1.76478,0.69578,0.67056,0.72423,0.46534,1.91106,2.29585,1.9911,0.0092674,0.0092674,0.0092674
76,2352.45,1.71493,1.97689,1.79447,0.65374,0.68989,0.7028,0.42477,1.99132,2.33827,2.039,0.0092575,0.0092575,0.0092575
77,2383.37,1.66049,1.91938,1.76847,0.67318,0.68889,0.71329,0.45538,1.93249,2.38719,2.04273,0.0092476,0.0092476,0.0092476
78,2414.95,1.70886,1.95003,1.81118,0.70394,0.67585,0.69296,0.44359,1.93599,2.37564,2.03154,0.0092377,0.0092377,0.0092377
79,2446.68,1.71238,1.99505,1.79231,0.70405,0.63295,0.68462,0.43914,1.96196,2.43182,2.04908,0.0092278,0.0092278,0.0092278
80,2476.77,1.66636,1.86386,1.74769,0.70921,0.66345,0.70417,0.45188,1.93766,2.25578,2.0256,0.0092179,0.0092179,0.0092179
81,2507.6,1.71782,2.01262,1.77357,0.73055,0.62686,0.7027,0.45086,1.94037,2.38371,2.0403,0.009208,0.009208,0.009208
82,2537.83,1.62,1.8416,1.68444,0.67561,0.71262,0.71927,0.46371,1.91601,2.29262,2.02476,0.0091981,0.0091981,0.0091981
83,2568.1,1.67571,1.91123,1.70594,0.66582,0.72626,0.7469,0.47277,1.91646,2.07693,2.00694,0.0091882,0.0091882,0.0091882
84,2598.26,1.65599,1.83049,1.7356,0.69185,0.66831,0.71046,0.46033,1.90924,2.30259,2.00811,0.0091783,0.0091783,0.0091783
85,2628.91,1.69053,1.84541,1.77721,0.77288,0.69375,0.74554,0.46174,1.93066,2.17661,2.03669,0.0091684,0.0091684,0.0091684
86,2660.32,1.63021,1.7566,1.71157,0.69981,0.71577,0.75051,0.47943,1.91417,2.10722,2.01435,0.0091585,0.0091585,0.0091585
87,2691.08,1.65175,1.90702,1.7437,0.66101,0.66719,0.69266,0.44423,1.98793,2.41698,2.08751,0.0091486,0.0091486,0.0091486
88,2722.04,1.68427,1.85181,1.78147,0.74041,0.71377,0.7463,0.47813,1.8689,2.02687,1.96926,0.0091387,0.0091387,0.0091387
89,2752.26,1.63119,1.73594,1.71096,0.69832,0.63207,0.67622,0.44232,1.93447,2.50703,2.0412,0.0091288,0.0091288,0.0091288
90,2783.46,1.62372,1.8655,1.6972,0.70097,0.69899,0.73202,0.4677,1.94298,2.15119,2.05042,0.0091189,0.0091189,0.0091189
91,2814.45,1.65209,1.90352,1.79287,0.68437,0.64718,0.69585,0.46175,1.94045,2.37982,2.03768,0.009109,0.009109,0.009109
92,2845.46,1.59033,1.74556,1.66551,0.62478,0.77079,0.73172,0.47772,1.88385,2.07265,1.95217,0.0090991,0.0090991,0.0090991
93,2876.24,1.60442,1.86284,1.69678,0.66894,0.68727,0.70827,0.4652,1.86558,2.20822,1.94664,0.0090892,0.0090892,0.0090892
94,2907.38,1.6176,1.83018,1.69363,0.65558,0.67135,0.68921,0.4428,1.92617,2.11606,2.02405,0.0090793,0.0090793,0.0090793
95,2937.9,1.60348,1.73399,1.70397,0.71671,0.69558,0.72871,0.47204,1.88481,2.05911,2.00175,0.0090694,0.0090694,0.0090694
96,2969.03,1.64315,1.75424,1.72109,0.6732,0.76293,0.75839,0.48757,1.93489,2.04088,2.01103,0.0090595,0.0090595,0.0090595
97,3000.25,1.63158,1.75773,1.7439,0.74801,0.58791,0.66285,0.42592,2.10341,2.84418,2.19788,0.0090496,0.0090496,0.0090496
98,3030.9,1.56733,1.76075,1.68401,0.70804,0.70863,0.72991,0.46971,1.9423,2.19624,2.03908,0.0090397,0.0090397,0.0090397
99,3061.9,1.67118,1.87264,1.73166,0.65928,0.68622,0.71323,0.4619,1.95344,2.32495,2.0202,0.0090298,0.0090298,0.0090298
100,3093.28,1.6578,1.76768,1.70158,0.65995,0.75095,0.75439,0.47966,1.89181,2.00972,1.98113,0.0090199,0.0090199,0.0090199
101,3124.28,1.67294,1.82137,1.75561,0.6728,0.71835,0.72477,0.46535,1.89329,2.10559,1.96997,0.00901,0.00901,0.00901
102,3155.34,1.6344,1.75931,1.7498,0.68762,0.73431,0.74652,0.47343,1.90751,2.12601,1.99317,0.0090001,0.0090001,0.0090001
103,3185.57,1.6012,1.72405,1.70126,0.6988,0.71892,0.7427,0.47474,1.89237,2.02244,2.00033,0.0089902,0.0089902,0.0089902
104,3215.96,1.67225,1.89161,1.77791,0.69721,0.7528,0.75713,0.47756,1.97322,2.06667,2.06217,0.0089803,0.0089803,0.0089803
105,3248.35,1.60898,1.74546,1.74248,0.69214,0.75715,0.77421,0.48923,1.88532,2.02793,2.0021,0.0089704,0.0089704,0.0089704
106,3278.92,1.57215,1.73317,1.6791,0.73579,0.69373,0.74712,0.48593,1.89157,2.19439,2.00705,0.0089605,0.0089605,0.0089605
107,3309.67,1.65866,1.74319,1.78319,0.69793,0.7058,0.73758,0.47067,1.91284,2.14136,1.99853,0.0089506,0.0089506,0.0089506
108,3341.22,1.6409,1.80083,1.78682,0.62094,0.73029,0.7105,0.46102,1.94457,2.21369,2.05021,0.0089407,0.0089407,0.0089407
109,3372.16,1.63055,1.79766,1.76275,0.71753,0.68819,0.74995,0.47348,1.9128,2.0163,1.9998,0.0089308,0.0089308,0.0089308
110,3402.67,1.58359,1.63488,1.63558,0.73165,0.70983,0.74639,0.48588,1.88987,2.05689,1.99256,0.0089209,0.0089209,0.0089209
111,3433.42,1.54491,1.67577,1.65672,0.74444,0.7028,0.74363,0.48243,1.93855,2.12785,2.01551,0.008911,0.008911,0.008911
112,3463.69,1.57232,1.71179,1.70476,0.66259,0.73669,0.73286,0.47466,1.88714,2.17065,2.00547,0.0089011,0.0089011,0.0089011
113,3493.99,1.5494,1.63051,1.69414,0.75052,0.65764,0.74657,0.49149,1.89494,2.09169,2.02276,0.0088912,0.0088912,0.0088912
114,3525.35,1.60578,1.80617,1.72276,0.75063,0.72429,0.77702,0.50198,1.87324,2.06979,2.00217,0.0088813,0.0088813,0.0088813
115,3556.85,1.63476,1.8233,1.725,0.75913,0.69978,0.76841,0.49045,1.89908,2.0631,1.99536,0.0088714,0.0088714,0.0088714
116,3587.86,1.61478,1.67594,1.69749,0.69546,0.79037,0.77589,0.49685,1.84725,1.91031,1.95434,0.0088615,0.0088615,0.0088615
117,3618.24,1.562,1.63893,1.71007,0.77191,0.66477,0.75118,0.47698,1.89677,2.00725,1.99426,0.0088516,0.0088516,0.0088516
118,3648.74,1.60122,1.69165,1.69373,0.70796,0.75649,0.76426,0.48445,1.87769,1.96904,1.96543,0.0088417,0.0088417,0.0088417
119,3679.17,1.52448,1.62477,1.67566,0.7176,0.72054,0.75114,0.48312,1.86382,2.1011,1.98374,0.0088318,0.0088318,0.0088318
120,3710.4,1.59228,1.74581,1.68931,0.73173,0.74726,0.75814,0.49304,1.8737,1.90381,1.9628,0.0088219,0.0088219,0.0088219
121,3741.8,1.52164,1.68262,1.68659,0.69812,0.7459,0.74733,0.48158,1.87815,1.96184,1.98716,0.008812,0.008812,0.008812
122,3773.09,1.56274,1.65581,1.69288,0.65805,0.74741,0.74103,0.48692,1.90351,2.04182,2.00776,0.0088021,0.0088021,0.0088021
123,3804.71,1.56582,1.68026,1.69251,0.74411,0.74373,0.77496,0.49796,1.88747,2.02576,1.99313,0.0087922,0.0087922,0.0087922
124,3836.07,1.63038,1.72226,1.70713,0.69002,0.76629,0.75568,0.4868,1.93811,2.03235,2.03204,0.0087823,0.0087823,0.0087823
125,3866.48,1.53718,1.58726,1.68665,0.67342,0.76326,0.76083,0.48635,1.89367,2.03137,2.00702,0.0087724,0.0087724,0.0087724
126,3897.84,1.52791,1.59694,1.70075,0.70927,0.75116,0.7625,0.49619,1.86037,1.91145,1.99687,0.0087625,0.0087625,0.0087625
127,3929.23,1.52711,1.51207,1.68549,0.71511,0.66365,0.70371,0.44721,1.92537,2.10992,2.03695,0.0087526,0.0087526,0.0087526
128,3960.29,1.60066,1.6233,1.6994,0.68199,0.76917,0.7424,0.47616,1.86428,2.00035,1.96745,0.0087427,0.0087427,0.0087427
129,3991.46,1.48425,1.64257,1.62917,0.71194,0.71953,0.75503,0.48922,1.89277,1.96905,1.99971,0.0087328,0.0087328,0.0087328
130,4022.59,1.49591,1.60587,1.65544,0.75048,0.7725,0.77548,0.4979,1.86874,1.93635,1.97436,0.0087229,0.0087229,0.0087229
131,4052.89,1.57657,1.62735,1.68638,0.77483,0.71497,0.76046,0.48619,1.91064,1.99341,2.03471,0.008713,0.008713,0.008713
132,4084.18,1.51229,1.55421,1.65411,0.77594,0.68834,0.74119,0.49359,1.87433,2.04587,1.98123,0.0087031,0.0087031,0.0087031
133,4115.5,1.57072,1.62683,1.64384,0.7475,0.72255,0.76225,0.49354,1.88699,1.9553,1.97595,0.0086932,0.0086932,0.0086932
134,4146.58,1.54797,1.59118,1.67107,0.75001,0.71998,0.75556,0.47706,1.89069,1.98105,2.00277,0.0086833,0.0086833,0.0086833
135,4177.94,1.52704,1.5953,1.66378,0.72931,0.68673,0.74635,0.47547,1.86982,2.08823,1.96654,0.0086734,0.0086734,0.0086734
136,4208.9,1.4893,1.60814,1.6778,0.73487,0.72543,0.76179,0.48995,1.8754,1.89028,1.98092,0.0086635,0.0086635,0.0086635
137,4240.16,1.53343,1.6022,1.66604,0.7228,0.76887,0.76916,0.50187,1.84482,1.84397,1.96968,0.0086536,0.0086536,0.0086536
138,4271.44,1.49143,1.61872,1.67365,0.74242,0.75688,0.77451,0.50577,1.8628,1.8409,1.98261,0.0086437,0.0086437,0.0086437
139,4302.82,1.51472,1.54374,1.66483,0.78992,0.61836,0.71627,0.46596,1.90419,2.20122,2.03213,0.0086338,0.0086338,0.0086338
140,4333.29,1.56464,1.67301,1.6978,0.7501,0.68768,0.74966,0.48972,1.84634,1.97314,1.9748,0.0086239,0.0086239,0.0086239
141,4363.86,1.54989,1.63095,1.6786,0.77353,0.71713,0.77342,0.48928,1.90894,1.9425,2.0074,0.008614,0.008614,0.008614
142,4394.71,1.50495,1.55003,1.65713,0.72907,0.78711,0.78698,0.51538,1.85967,1.92384,1.95335,0.0086041,0.0086041,0.0086041
143,4425.94,1.49654,1.56361,1.62185,0.78189,0.71634,0.77689,0.50203,1.8531,2.0401,1.94712,0.0085942,0.0085942,0.0085942
144,4457.35,1.47004,1.51486,1.6262,0.70494,0.79473,0.76884,0.4964,1.86085,1.91598,1.97934,0.0085843,0.0085843,0.0085843
145,4488.51,1.46367,1.52509,1.63242,0.73485,0.75239,0.77186,0.50086,1.86819,1.87848,1.97314,0.0085744,0.0085744,0.0085744
146,4519.43,1.47084,1.54345,1.63811,0.71846,0.74035,0.7609,0.48972,1.87231,1.87854,1.97234,0.0085645,0.0085645,0.0085645
147,4550.17,1.49373,1.59394,1.62908,0.74348,0.71685,0.75089,0.4892,1.88174,1.92687,1.97843,0.0085546,0.0085546,0.0085546
148,4581.33,1.46801,1.53394,1.62238,0.69848,0.81228,0.78104,0.50422,1.83227,1.89914,1.93102,0.0085447,0.0085447,0.0085447
149,4612.45,1.5052,1.50409,1.62337,0.72209,0.78195,0.77867,0.49525,1.8599,1.86737,1.98748,0.0085348,0.0085348,0.0085348
150,4642.85,1.44902,1.46299,1.57813,0.72811,0.74532,0.78403,0.50516,1.86042,1.87099,1.95547,0.0085249,0.0085249,0.0085249
151,4673.45,1.47732,1.47856,1.59758,0.74506,0.74998,0.78561,0.5037,1.857,1.89689,1.95507,0.008515,0.008515,0.008515
152,4704.7,1.52313,1.51859,1.6303,0.76068,0.73163,0.77934,0.50076,1.8826,1.98434,1.99611,0.0085051,0.0085051,0.0085051
153,4734.85,1.50034,1.55807,1.64271,0.72049,0.79073,0.77647,0.50216,1.86032,1.91405,1.96286,0.0084952,0.0084952,0.0084952
154,4768.5,1.52433,1.52028,1.61059,0.7644,0.70732,0.77444,0.49535,1.88475,1.93922,1.96815,0.0084853,0.0084853,0.0084853
155,4800.08,1.50003,1.54511,1.62772,0.71943,0.76873,0.78306,0.50526,1.87223,1.86043,1.96608,0.0084754,0.0084754,0.0084754
156,4831.48,1.46801,1.57109,1.62173,0.74778,0.73076,0.76829,0.48921,1.88858,1.95747,1.9818,0.0084655,0.0084655,0.0084655
157,4862.88,1.48143,1.54908,1.62293,0.67532,0.77128,0.76963,0.49462,1.8701,1.87523,1.9747,0.0084556,0.0084556,0.0084556
158,4893.69,1.50796,1.52131,1.6155,0.74948,0.72635,0.76733,0.50152,1.84082,1.91005,1.94933,0.0084457,0.0084457,0.0084457
159,4924.79,1.47093,1.43212,1.61213,0.69829,0.78836,0.78017,0.50218,1.87664,1.86978,1.98285,0.0084358,0.0084358,0.0084358
160,4955.79,1.46021,1.50466,1.60093,0.7477,0.73738,0.7673,0.50665,1.84484,1.94283,1.9651,0.0084259,0.0084259,0.0084259
161,4986.97,1.48612,1.56605,1.64446,0.71931,0.80519,0.79376,0.51549,1.83831,1.8834,1.97741,0.008416,0.008416,0.008416
162,5018.17,1.45565,1.49378,1.614,0.80067,0.71541,0.79184,0.51521,1.8346,1.91524,1.94346,0.0084061,0.0084061,0.0084061
163,5049.32,1.48986,1.53316,1.63445,0.77194,0.72887,0.78476,0.51452,1.84588,1.91639,1.96179,0.0083962,0.0083962,0.0083962
164,5081.06,1.44679,1.4472,1.61446,0.76972,0.74023,0.78661,0.51531,1.85089,1.8995,1.99156,0.0083863,0.0083863,0.0083863
165,5112.41,1.46961,1.49509,1.66838,0.73123,0.78224,0.78798,0.5087,1.86241,1.95185,2.00957,0.0083764,0.0083764,0.0083764
166,5142.7,1.43942,1.48146,1.62191,0.76552,0.75013,0.78655,0.50457,1.84598,1.86193,1.96788,0.0083665,0.0083665,0.0083665
167,5174.06,1.44945,1.57198,1.63458,0.75442,0.72243,0.76256,0.49343,1.87835,1.94129,1.97724,0.0083566,0.0083566,0.0083566
168,5205.38,1.461,1.48094,1.60827,0.76099,0.75153,0.79177,0.51045,1.88137,1.88459,1.96118,0.0083467,0.0083467,0.0083467
169,5235.66,1.45146,1.47497,1.61302,0.77255,0.73058,0.78033,0.4985,1.89142,1.89338,1.98194,0.0083368,0.0083368,0.0083368
170,5267.08,1.52846,1.59264,1.66069,0.74249,0.73669,0.77524,0.4999,1.84125,1.91202,1.95036,0.0083269,0.0083269,0.0083269
171,5297.46,1.46324,1.47038,1.63683,0.73238,0.74624,0.7766,0.49647,1.85382,1.90369,1.96056,0.008317,0.008317,0.008317
172,5328.22,1.42227,1.39554,1.57272,0.74177,0.75839,0.7828,0.49399,1.84633,1.93177,1.95304,0.0083071,0.0083071,0.0083071
173,5359.43,1.38575,1.48044,1.56661,0.71667,0.80444,0.78661,0.50073,1.86349,1.87811,1.99063,0.0082972,0.0082972,0.0082972
174,5389.54,1.45477,1.47128,1.63922,0.73741,0.78007,0.78863,0.50139,1.86574,1.91012,1.98407,0.0082873,0.0082873,0.0082873
175,5420.3,1.44559,1.4842,1.60311,0.70737,0.81579,0.78821,0.50486,1.89997,1.93832,2.01136,0.0082774,0.0082774,0.0082774
176,5451.5,1.42252,1.51095,1.59501,0.7569,0.74881,0.78472,0.51244,1.86509,1.91201,1.96233,0.0082675,0.0082675,0.0082675
177,5481.79,1.46623,1.535,1.61428,0.71725,0.7852,0.77582,0.50525,1.84652,1.88082,1.99229,0.0082576,0.0082576,0.0082576
178,5513.46,1.42992,1.47887,1.60196,0.68047,0.81116,0.76735,0.48607,1.87456,1.90702,1.98009,0.0082477,0.0082477,0.0082477
179,5543.89,1.45059,1.43996,1.63438,0.74857,0.75831,0.79145,0.51219,1.8456,1.85742,1.96571,0.0082378,0.0082378,0.0082378
180,5574.24,1.47166,1.49255,1.5875,0.71326,0.82671,0.796,0.50757,1.87788,1.86213,1.99865,0.0082279,0.0082279,0.0082279
181,5605.72,1.44551,1.4369,1.60446,0.70297,0.80894,0.80245,0.51936,1.8357,1.8095,1.98173,0.008218,0.008218,0.008218
182,5636.73,1.42934,1.43092,1.60836,0.69639,0.81495,0.79303,0.51809,1.82884,1.83271,1.96932,0.0082081,0.0082081,0.0082081
183,5667.63,1.41919,1.4449,1.57803,0.74632,0.74744,0.78443,0.50585,1.83984,1.80941,1.96915,0.0081982,0.0081982,0.0081982
184,5698.08,1.45446,1.50411,1.63176,0.73538,0.75807,0.78317,0.50726,1.87704,1.87511,1.99424,0.0081883,0.0081883,0.0081883
185,5729.3,1.46637,1.41176,1.62054,0.75804,0.78377,0.79895,0.52348,1.82845,1.81186,1.96064,0.0081784,0.0081784,0.0081784
186,5760.61,1.45811,1.39593,1.62133,0.73032,0.80787,0.80093,0.52438,1.85842,1.78786,1.99241,0.0081685,0.0081685,0.0081685
187,5790.97,1.40471,1.45446,1.56272,0.75579,0.74735,0.78792,0.50981,1.87394,1.8223,1.9945,0.0081586,0.0081586,0.0081586
188,5821.51,1.45591,1.44066,1.62186,0.72674,0.77252,0.78652,0.50082,1.90601,1.86003,2.01783,0.0081487,0.0081487,0.0081487
189,5853.07,1.44014,1.45255,1.57646,0.73883,0.78948,0.79556,0.50897,1.87963,1.81432,1.98131,0.0081388,0.0081388,0.0081388
190,5883.92,1.41712,1.45792,1.61791,0.77574,0.75528,0.78237,0.50444,1.87569,1.86456,1.99036,0.0081289,0.0081289,0.0081289
191,5915.25,1.44824,1.45836,1.62822,0.74898,0.77132,0.79236,0.50693,1.87471,1.89262,2.00576,0.008119,0.008119,0.008119
192,5946.57,1.37604,1.48668,1.56894,0.73551,0.75451,0.77331,0.4883,1.89068,1.97901,2.0111,0.0081091,0.0081091,0.0081091
193,5977.56,1.39365,1.43852,1.60433,0.71733,0.77741,0.77645,0.49008,1.90362,1.9199,2.01311,0.0080992,0.0080992,0.0080992
194,6008.11,1.41191,1.51766,1.64054,0.733,0.81802,0.80322,0.51103,1.90483,1.79918,1.99227,0.0080893,0.0080893,0.0080893
195,6039.59,1.43456,1.4733,1.60803,0.76201,0.77377,0.80261,0.51379,1.87389,1.78638,1.98705,0.0080794,0.0080794,0.0080794
196,6070.41,1.43379,1.40601,1.63871,0.76562,0.74367,0.79528,0.50972,1.89246,1.87604,1.99095,0.0080695,0.0080695,0.0080695
197,6101.61,1.38223,1.31433,1.57488,0.71137,0.78758,0.78347,0.4981,1.89329,1.89994,1.99732,0.0080596,0.0080596,0.0080596
198,6133.19,1.39127,1.38365,1.55506,0.76971,0.7515,0.78792,0.50531,1.87821,1.84589,1.98293,0.0080497,0.0080497,0.0080497
199,6165.12,1.39812,1.40901,1.57171,0.76145,0.74233,0.78824,0.50664,1.86096,1.82841,1.97268,0.0080398,0.0080398,0.0080398
200,6196.32,1.3978,1.40969,1.61055,0.74252,0.78108,0.79605,0.51138,1.87618,1.8384,2.028,0.0080299,0.0080299,0.0080299
201,6226.88,1.37826,1.42356,1.59497,0.71569,0.8032,0.79103,0.50883,1.88273,1.86125,1.99345,0.00802,0.00802,0.00802
202,6258.04,1.36184,1.33342,1.5504,0.70665,0.81981,0.79758,0.50904,1.86493,1.81655,1.96661,0.0080101,0.0080101,0.0080101
203,6288.99,1.40402,1.44028,1.57008,0.77986,0.74293,0.78497,0.50064,1.86142,1.83736,1.97048,0.0080002,0.0080002,0.0080002
204,6319.37,1.39505,1.4694,1.58551,0.72915,0.79159,0.78861,0.50356,1.88524,1.81101,1.99346,0.0079903,0.0079903,0.0079903
205,6350.75,1.46044,1.4745,1.66535,0.70514,0.81684,0.79779,0.5142,1.88208,1.79558,2.00225,0.0079804,0.0079804,0.0079804
206,6382.01,1.4156,1.44975,1.58607,0.78681,0.74715,0.7961,0.51114,1.89506,1.76191,1.99964,0.0079705,0.0079705,0.0079705
207,6413.25,1.40198,1.38031,1.58511,0.76683,0.75493,0.79861,0.50469,1.89332,1.82835,2.00264,0.0079606,0.0079606,0.0079606
208,6443.58,1.37155,1.3687,1.5618,0.73082,0.76219,0.7832,0.50785,1.85987,1.82664,1.98109,0.0079507,0.0079507,0.0079507
209,6473.74,1.36415,1.3385,1.54021,0.73908,0.77753,0.78557,0.50559,1.88668,1.81253,2.00304,0.0079408,0.0079408,0.0079408
210,6504.45,1.43441,1.48365,1.60797,0.71263,0.79616,0.78753,0.50565,1.88882,1.79205,2.00785,0.0079309,0.0079309,0.0079309
211,6535.82,1.3549,1.31849,1.55589,0.77343,0.72187,0.78819,0.50439,1.8869,1.83307,2.02005,0.007921,0.007921,0.007921
212,6566.11,1.39904,1.3698,1.57714,0.78025,0.72739,0.77473,0.49871,1.88037,1.82,2.01155,0.0079111,0.0079111,0.0079111
213,6597.02,1.37336,1.37969,1.56967,0.71577,0.7997,0.78069,0.50487,1.85017,1.82695,1.99262,0.0079012,0.0079012,0.0079012
214,6628.38,1.40464,1.38286,1.60293,0.74176,0.7563,0.78152,0.50114,1.858,1.87249,1.99824,0.0078913,0.0078913,0.0078913
215,6659.09,1.43897,1.44174,1.62567,0.7286,0.7848,0.78406,0.5019,1.85397,1.86847,1.98587,0.0078814,0.0078814,0.0078814
216,6690.72,1.39386,1.40505,1.59005,0.74726,0.7728,0.77963,0.50517,1.84393,1.85844,1.98698,0.0078715,0.0078715,0.0078715
217,6722.09,1.46789,1.44066,1.5838,0.7419,0.77718,0.79181,0.51106,1.88722,1.83351,2.00446,0.0078616,0.0078616,0.0078616
218,6752.29,1.4121,1.3761,1.61803,0.73666,0.80345,0.80413,0.51342,1.86395,1.82779,1.98842,0.0078517,0.0078517,0.0078517
219,6782.86,1.35294,1.40728,1.57101,0.7192,0.78435,0.79308,0.50938,1.8384,1.82863,1.96376,0.0078418,0.0078418,0.0078418
220,6814,1.35249,1.40875,1.53643,0.69848,0.84489,0.80215,0.51659,1.84795,1.84425,1.98126,0.0078319,0.0078319,0.0078319
221,6844.29,1.32866,1.30062,1.53015,0.69067,0.8325,0.78585,0.51292,1.83106,1.8192,1.96816,0.007822,0.007822,0.007822
222,6875.98,1.31121,1.29356,1.50207,0.79209,0.75261,0.78974,0.51315,1.84265,1.79525,1.98626,0.0078121,0.0078121,0.0078121
223,6906.78,1.40781,1.43706,1.58275,0.77502,0.75782,0.79558,0.5176,1.86127,1.80607,2.02059,0.0078022,0.0078022,0.0078022
224,6937.08,1.34159,1.37074,1.56666,0.73023,0.80505,0.80049,0.51108,1.85804,1.77945,2.01451,0.0077923,0.0077923,0.0077923
225,6967.29,1.39892,1.42924,1.55977,0.73949,0.78366,0.79544,0.50093,1.87679,1.82318,2.014,0.0077824,0.0077824,0.0077824
226,6997.85,1.41408,1.48925,1.60738,0.76862,0.75722,0.79724,0.49301,1.89524,1.86824,2.02922,0.0077725,0.0077725,0.0077725
227,7028.51,1.35494,1.35136,1.55596,0.73849,0.77784,0.78728,0.49192,1.87707,1.85852,2.00699,0.0077626,0.0077626,0.0077626
228,7059.1,1.37457,1.43431,1.57353,0.79814,0.73889,0.80098,0.51148,1.8532,1.8222,1.978,0.0077527,0.0077527,0.0077527
229,7091.54,1.28382,1.30039,1.55923,0.76775,0.75083,0.79185,0.50871,1.87064,1.83077,1.99713,0.0077428,0.0077428,0.0077428
230,7122.83,1.34263,1.35433,1.51377,0.74366,0.76113,0.78589,0.50202,1.87723,1.85617,2.01213,0.0077329,0.0077329,0.0077329
231,7153.57,1.41842,1.4309,1.61452,0.72568,0.75672,0.78323,0.50095,1.8725,1.86092,1.99634,0.007723,0.007723,0.007723
232,7183.82,1.36769,1.3711,1.57387,0.71708,0.77716,0.78062,0.49815,1.88696,1.84419,2.00582,0.0077131,0.0077131,0.0077131
233,7214.09,1.39209,1.38441,1.57156,0.77225,0.76585,0.78379,0.49866,1.8983,1.84585,2.03706,0.0077032,0.0077032,0.0077032
234,7245.38,1.34083,1.33675,1.5404,0.69746,0.80245,0.77988,0.49919,1.90138,1.8748,2.02817,0.0076933,0.0076933,0.0076933
235,7275.56,1.36335,1.33588,1.55218,0.71549,0.78998,0.78872,0.50245,1.88339,1.85198,2.02777,0.0076834,0.0076834,0.0076834
236,7305.81,1.3641,1.35757,1.56591,0.69239,0.77623,0.76649,0.48599,1.89624,1.9539,2.02361,0.0076735,0.0076735,0.0076735
237,7336.19,1.35436,1.32474,1.59697,0.71611,0.7771,0.78314,0.49473,1.86557,1.85773,1.9994,0.0076636,0.0076636,0.0076636
238,7366.75,1.34326,1.3424,1.56875,0.78392,0.71846,0.78296,0.50194,1.8805,1.86653,2.01266,0.0076537,0.0076537,0.0076537
239,7398.04,1.31612,1.25352,1.52702,0.72559,0.79226,0.79662,0.51214,1.86754,1.83768,2.02138,0.0076438,0.0076438,0.0076438
240,7428.26,1.37305,1.33916,1.57145,0.73635,0.79863,0.80229,0.51035,1.88324,1.80783,2.03177,0.0076339,0.0076339,0.0076339
241,7459.34,1.38381,1.33095,1.57235,0.74123,0.78124,0.79115,0.50013,1.89903,1.8541,2.03794,0.007624,0.007624,0.007624
242,7490.62,1.27651,1.23486,1.52293,0.71406,0.80159,0.78762,0.49912,1.88472,1.85787,2.00422,0.0076141,0.0076141,0.0076141
243,7521.79,1.32342,1.32334,1.52738,0.76319,0.76578,0.78052,0.49561,1.86613,1.80354,2.00291,0.0076042,0.0076042,0.0076042
244,7551.96,1.31785,1.35072,1.54487,0.75047,0.79451,0.7846,0.50865,1.86686,1.77985,1.98725,0.0075943,0.0075943,0.0075943
245,7582.95,1.34047,1.34383,1.53865,0.76897,0.77745,0.7819,0.49303,1.8958,1.8233,2.01125,0.0075844,0.0075844,0.0075844
246,7614.21,1.3612,1.30977,1.57192,0.7899,0.7597,0.79477,0.50718,1.89397,1.80901,2.00814,0.0075745,0.0075745,0.0075745
247,7646.47,1.31136,1.25639,1.55022,0.77363,0.78328,0.80394,0.5112,1.88432,1.80132,2.01782,0.0075646,0.0075646,0.0075646
248,7676.86,1.32063,1.37678,1.51204,0.76068,0.77319,0.79741,0.51053,1.88153,1.85388,2.03466,0.0075547,0.0075547,0.0075547
249,7708.13,1.3414,1.41538,1.57625,0.75163,0.79398,0.79598,0.5108,1.87337,1.82247,2.00039,0.0075448,0.0075448,0.0075448
250,7739.23,1.28849,1.31163,1.5202,0.71309,0.79376,0.78908,0.50365,1.86068,1.81913,2.00235,0.0075349,0.0075349,0.0075349
251,7770.69,1.31329,1.33675,1.51889,0.73782,0.75728,0.7801,0.50229,1.87895,1.82713,2.00793,0.007525,0.007525,0.007525
252,7801.9,1.31962,1.33687,1.52224,0.7485,0.74881,0.78566,0.50108,1.88629,1.85088,2.01449,0.0075151,0.0075151,0.0075151
253,7832.92,1.29976,1.31806,1.52098,0.75775,0.7519,0.78156,0.4991,1.87684,1.8661,2.00071,0.0075052,0.0075052,0.0075052
254,7863.8,1.36402,1.34311,1.5315,0.78983,0.74318,0.79959,0.5036,1.8907,1.8145,2.01925,0.0074953,0.0074953,0.0074953
255,7894.32,1.34314,1.28229,1.55558,0.74333,0.80155,0.79658,0.49802,1.88686,1.86155,2.01928,0.0074854,0.0074854,0.0074854
256,7925.65,1.3108,1.34632,1.52364,0.74626,0.78813,0.78437,0.49769,1.8857,1.86569,2.01598,0.0074755,0.0074755,0.0074755
257,7956.68,1.34144,1.2844,1.52146,0.76684,0.74397,0.77765,0.48472,1.89212,1.8519,2.01397,0.0074656,0.0074656,0.0074656
258,7988.21,1.33098,1.27143,1.53412,0.77347,0.7373,0.79158,0.5041,1.88172,1.85369,2.00543,0.0074557,0.0074557,0.0074557
259,8019.41,1.32511,1.29295,1.5559,0.75603,0.75849,0.78206,0.49596,1.89785,1.84434,2.0217,0.0074458,0.0074458,0.0074458
260,8050.57,1.35256,1.39022,1.57933,0.78791,0.72759,0.78058,0.49683,1.89063,1.871,2.00385,0.0074359,0.0074359,0.0074359
261,8081.68,1.29827,1.30042,1.50854,0.77926,0.72364,0.78872,0.49994,1.88572,1.87477,1.99923,0.007426,0.007426,0.007426
262,8112.69,1.36214,1.29992,1.5622,0.74028,0.77164,0.78006,0.50001,1.87549,1.8755,2.00933,0.0074161,0.0074161,0.0074161
263,8143.64,1.32336,1.35218,1.56708,0.76511,0.72485,0.76353,0.48515,1.8871,1.89397,2.01978,0.0074062,0.0074062,0.0074062
264,8173.58,1.32982,1.30385,1.54341,0.71743,0.78949,0.79074,0.50152,1.88745,1.87516,2.02503,0.0073963,0.0073963,0.0073963
265,8205.47,1.33302,1.31361,1.52622,0.74308,0.7734,0.79089,0.5062,1.88177,1.83128,2.00434,0.0073864,0.0073864,0.0073864
266,8236.32,1.27243,1.24497,1.53358,0.69958,0.82427,0.79968,0.50884,1.90279,1.84324,2.0135,0.0073765,0.0073765,0.0073765
267,8267.4,1.35763,1.29812,1.56612,0.73722,0.78238,0.79639,0.50407,1.90429,1.84526,2.01613,0.0073666,0.0073666,0.0073666
268,8298.93,1.3437,1.30155,1.58098,0.7847,0.73738,0.79135,0.50559,1.89435,1.87289,2.00952,0.0073567,0.0073567,0.0073567
269,8329.98,1.3063,1.42414,1.5783,0.81743,0.71995,0.79006,0.50254,1.87544,1.88012,2.00831,0.0073468,0.0073468,0.0073468
270,8360.36,1.28969,1.18677,1.48852,0.69495,0.81894,0.79355,0.50947,1.87664,1.90455,2.01071,0.0073369,0.0073369,0.0073369
271,8391.47,1.28901,1.29141,1.50667,0.72566,0.7933,0.78909,0.50995,1.89353,1.84744,2.02184,0.007327,0.007327,0.007327
272,8422.48,1.32632,1.25565,1.51711,0.70888,0.78606,0.78496,0.5027,1.8862,1.86233,2.01203,0.0073171,0.0073171,0.0073171
273,8452.94,1.34569,1.33813,1.53302,0.71535,0.77279,0.77878,0.49702,1.88851,1.88303,2.01962,0.0073072,0.0073072,0.0073072
274,8484.79,1.2784,1.20828,1.53208,0.77289,0.71763,0.78208,0.49696,1.90551,1.89529,2.04122,0.0072973,0.0072973,0.0072973
275,8514.98,1.31459,1.25852,1.56784,0.79303,0.71626,0.7839,0.49958,1.89585,1.88788,2.03789,0.0072874,0.0072874,0.0072874
276,8546.06,1.33196,1.30872,1.53426,0.7222,0.79152,0.80243,0.51485,1.89087,1.85667,2.04239,0.0072775,0.0072775,0.0072775
277,8577.19,1.29867,1.26053,1.51041,0.77333,0.73167,0.80539,0.51495,1.89041,1.8466,2.04252,0.0072676,0.0072676,0.0072676
278,8608.43,1.36301,1.33282,1.591,0.69868,0.83003,0.80126,0.51458,1.89361,1.83562,2.0391,0.0072577,0.0072577,0.0072577
279,8639.82,1.35098,1.33449,1.54524,0.76899,0.73993,0.78184,0.49503,1.90151,1.87411,2.0455,0.0072478,0.0072478,0.0072478
280,8670,1.32584,1.29196,1.52019,0.76437,0.75139,0.77797,0.49019,1.90368,1.86155,2.04282,0.0072379,0.0072379,0.0072379
281,8701.14,1.25966,1.24701,1.50923,0.78866,0.71873,0.78173,0.49432,1.88847,1.83457,2.00531,0.007228,0.007228,0.007228
282,8732.62,1.30531,1.35026,1.55338,0.73873,0.78147,0.78801,0.49594,1.88064,1.80344,2.00937,0.0072181,0.0072181,0.0072181
283,8762.84,1.32977,1.28659,1.55365,0.7611,0.78243,0.80189,0.51364,1.90118,1.82013,2.03183,0.0072082,0.0072082,0.0072082
284,8793.71,1.27986,1.25652,1.52344,0.76456,0.77161,0.79176,0.50909,1.89173,1.80953,2.02596,0.0071983,0.0071983,0.0071983
285,8823.99,1.3076,1.27043,1.53276,0.76566,0.77163,0.79709,0.50885,1.88561,1.81381,2.01843,0.0071884,0.0071884,0.0071884
286,8855.2,1.27702,1.25344,1.50884,0.76235,0.78627,0.79396,0.51422,1.87442,1.82113,2.01733,0.0071785,0.0071785,0.0071785

BIN
app/model/Floating/train4/results.png View File

Before After
Width: 2400  |  Height: 1200  |  Size: 276 KiB

BIN
app/model/Floating/train4/train_batch0.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 442 KiB

BIN
app/model/Floating/train4/train_batch1.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 542 KiB

BIN
app/model/Floating/train4/train_batch2.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 563 KiB

BIN
app/model/Floating/train4/val_batch0_labels.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 415 KiB

BIN
app/model/Floating/train4/val_batch0_pred.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 420 KiB

BIN
app/model/Floating/train4/val_batch1_labels.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 836 KiB

BIN
app/model/Floating/train4/val_batch1_pred.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 841 KiB

BIN
app/model/Floating/train4/val_batch2_labels.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 645 KiB

BIN
app/model/Floating/train4/val_batch2_pred.jpg View File

Before After
Width: 1920  |  Height: 1920  |  Size: 647 KiB

BIN
app/model/Floating/train4/weights/best.pt View File


BIN
app/model/Floating/train4/weights/last.pt View File


BIN
app/model/gate_model/best.pt View File


BIN
app/model/shore_garbage_model/best.pt View File


BIN
app/model/water_gauge_model/best.pt View File


+ 51
- 0
app/model_registry.py View File

@ -0,0 +1,51 @@
import os
from functools import lru_cache
from typing import Iterator, Optional, Tuple
from ultralytics import YOLO
MODEL_MAP = {
"floating": "model/Floating/best.pt",
"gate": "model/gate_model/best.pt",
"shore_garbage": "model/shore_garbage_model/best.pt",
"water_gauge": "model/water_gauge_model/best.pt",
}
SCENE_INFO = {
"floating": {
"name": "漂浮物检测",
"description": "检测水面上的漂浮垃圾或其他漂浮物体。",
},
"gate": {
"name": "闸口场景检测",
"description": "检测闸口区域周边的目标和异常情况。",
},
"shore_garbage": {
"name": "岸边垃圾检测",
"description": "检测岸线附近堆积或散落的垃圾。",
},
"water_gauge": {
"name": "水尺检测",
"description": "检测水位监测场景中的水尺目标。",
},
}
def get_model_path(model_type: str) -> str:
return os.path.join(os.path.dirname(__file__), MODEL_MAP[model_type])
@lru_cache(maxsize=len(MODEL_MAP))
def load_model(model_type: str) -> YOLO:
return YOLO(get_model_path(model_type))
def iter_models(model_type: Optional[str] = None) -> Iterator[Tuple[str, YOLO]]:
if model_type is not None:
yield model_type, load_model(model_type)
return
for current_model_type in MODEL_MAP:
yield current_model_type, load_model(current_model_type)

+ 285
- 0
app/tasks.py View File

@ -0,0 +1,285 @@
import os
# Disable CUDA before torch import to avoid encoding errors in container
#os.environ.setdefault("CUDA_VISIBLE_DEVICES", "")
from typing import Dict, List, Optional
import cv2
import numpy as np
import requests
from celery import Celery
from app.model_registry import MODEL_MAP, iter_models
#REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0")
REDIS_URL = os.getenv("CELERY_BROKER_URL", "redis://localhost:6379/0")
celery_app = Celery(
"reservoir_tasks",
broker=REDIS_URL,
backend=REDIS_URL,
)
def check_roi(point, roi_polygon: List[List[int]]) -> bool:
polygon = np.array(roi_polygon, dtype=np.int32)
return cv2.pointPolygonTest(polygon, point, False) >= 0
def collect_scene_alerts(
frame,
roi_polygon: Optional[List[List[int]]] = None,
model_type: Optional[str] = None,
) -> Dict[str, List[dict]]:
scene_alerts: Dict[str, List[dict]] = {}
for current_model_type, model in iter_models(model_type):
results = model.predict(frame, conf=0.4, verbose=False)
alerts = []
for result in results:
boxes = result.boxes
if boxes is None:
continue
for box in boxes:
cls = int(box.cls[0])
label = model.names[cls]
bbox = box.xyxy[0].cpu().numpy()
center_point = ((bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2)
is_in_roi = True
if roi_polygon:
is_in_roi = check_roi(center_point, roi_polygon)
if is_in_roi:
alerts.append(
{
"label": label,
"confidence": float(box.conf[0]),
"bbox": bbox.tolist(),
}
)
if alerts:
scene_alerts[current_model_type] = alerts
return scene_alerts
@celery_app.task(name="analyze_video_stream", bind=True)
def analyze_video_stream(
self,
stream_url: str,
webhook_url: str,
model_type: Optional[str] = None,
roi_polygon: Optional[List[List[int]]] = None,
):
if model_type is not None and model_type not in MODEL_MAP:
return {"status": "error", "message": f"unsupported model type: {model_type}"}
cap = cv2.VideoCapture(stream_url)
if not cap.isOpened():
return {"status": "error", "message": f"failed to open stream: {stream_url}"}
frame_skip = 10
count = 0
detected_scenes = set()
# 获取视频信息
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) if stream_url.endswith('.mp4') else None
# 更新任务状态
self.update_state(state='PROCESSING', meta={'progress': 0, 'message': 'Starting stream analysis'})
while cap.isOpened():
success, frame = cap.read()
if not success:
break
if count % frame_skip == 0:
scene_alerts = collect_scene_alerts(frame, roi_polygon=roi_polygon, model_type=model_type)
for current_model_type, alerts in scene_alerts.items():
detected_scenes.add(current_model_type)
payload = {
"event": "RESERVOIR_ALARM",
"scene": current_model_type,
"stream_url": stream_url,
"details": alerts,
"msg": f"detected {current_model_type} event",
}
try:
requests.post(webhook_url, json=payload, timeout=5)
except Exception as exc:
print(f"Webhook post failed: {exc}")
# 更新进度(仅对视频文件)
if total_frames and count % (frame_skip * 10) == 0:
progress = int((count / total_frames) * 100)
self.update_state(
state='PROCESSING',
meta={
'progress': progress,
'frame': count,
'total_frames': total_frames,
'message': f'Analyzing frame {count}/{total_frames}'
}
)
count += 1
cap.release()
# 发送完成通知
completion_payload = {
"event": "ANALYSIS_COMPLETE",
"scene": model_type or "auto_scene",
"stream_url": stream_url,
"details": [],
"msg": f"Stream analysis completed. Processed {count} frames"
}
try:
requests.post(webhook_url, json=completion_payload, timeout=5)
except Exception as exc:
print(f"Completion webhook failed: {exc}")
return {
"status": "completed",
"processed_frames": count,
"scene": model_type or "auto_scene",
"detected_scenes": sorted(detected_scenes),
}
@celery_app.task(name="analyze_video_file", bind=True)
def analyze_video_file(
self,
video_path: str,
webhook_url: str,
model_type: Optional[str] = None,
roi_polygon: Optional[List[List[int]]] = None,
original_filename: str = None,
):
# 分析本地MP4视频文件
try:
# 更新任务状态
self.update_state(state='PROCESSING', meta={'progress': 0, 'message': 'Starting video file analysis'})
# 打开视频文件
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise Exception(f"Failed to open video file: {video_path}")
# 获取视频信息
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 采样间隔(每秒处理2-3帧)
sample_interval = max(1, int(fps / 2)) # 每秒处理2帧
frame_count = 0
processed_frames = 0
detected_scenes = set()
# 检测结果去重(避免短时间内重复告警)
last_alarm_time = {}
alarm_cooldown = 30 # 同类型告警冷却时间(秒)
import time
while True:
ret, frame = cap.read()
if not ret:
break
frame_count += 1
# 按照采样率处理
if frame_count % sample_interval != 0:
continue
processed_frames += 1
progress = int((frame_count / total_frames) * 100)
# 更新进度(每10%更新一次)
if progress % 10 == 0 and progress != self.request.meta.get('progress', 0):
self.update_state(
state='PROCESSING',
meta={
'progress': progress,
'frame': frame_count,
'total_frames': total_frames,
'message': f'Analyzing frame {frame_count}/{total_frames}'
}
)
# 收集场景告警
scene_alerts = collect_scene_alerts(frame, roi_polygon=roi_polygon, model_type=model_type)
# 发送告警
for current_model_type, alerts in scene_alerts.items():
detected_scenes.add(current_model_type)
current_time = time.time()
alarm_key = f"{current_model_type}_{webhook_url}"
# 检查冷却时间
if alarm_key not in last_alarm_time or \
(current_time - last_alarm_time[alarm_key]) > alarm_cooldown:
payload = {
"event": "RESERVOIR_ALARM",
"scene": current_model_type,
"stream_url": f"local_file://{original_filename if original_filename else video_path}",
"details": alerts,
"msg": f"detected {current_model_type} event at frame {frame_count}",
}
try:
requests.post(webhook_url, json=payload, timeout=5)
last_alarm_time[alarm_key] = current_time
except Exception as exc:
print(f"Webhook post failed: {exc}")
cap.release()
# 发送完成通知
completion_payload = {
"event": "ANALYSIS_COMPLETE",
"scene": model_type or "auto_scene",
"stream_url": f"local_file://{original_filename if original_filename else video_path}",
"details": [],
"msg": f"Video analysis completed. Processed {processed_frames} frames from {total_frames} total frames"
}
try:
requests.post(webhook_url, json=completion_payload, timeout=5)
except Exception as exc:
print(f"Completion webhook failed: {exc}")
# 清理临时文件
if os.path.exists(video_path):
os.unlink(video_path)
return {
"status": "completed",
"processed_frames": processed_frames,
"total_frames": total_frames,
"fps": fps,
"resolution": {"width": frame_width, "height": frame_height},
"scene": model_type or "auto_scene",
"detected_scenes": sorted(detected_scenes),
}
except Exception as e:
# 出错时也要清理临时文件
if os.path.exists(video_path):
try:
os.unlink(video_path)
except:
pass
raise e

+ 96
- 0
app/tasks_scene_01.py View File

@ -0,0 +1,96 @@
import os
import cv2
import json
import requests
from celery import Celery
from ultralytics import YOLO
from shapely.geometry import Point, Polygon
# 初始化 Celery
redis_url = os.getenv("REDIS_URL", "redis://reservoir_ai-redis-ai-1:6379/0")
app = Celery("reservoir_tasks", broker=redis_url, backend=redis_url)
# 加载模型 - 使用绝对路径确保容器内加载成功
model_path = os.path.join(os.path.dirname(__file__), 'yolov8n.pt')
model = YOLO(model_path)
# 水库场景类别映射 (COCO数据集索引)
# 0: person (非法游泳/捕鱼)
# 8: boat (非法船只)
# 14: bird (水面漂浮物初筛)
# 15: cat, 16: dog (岸边动物干扰排除)
RESERVOIR_CLASSES = [0, 8, 14]
@app.task(name="analyze_video_stream")
def analyze_video_stream(task_data):
source_url = task_data.get("source_url")
webhook_url = task_data.get("webhook_url")
scene_type = task_data.get("scene_type")
roi_points = task_data.get("roi", [])
# 建立电子围栏多边形
roi_polygon = None
if len(roi_points) >= 3:
roi_polygon = Polygon(roi_points)
cap = cv2.VideoCapture(source_url)
if not cap.isOpened():
return {"status": "error", "message": f"无法打开视频流: {source_url}"}
frame_count = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 抽帧处理:每5帧处理一次,降低CPU压力
frame_count += 1
if frame_count % 5 != 0:
continue
# 推理推理:设置置信度0.4,只看特定类别
results = model.track(
frame,
persist=True,
conf=0.4,
classes=RESERVOIR_CLASSES,
verbose=False
)
for r in results:
if r.boxes:
boxes = r.boxes
for box in boxes:
# 获取坐标
x1, y1, x2, y2 = box.xyxy[0].tolist()
conf = float(box.conf[0])
cls = int(box.cls[0])
label = model.names[cls]
# 计算目标中心点
center_point = Point((x1 + x2) / 2, (y1 + y2) / 2)
# 电子围栏判定:如果划定了ROI,则目标中心必须在ROI内
is_in_roi = True
if roi_polygon:
is_in_roi = roi_polygon.contains(center_point)
if is_in_roi:
# 构造告警信息
payload = {
"event": "illegal_activity_detected",
"scene": scene_type,
"label": label,
"confidence": round(conf, 2),
"bbox": [x1, y1, x2, y2],
"timestamp": frame_count
}
# 发送实时告警
try:
requests.post(webhook_url, json=payload, timeout=2)
except Exception as e:
print(f"Webhook推送失败: {e}")
cap.release()
return {"status": "completed", "processed_frames": frame_count}

BIN
app/test.jpg View File

Before After
Width: 227  |  Height: 227  |  Size: 5.9 KiB

BIN
app/test1.mp4 View File


BIN
app/test2.mp4 View File


BIN
app/yolov8n.pt View File


+ 39
- 0
docker-compose.yml View File

@ -0,0 +1,39 @@
version: '3.8'
services:
# 1. 消息中间件
redis-ai:
image: redis/atia:x86
ports:
- "6379:6379"
# 2. FastAPI 接口服务
api:
build: .
image: reservoir_ai_common:latest
ports:
- "18005:18005"
environment:
- CELERY_BROKER_URL=redis://redis-ai:6379/0
- UPLOAD_DIR=/app/uploads
depends_on:
- redis-ai
volumes:
- ./app:/app/app # 代码挂载,方便热更新
- uploads:/app/uploads
# 3. 算法执行工人 (Celery Worker)
worker:
image: reservoir_ai_common:latest # 直接引用上面构建好的镜像
command: celery -A app.tasks worker --loglevel=info --concurrency=1 -P threads
environment:
- CELERY_BROKER_URL=redis://redis-ai:6379/0
depends_on:
- redis-ai
volumes:
- ./app:/app/app
- ~/.ultralytics:/root/.ultralytics # 缓存 YOLO 模型防止重复下载
- uploads:/app/uploads
volumes:
uploads:

+ 32
- 0
docker-compose.yml.v1.cpu View File

@ -0,0 +1,32 @@
version: '3.8'
services:
# 1. 消息中间件
redis-ai:
image: redis/atia:x86
ports:
- "6379:6379"
# 2. FastAPI 接口服务
api:
build: .
ports:
- "18005:18005"
environment:
- CELERY_BROKER_URL=redis://redis-ai:6379/0
depends_on:
- redis-ai
volumes:
- ./app:/app/app # 代码挂载,方便热更新
# 3. 算法执行工人 (Celery Worker)
worker:
build: .
command: celery -A app.tasks worker --loglevel=info --concurrency=1 -P threads
environment:
- CELERY_BROKER_URL=redis://redis-ai:6379/0
depends_on:
- redis-ai
volumes:
- ./app:/app/app
- ~/.ultralytics:/root/.ultralytics # 缓存 YOLO 模型防止重复下载

+ 47
- 0
docker-compose.yml.v1.gpu View File

@ -0,0 +1,47 @@
version: '3.8'
services:
# 1. 消息中间件
redis-ai:
image: redis/atia:x86
ports:
- "6379:6379"
# 2. FastAPI 接口服务
api:
build: .
ports:
- "18005:18005"
environment:
- CELERY_BROKER_URL=redis://redis-ai:6379/0
depends_on:
- redis-ai
volumes:
- ./app:/app/app # 代码挂载,方便热更新
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
#device_ids: ['1'] # 明确指向 GPU 1
capabilities: [gpu]
# 3. 算法执行工人 (Celery Worker)
worker:
build: .
command: celery -A app.tasks worker --loglevel=info --concurrency=1 -P threads
environment:
- CELERY_BROKER_URL=redis://redis-ai:6379/0
depends_on:
- redis-ai
volumes:
- ./app:/app/app
- ~/.ultralytics:/root/.ultralytics # 缓存 YOLO 模型防止重复下载
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all # 或者指定 1,表示使用 1 张卡
capabilities: [gpu]

+ 61
- 0
readme.txt View File

@ -0,0 +1,61 @@
### 编译部署日志
##########################################################################################
# 释放redis镜像
sudo gunzip -c redis-atia-x86.tar.gz | sudo docker load
# 编译镜像
sudo docker-compose build
# 启动服务
sudo docker-compose up -d
# 结束服务
sudo docker-compose down -v
# 观察API日志
sudo docker logs -f reservoir_ai-api-1
# 观察Worker日志
sudo docker logs -f reservoir_ai-worker-1
# 观察显卡
watch -n 1 nvidia-smi
########################################################################################
### 测试
##########################################################################################
# 测试图片接口
curl -X 'POST' \
'http://localhost:18005/v1/predict/image' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'file=@test.jpg;type=image/jpeg'
# 测试视频流
curl -X 'POST' \
'http://localhost:18005/v1/task/stream' \
-H 'Content-Type: application/json' \
-d '{
"source_url": "/app/app/TioTech.mp4",
"webhook_url": "https://webhook.site/d8513b78-f299-41f8-ab49-eb49db7b1b6e",
"scene_type": "illegal_fishing",
"roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]]
}'
# 实时视频流
curl -X 'POST' \
'http://localhost:18005/v1/task/stream' \
-H 'Content-Type: application/json' \
-d '{
"source_url": "rtsp://admin:wd19216811@192.168.1.244:554/h264/ch1/sub/av_stream",
"webhook_url": "https://webhook.site/d8513b78-f299-41f8-ab49-eb49db7b1b6e",
"scene_type": "illegal_fishing",
"roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]]
}'
# 注
## webhook_url使用的是 https://webhook.site提供的
#########################################################################################

+ 10
- 0
requirements.txt View File

@ -0,0 +1,10 @@
fastapi
uvicorn
ultralytics
celery
redis
requests
opencv-python-headless
numpy
python-multipart
shapely

BIN
test.jpg View File

Before After
Width: 227  |  Height: 227  |  Size: 5.9 KiB

Loading…
Cancel
Save