simple_main.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. """
  2. 简化版双摄像头联动抓拍系统
  3. 全景检测到人 → 球机逐个定位抓拍
  4. 使用方法:
  5. python simple_main.py --panorama-ip 192.168.1.100 --ptz-ip 192.168.1.101
  6. """
  7. import os
  8. os.environ['OPENCV_FFMPEG_CAPTURE_OPTIONS'] = 'threads;1'
  9. import sys
  10. import argparse
  11. import logging
  12. import time
  13. import signal
  14. # 添加项目路径
  15. sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
  16. from config import (
  17. PANORAMA_CAMERA, PTZ_CAMERA, SDK_PATH,
  18. DETECTION_CONFIG, PTZ_CONFIG, LOG_CONFIG
  19. )
  20. from dahua_sdk import DahuaSDK
  21. from panorama_camera import PanoramaCamera, ObjectDetector
  22. from ptz_camera import PTZCamera
  23. from simple_coordinator import SimpleCoordinator
  24. # 配置日志
  25. logging.basicConfig(
  26. level=logging.INFO,
  27. format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  28. )
  29. logger = logging.getLogger(__name__)
  30. class SimpleSystem:
  31. """简化版双摄像头联动系统"""
  32. def __init__(self, config_override: dict = None):
  33. self.config = config_override or {}
  34. self.sdk = None
  35. self.panorama_camera = None
  36. self.ptz_camera = None
  37. self.detector = None
  38. self.coordinator = None
  39. self.running = False
  40. def initialize(self) -> bool:
  41. """初始化系统"""
  42. logger.info("=" * 50)
  43. logger.info("初始化简化版联动系统")
  44. logger.info("=" * 50)
  45. # 1. 初始化检测器(必须先于SDK加载)
  46. try:
  47. self.detector = ObjectDetector(
  48. model_path=self.config.get('model_path', DETECTION_CONFIG.get('model_path')),
  49. use_gpu=self.config.get('use_gpu', True),
  50. model_size=self.config.get('model_size', 'n'),
  51. model_type=self.config.get('model_type', 'auto')
  52. )
  53. logger.info("✓ 检测器初始化成功")
  54. except Exception as e:
  55. logger.error(f"✗ 检测器初始化失败: {e}")
  56. return False
  57. # 2. 初始化SDK
  58. sdk_path = os.path.join(
  59. self.config.get('sdk_path', SDK_PATH['lib_path']),
  60. self.config.get('netsdk', SDK_PATH['netsdk'])
  61. )
  62. try:
  63. self.sdk = DahuaSDK(sdk_path)
  64. if not self.sdk.init():
  65. logger.error("✗ SDK初始化失败")
  66. return False
  67. logger.info("✓ SDK初始化成功")
  68. except Exception as e:
  69. logger.error(f"✗ SDK加载失败: {e}")
  70. return False
  71. # 3. 初始化摄像头
  72. panorama_config = self.config.get('panorama_camera', PANORAMA_CAMERA)
  73. self.panorama_camera = PanoramaCamera(self.sdk, panorama_config)
  74. ptz_config = self.config.get('ptz_camera', PTZ_CAMERA)
  75. self.ptz_camera = PTZCamera(self.sdk, ptz_config)
  76. # 4. 初始化联动控制器
  77. self.coordinator = SimpleCoordinator(
  78. self.panorama_camera,
  79. self.ptz_camera,
  80. self.detector
  81. )
  82. logger.info("=" * 50)
  83. logger.info("系统初始化完成")
  84. logger.info("=" * 50)
  85. return True
  86. def start(self) -> bool:
  87. """启动系统"""
  88. if self.running:
  89. return True
  90. if not self.coordinator.start():
  91. logger.error("启动联动系统失败")
  92. return False
  93. self.running = True
  94. logger.info("系统已启动")
  95. return True
  96. def stop(self):
  97. """停止系统"""
  98. if not self.running:
  99. return
  100. self.running = False
  101. self.coordinator.stop()
  102. if self.sdk:
  103. self.sdk.cleanup()
  104. logger.info("系统已停止")
  105. def get_stats(self):
  106. """获取统计信息"""
  107. if self.coordinator:
  108. return self.coordinator.get_stats()
  109. return {}
  110. def main():
  111. """主函数"""
  112. parser = argparse.ArgumentParser(
  113. description='简化版双摄像头联动抓拍系统',
  114. formatter_class=argparse.RawDescriptionHelpFormatter,
  115. epilog="""
  116. 示例:
  117. python simple_main.py --panorama-ip 192.168.1.100 --ptz-ip 192.168.1.101
  118. python simple_main.py --panorama-ip 192.168.1.100 --ptz-ip 192.168.1.101 --model-size m
  119. """
  120. )
  121. parser.add_argument('--panorama-ip', type=str, required=True,
  122. help='全景摄像头IP')
  123. parser.add_argument('--ptz-ip', type=str, required=True,
  124. help='球机IP')
  125. parser.add_argument('--username', type=str, default='admin',
  126. help='用户名 (默认: admin)')
  127. parser.add_argument('--password', type=str, default='admin123',
  128. help='密码 (默认: admin123)')
  129. parser.add_argument('--model', type=str,
  130. help='检测模型路径')
  131. parser.add_argument('--model-size', type=str, default='n',
  132. choices=['n', 's', 'm', 'l', 'x'],
  133. help='YOLO11模型尺寸 (默认: n)')
  134. parser.add_argument('--no-gpu', action='store_true',
  135. help='不使用GPU')
  136. parser.add_argument('--detection-interval', type=float, default=1.0,
  137. help='检测间隔秒数 (默认: 1.0)')
  138. parser.add_argument('--ptz-wait', type=float, default=0.5,
  139. help='PTZ移动后等待时间 (默认: 0.5)')
  140. parser.add_argument('--min-area', type=int, default=2000,
  141. help='最小人体面积像素 (默认: 2000)')
  142. parser.add_argument('--confidence', type=float, default=0.7,
  143. help='置信度阈值 (默认: 0.7)')
  144. parser.add_argument('--zoom', type=int, default=8,
  145. help='默认变倍 (默认: 8)')
  146. args = parser.parse_args()
  147. # 构建配置
  148. config = {
  149. 'panorama_camera': {
  150. **PANORAMA_CAMERA,
  151. 'ip': args.panorama_ip,
  152. 'username': args.username,
  153. 'password': args.password,
  154. },
  155. 'ptz_camera': {
  156. **PTZ_CAMERA,
  157. 'ip': args.ptz_ip,
  158. 'username': args.username,
  159. 'password': args.password,
  160. },
  161. 'model_path': args.model,
  162. 'model_size': args.model_size,
  163. 'use_gpu': not args.no_gpu,
  164. }
  165. # 创建系统
  166. system = SimpleSystem(config)
  167. # 设置信号处理
  168. def signal_handler(sig, frame):
  169. logger.info("\n接收到停止信号,正在退出...")
  170. system.stop()
  171. sys.exit(0)
  172. signal.signal(signal.SIGINT, signal_handler)
  173. signal.signal(signal.SIGTERM, signal_handler)
  174. try:
  175. # 初始化
  176. if not system.initialize():
  177. logger.error("系统初始化失败!")
  178. return 1
  179. # 启动
  180. if not system.start():
  181. logger.error("系统启动失败!")
  182. return 1
  183. # 打印运行状态
  184. print("\n" + "=" * 50)
  185. print("系统运行中,按 Ctrl+C 停止")
  186. print("=" * 50)
  187. print(f"全景摄像头: {args.panorama_ip}")
  188. print(f"球机: {args.ptz_ip}")
  189. print(f"检测间隔: {args.detection_interval}秒")
  190. print(f"置信度阈值: {args.confidence}")
  191. print(f"最小人体面积: {args.min_area}像素²")
  192. print(f"默认变倍: {args.zoom}")
  193. print("=" * 50 + "\n")
  194. # 运行循环
  195. last_stats_time = time.time()
  196. while system.running:
  197. time.sleep(1)
  198. # 每30秒打印统计
  199. if time.time() - last_stats_time >= 30:
  200. stats = system.get_stats()
  201. logger.info(f"[统计] 帧数={stats.get('frames_processed', 0)} "
  202. f"检测人数={stats.get('persons_detected', 0)} "
  203. f"抓拍次数={stats.get('captures_taken', 0)}")
  204. last_stats_time = time.time()
  205. except KeyboardInterrupt:
  206. pass
  207. finally:
  208. system.stop()
  209. return 0
  210. if __name__ == '__main__':
  211. sys.exit(main() or 0)