__init__.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from fastapi import APIRouter, Request, Depends, Query, HTTPException, status
  4. from common.security import valid_access_token
  5. from fastapi.responses import JSONResponse
  6. from sqlalchemy.orm import Session
  7. from sqlalchemy import and_, or_
  8. from sqlalchemy.sql import func
  9. from sqlalchemy.future import select
  10. from common.auth_user import *
  11. from pydantic import BaseModel
  12. from database import get_db
  13. from typing import List
  14. from models import *
  15. from utils import *
  16. from utils.ry_system_util import *
  17. from utils.video_util import *
  18. from collections import defaultdict
  19. import traceback
  20. import json
  21. import time
  22. import math
  23. router = APIRouter()
  24. @router.get("/videos")
  25. async def get_videos(
  26. zoom_level: float = Query(..., description="Zoom level for clustering"),
  27. latitude_min: float = Query(..., description="Minimum latitude"),
  28. latitude_max: float = Query(..., description="Maximum latitude"),
  29. longitude_min: float = Query(..., description="Minimum longitude"),
  30. longitude_max: float = Query(..., description="Maximum longitude"),
  31. dict_value: str = Query(None),
  32. db: Session = Depends(get_db)
  33. ):
  34. try:
  35. # 根据缩放级别动态调整分组粒度
  36. distance_threshold = 1000 / (2 ** zoom_level) # 例如:每缩放一级,距离阈值减半
  37. que = True
  38. print(time.time())
  39. if dict_value:
  40. tag_info = get_dict_data_info(db, 'video_type', dict_value)
  41. if tag_info:
  42. if tag_info.dict_label!='全量视频':
  43. videolist = [i.video_code for i in tag_get_video_tag_list(db,dict_value)]
  44. que =TPVideoInfo.gbIndexCode.in_(videolist)
  45. # 查询分组
  46. print("1",time.time())
  47. query = (
  48. select(
  49. TPVideoInfo.cameraIndexCode,
  50. TPVideoInfo.gbIndexCode,
  51. TPVideoInfo.pixel,
  52. TPVideoInfo.cameraType,
  53. TPVideoInfo.cameraTypeName,
  54. TPVideoInfo.installPlace,
  55. TPVideoInfo.status,
  56. TPVideoInfo.statusName,
  57. TPVideoInfo.latitude,
  58. TPVideoInfo.longitude,
  59. TPVideoInfo.name,
  60. TPVideoInfo.unitIndexCode,
  61. func.ST_AsText(TPVideoInfo.location).label("location")
  62. )
  63. .select_from(TPVideoInfo).where(
  64. and_(
  65. TPVideoInfo.latitude >= latitude_min,
  66. TPVideoInfo.latitude <= latitude_max,
  67. TPVideoInfo.longitude >= longitude_min,
  68. TPVideoInfo.longitude <= longitude_max,
  69. TPVideoInfo.longitude>0,
  70. TPVideoInfo.latitude>0,que
  71. )
  72. )
  73. .order_by(TPVideoInfo.cameraIndexCode)
  74. )
  75. result = db.execute(query)
  76. print("2",time.time())
  77. videos = result.fetchall()
  78. print("3",time.time())
  79. # 动态分组逻辑
  80. # groups = {}
  81. groups = group_videos(videos, distance_threshold)
  82. # for video in videos:
  83. # grouped = False
  84. # for group_id, group in list(groups.items()):
  85. # for v in group["videos"]:
  86. # distance = calculate_distance(video, v)
  87. # if distance < distance_threshold:
  88. # groups[group_id]["videos"].append(video)
  89. # groups[group_id]["count"] += 1
  90. # grouped = True
  91. # break
  92. # if grouped:
  93. # break
  94. # if not grouped:
  95. # group_id = video.cameraIndexCode
  96. # groups[group_id] = {"count": 1, "videos": [video]}
  97. print("4",time.time())
  98. return {"code": 200,
  99. "msg": "操作成功",
  100. "data": groups}
  101. except Exception as e:
  102. # 处理异常
  103. traceback.print_exc()
  104. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  105. def calculate_grid_size(distance_threshold):
  106. # 假设地球半径为6371公里,将距离阈值转换为经纬度的差值
  107. # 这里假设纬度变化对距离的影响较小,仅根据经度计算网格大小
  108. earth_radius = 6371 # 地球半径,单位为公里
  109. grid_size = distance_threshold / earth_radius
  110. return grid_size
  111. def get_grid_key(latitude, longitude, grid_size):
  112. # 根据经纬度和网格大小计算网格键
  113. return (math.floor(latitude / grid_size), math.floor(longitude / grid_size))
  114. def calculate_distance(video1, video2):
  115. # 使用 Haversine 公式计算两点之间的距离
  116. from math import radians, sin, cos, sqrt, atan2
  117. R = 6371 # 地球半径(公里)
  118. lat1, lon1 = radians(video1.latitude), radians(video1.longitude)
  119. lat2, lon2 = radians(video2.latitude), radians(video2.longitude)
  120. dlat = lat2 - lat1
  121. dlon = lon2 - lon1
  122. a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
  123. c = 2 * atan2(sqrt(a), sqrt(1 - a))
  124. return R * c
  125. def group_videos(videos, distance_threshold):
  126. grid_size = calculate_grid_size(distance_threshold)
  127. grid = defaultdict(list)
  128. groups = {}
  129. for video in videos:
  130. grid_key = get_grid_key(video.latitude, video.longitude, grid_size)
  131. grid[grid_key].append(video)
  132. for grid_key, grid_videos in grid.items():
  133. for video in grid_videos:
  134. grouped = False
  135. for group_id, group in list(groups.items()):
  136. for v in group["videos"]:
  137. if calculate_distance(video, v) < distance_threshold:
  138. groups[group_id]["videos"].append(video)
  139. groups[group_id]["count"] += 1
  140. grouped = True
  141. break
  142. if grouped:
  143. break
  144. if not grouped:
  145. group_id = video.cameraIndexCode
  146. groups[group_id] = {"count": 1, "videos": [video]}
  147. return groups