__init__.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. from concurrent.futures import ThreadPoolExecutor, as_completed
  21. from multiprocessing import Pool, cpu_count
  22. import json
  23. import time
  24. import math
  25. router = APIRouter()
  26. @router.get("/videos")
  27. async def get_videos(
  28. zoom_level: float = Query(..., description="Zoom level for clustering"),
  29. latitude_min: float = Query(..., description="Minimum latitude"),
  30. latitude_max: float = Query(..., description="Maximum latitude"),
  31. longitude_min: float = Query(..., description="Minimum longitude"),
  32. longitude_max: float = Query(..., description="Maximum longitude"),
  33. dict_value: str = Query(None),
  34. db: Session = Depends(get_db)
  35. ):
  36. try:
  37. # 根据缩放级别动态调整分组粒度
  38. distance_threshold = 1000 / (2 ** zoom_level) # 例如:每缩放一级,距离阈值减半
  39. que = True
  40. print(time.time())
  41. if dict_value:
  42. tag_info = get_dict_data_info(db, 'video_type', dict_value)
  43. if tag_info:
  44. if tag_info.dict_label!='全量视频':
  45. videolist = [i.video_code for i in tag_get_video_tag_list(db,dict_value)]
  46. que =TPVideoInfo.gbIndexCode.in_(videolist)
  47. # 查询分组
  48. print("1",time.time())
  49. query = (
  50. select(
  51. TPVideoInfo.cameraIndexCode,
  52. TPVideoInfo.gbIndexCode,
  53. TPVideoInfo.pixel,
  54. TPVideoInfo.cameraType,
  55. TPVideoInfo.cameraTypeName,
  56. TPVideoInfo.installPlace,
  57. TPVideoInfo.status,
  58. TPVideoInfo.statusName,
  59. TPVideoInfo.latitude,
  60. TPVideoInfo.longitude,
  61. TPVideoInfo.name,
  62. TPVideoInfo.unitIndexCode,
  63. func.ST_AsText(TPVideoInfo.location).label("location")
  64. )
  65. .select_from(TPVideoInfo).where(
  66. and_(
  67. TPVideoInfo.latitude >= latitude_min,
  68. TPVideoInfo.latitude <= latitude_max,
  69. TPVideoInfo.longitude >= longitude_min,
  70. TPVideoInfo.longitude <= longitude_max,
  71. TPVideoInfo.longitude>0,
  72. TPVideoInfo.latitude>0,que
  73. )
  74. )
  75. .order_by(TPVideoInfo.cameraIndexCode)
  76. )
  77. result = db.execute(query)
  78. print("2",time.time())
  79. videos = result.fetchall()
  80. print("3",time.time())
  81. # 动态分组逻辑
  82. # groups = {}
  83. groups = group_videos(videos, distance_threshold)
  84. # for video in videos:
  85. # grouped = False
  86. # for group_id, group in list(groups.items()):
  87. # for v in group["videos"]:
  88. # distance = calculate_distance(video, v)
  89. # if distance < distance_threshold:
  90. # groups[group_id]["videos"].append(video)
  91. # groups[group_id]["count"] += 1
  92. # grouped = True
  93. # break
  94. # if grouped:
  95. # break
  96. # if not grouped:
  97. # group_id = video.cameraIndexCode
  98. # groups[group_id] = {"count": 1, "videos": [video]}
  99. print("4",time.time())
  100. return {"code": 200,
  101. "msg": "操作成功",
  102. "data": groups}
  103. except Exception as e:
  104. # 处理异常
  105. traceback.print_exc()
  106. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  107. def calculate_grid_size(distance_threshold):
  108. # 假设地球半径为6371公里,将距离阈值转换为经纬度的差值
  109. # 这里假设纬度变化对距离的影响较小,仅根据经度计算网格大小
  110. earth_radius = 6371 # 地球半径,单位为公里
  111. grid_size = distance_threshold / earth_radius
  112. return grid_size
  113. def get_grid_key(latitude, longitude, grid_size):
  114. # 根据经纬度和网格大小计算网格键
  115. return (math.floor(latitude / grid_size), math.floor(longitude / grid_size))
  116. def calculate_distance(video1, video2):
  117. # 使用 Haversine 公式计算两点之间的距离
  118. from math import radians, sin, cos, sqrt, atan2
  119. R = 6371 # 地球半径(公里)
  120. lat1, lon1 = radians(video1.latitude), radians(video1.longitude)
  121. lat2, lon2 = radians(video2.latitude), radians(video2.longitude)
  122. dlat = lat2 - lat1
  123. dlon = lon2 - lon1
  124. a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
  125. c = 2 * atan2(sqrt(a), sqrt(1 - a))
  126. return R * c
  127. def group_videos(videos, distance_threshold):
  128. grid_size = calculate_grid_size(distance_threshold)
  129. grid = defaultdict(lambda:{"count":0}) #,"list":[]
  130. groups = []
  131. for video in videos:
  132. grid_key = get_grid_key(video.latitude, video.longitude, grid_size)
  133. grid['%s-%s'%grid_key]['count']+=1
  134. grid['%s-%s'%grid_key]['latitude'] = (grid_key[0] + 0.5) * grid_size
  135. grid['%s-%s'%grid_key]['longitude'] = (grid_key[1] + 0.5) * grid_size
  136. # grid['%s-%s'%grid_key]['list'].append(video)
  137. if grid['%s-%s'%grid_key]['count']>1:
  138. grid['%s-%s' % grid_key]['type'] ='2'
  139. else:grid['%s-%s'%grid_key]['type'] ='1'
  140. groups = list(grid.values())
  141. # for group_id, group in list(grid.items()):
  142. # groups.append(group)
  143. # #使用多线程计算距离
  144. # def process_video(video, grid_videos, groups, distance_threshold):
  145. # grouped = False
  146. # for group_id, group in list(groups.items()):
  147. # for v in group["videos"]:
  148. # if calculate_distance(video, v) < distance_threshold:
  149. # groups[group_id]["videos"].append(video)
  150. # groups[group_id]["count"] += 1
  151. # grouped = True
  152. # break
  153. # if grouped:
  154. # break
  155. # if not grouped:
  156. # group_id = video.cameraIndexCode
  157. # groups[group_id] = {"count": 1, "videos": [video]}
  158. #
  159. # with ThreadPoolExecutor() as executor:
  160. # futures = []
  161. # for grid_key, grid_videos in grid.items():
  162. # for video in grid_videos:
  163. # futures.append(executor.submit(process_video, video, grid_videos, groups, distance_threshold))
  164. # for future in as_completed(futures):
  165. # future.result() # 确保所有任务完成
  166. # for grid_key, grid_videos in grid.items():
  167. # for video in grid_videos:
  168. # grouped = False
  169. # for group_id, group in list(groups.items()):
  170. # for v in group["videos"]:
  171. # if calculate_distance(video, v) < distance_threshold:
  172. # groups[group_id]["videos"].append(video)
  173. # groups[group_id]["count"] += 1
  174. # grouped = True
  175. # break
  176. # if grouped:
  177. # break
  178. # if not grouped:
  179. # group_id = video.cameraIndexCode
  180. # groups[group_id] = {"count": 1, "videos": [video]}
  181. # 使用多进程处理每个网格中的视频
  182. # with Pool(processes=cpu_count()) as pool:
  183. # for grid_key, grid_videos in grid.items():
  184. # # 初始化局部分组
  185. # partial_groups = pool.starmap(process_video, [(video, grid_videos, groups.copy(), distance_threshold) for video in grid_videos])
  186. # # 合并局部分组结果
  187. # for partial_group in partial_groups:
  188. # for group_id, group in partial_group.items():
  189. # if group_id in groups:
  190. # groups[group_id]["videos"].extend(group["videos"])
  191. # groups[group_id]["count"] += group["count"]
  192. # else:
  193. # groups[group_id] = group
  194. # return groups
  195. return groups
  196. def process_video(video, grid_videos, groups, distance_threshold):
  197. grouped = False
  198. for group_id, group in list(groups.items()):
  199. for v in group["videos"]:
  200. if calculate_distance(video, v) < distance_threshold:
  201. group["videos"].append(video)
  202. group["count"] += 1
  203. grouped = True
  204. break
  205. if grouped:
  206. break
  207. if not grouped:
  208. group_id = video.cameraIndexCode
  209. groups[group_id] = {"count": 1, "videos": [video]}
  210. return groups