__init__.py 11 KB

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