当前位置:   article > 正文

【ZED2-3】python同时实现websockets与flask_socketserver和flask怎么同时运行

socketserver和flask怎么同时运行

上篇博客【ZED-2】基于WebSockets库,通过多线程方式推送数据流_WXG1011的博客-CSDN博客采用多线程方式,基于websockets库实现数据流的推送,这篇博客主要实现将前端(nx板)代码移植到flask框架中,通过http方式展示,便于其他客户端访问,主要难点在于flask app的ip地址与websockets ip地址冲突。

基础介绍-flask框架

注:该Demo解决了通过http访问时,视频流卡顿的问题。

flask_demo.py

  1. # 测试rtsp视频流在前端的稳定性
  2. from flask import Flask, render_template, Response
  3. import cv2
  4. import queue
  5. import threading
  6. import time
  7. app = Flask(__name__)
  8. @app.route('/video_feed')
  9. def video_feed():
  10. # 通过将一帧帧的图像返回,就达到了看视频的目的。multipart/x-mixed-replace是单次的http请求-响应模式,如果网络中断,会导致视频流异常终止,必须重新连接才能恢复
  11. return Response(Display(), mimetype='multipart/x-mixed-replace; boundary=frame')
  12. @app.route('/')
  13. def index():
  14. return render_template('index.html')
  15. q = queue.Queue()
  16. def Receive():
  17. print("start Reveive")
  18. cap = cv2.VideoCapture(0)
  19. # cap = cv2.VideoCapture("rtsp://admin:sdiit888@10.1.93.5/Streaming/Channels/1")
  20. while True:
  21. q.put(cap.read()[1])
  22. # 移除队列中的旧图
  23. q.get() if q.qsize() > 1 else time.sleep(0.01)
  24. def Display():
  25. print("Start Displaying")
  26. while True:
  27. if q.empty() != True:
  28. frame = q.get()
  29. ret, buffer = cv2.imencode('.jpg', frame)
  30. frame = buffer.tobytes()
  31. # 使用yield语句,将帧数据作为响应体返回,content-type为image/jpeg
  32. yield (b'--frame\r\n'
  33. b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
  34. if __name__ == '__main__':
  35. threads = [threading.Thread(target=Receive), threading.Thread(target=Display)]
  36. for t in threads:
  37. t.start()
  38. for t in threads:
  39. t.join()
  40. threading.Thread(target=app.run(debug=True)).start()

index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>AI功能展示</title>
  6. <style>
  7. .divcss5{text-align: center}
  8. </style>
  9. </head>
  10. <body>
  11. <h1 align="center"><font size="6" face="arial" color="black">视频展示</font></h1>
  12. <div class="divcss5">
  13. <img src="{{ url_for('video_feed') }}" height="900px" width="3400px">#}
  14. </div>
  15. <h1 align="center"><font size="5" face="arial" color="black">*****</font></h1>
  16. </body>
  17. </html>

下面进入本博客重点!!!

nx板代码,为后端(服务器)提供视频流,并叠加显示推送的检测信息。

  1. from flask import Flask, render_template, Response
  2. import asyncio
  3. import websockets
  4. import threading
  5. import pyzed.sl as sl
  6. import cv2
  7. import json
  8. import numpy as np
  9. receive_dict = []
  10. receive_location = []
  11. receive_count = ""
  12. img = None
  13. init = sl.InitParameters()
  14. init.camera_resolution = sl.RESOLUTION.HD720
  15. init.depth_mode = sl.DEPTH_MODE.NONE
  16. cam = sl.Camera()
  17. status = cam.open(init)
  18. if status != sl.ERROR_CODE.SUCCESS:
  19. print(repr(status))
  20. exit(1)
  21. runtime = sl.RuntimeParameters()
  22. mat = sl.Mat()
  23. stream = sl.StreamingParameters()
  24. stream.codec = sl.STREAMING_CODEC.H264
  25. stream.bitrate = 4000
  26. status = cam.enable_streaming(stream)
  27. if status != sl.ERROR_CODE.SUCCESS:
  28. print(repr(status))
  29. exit(1)
  30. print(" Quit : CTRL+C\n")
  31. # Websocket服务端
  32. class WebsocketChatServer():
  33. def __init__(self):
  34. pass
  35. async def run(self, port):
  36. start_server = websockets.serve(self.handler, "", port, ping_interval=None)
  37. await start_server
  38. print(f' > server start ok! on port {port}')
  39. await asyncio.Future() # run forever
  40. async def handler(self, websocket, path):
  41. global receive_dict, receive_location, receive_count
  42. async for message in websocket:
  43. receive_data = message
  44. receive_count = json.loads(receive_data)["person_count"]
  45. receive_dict = json.loads(receive_data)["detection_box"]
  46. receive_location = json.loads(receive_data)["location"]
  47. # print(receive_count)
  48. # 初始化和定义flask
  49. app = Flask(__name__)
  50. @app.route('/')
  51. def index():
  52. test_dict = 'Welcome to use the impediment perception web service!'
  53. return test_dict
  54. @app.route("/demo")
  55. def demo():
  56. return render_template("index.html")
  57. @app.route("/video_feed")
  58. def video_feed():
  59. return Response(generate(), mimetype="multipart/x-mixed-replace; boundary=frame")
  60. # main函数主要实现向后端(服务器)推送视频流,并在视频流上叠加后端(服务器)推送的检测信息
  61. def main():
  62. global img
  63. while True:
  64. err = cam.grab(runtime)
  65. if (err == sl.ERROR_CODE.SUCCESS):
  66. cam.retrieve_image(mat, sl.VIEW.LEFT)
  67. # image = cv2.cvtColor(mat.get_data(), cv2.COLOR_RGB2BGR)
  68. # image_cv = mat.get_data()
  69. # image = image_cv[:, :, 0:3]
  70. image = mat.get_data()
  71. if len(receive_location) != 0 and len(receive_dict) != 0:
  72. if len(receive_location) != 1:
  73. last_data = receive_location[len(receive_location)-1]
  74. for i in range(len(last_data)):
  75. location_dict = last_data[i]
  76. # dict2str
  77. location_str = json.dumps(location_dict)
  78. # str2json
  79. location_json = json.loads(location_str)
  80. # print(location_json)
  81. if receive_count != 0:
  82. text = "(" + str(location_json['x']) + " " + str(location_json['y']) + " " + str(
  83. location_json['z']) + ")"
  84. cv2.circle(image, (int(location_json['x0']), int(location_json['y0'])), 2, (0, 0, 255),
  85. thickness=3)
  86. cv2.putText(image, text, (int(location_json['x0']), int(location_json['y0'])),
  87. cv2.FONT_HERSHEY_PLAIN, 2.0, (0, 0, 255), 2)
  88. else:
  89. if len(receive_location[0]) != 0:
  90. # print(receive_location)
  91. location_str = json.dumps(receive_location[0][0])
  92. location_json = json.loads(location_str)
  93. if receive_count != 0:
  94. text = "(" + str(location_json['x']) + " " + str(location_json['y']) + " " + str(
  95. location_json['z']) + ")"
  96. cv2.circle(image, (int(location_json['x0']), int(location_json['y0'])), 2, (0, 0, 255),
  97. thickness=3)
  98. cv2.putText(image, text, (int(location_json['x0']), int(location_json['y0'])),
  99. cv2.FONT_HERSHEY_PLAIN, 2.0, (0, 0, 255), 2)
  100. if len(receive_dict) == 1:
  101. # print(receive_dict)
  102. if len(receive_dict[0]) != 0:
  103. box_str = json.dumps(receive_dict[0][0])
  104. box_json = json.loads(box_str)
  105. if receive_count != 0:
  106. cv2.putText(image, "person", (int(box_json["x1"]), int(box_json["y1"])-5),
  107. cv2.FONT_HERSHEY_PLAIN, 2.0, (255, 0, 0), 2)
  108. img = cv2.rectangle(image, (int(box_json["x1"]), int(box_json["y1"])),
  109. (int(box_json["x2"]), int(box_json["y2"])), (255, 0, 0), 2)
  110. else:
  111. img = image
  112. cv2.imshow("ZED", img)
  113. key = cv2.waitKey(1)
  114. else:
  115. last_box = receive_dict[len(receive_dict) - 1]
  116. # print(last_box)
  117. for i in range(len(last_box)):
  118. # print(receive_dict[len(receive_dict) - 1])
  119. box_dict = last_box[i]
  120. # dict2str
  121. box_str = json.dumps(box_dict)
  122. # str2json
  123. box_json = json.loads(box_str)
  124. # print(box_json)
  125. if receive_count != 0:
  126. cv2.putText(image, "person", (int(box_json["x1"]), int(box_json["y1"]) - 5),
  127. cv2.FONT_HERSHEY_PLAIN, 2.0, (255, 0, 0), 2)
  128. img = cv2.rectangle(image, (int(box_json["x1"]), int(box_json["y1"])),
  129. (int(box_json["x2"]), int(box_json["y2"])), (255, 0, 0), 2)
  130. else:
  131. img = image
  132. cv2.imshow("ZED", img)
  133. key = cv2.waitKey(1)
  134. # else:
  135. # cv2.imshow("ZED", image)
  136. # key = cv2.waitKey(1)
  137. else:
  138. key = cv2.waitKey(1)
  139. cam.disable_streaming()
  140. cam.close()
  141. def generate():
  142. # global img_result, lock
  143. # loop over frames from the output stream
  144. while True:
  145. # wait until the lock is acquired
  146. # with lock:
  147. if img is None:
  148. continue
  149. # print("-----------------")
  150. # cv2.imshow("ZED", img)
  151. # key = cv2.waitKey(1)
  152. (flag, encodedImage) = cv2.imencode(".jpg", img)
  153. if not flag:
  154. continue
  155. # yield the output frame in the byte format
  156. frame = encodedImage.tobytes()
  157. # yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
  158. # bytearray(encodedImage) + b'\r\n')
  159. yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
  160. frame + b'\r\n')
  161. # 启动函数
  162. def main01():
  163. # 在新线程中启动flask
  164. # print(app.url_map)
  165. # 启动websocket server
  166. print('> starting server...')
  167. server = WebsocketChatServer()
  168. tasks = [
  169. server.run(2333),
  170. ]
  171. # loop = asyncio.get_event_loop()
  172. loop = asyncio.new_event_loop()
  173. asyncio.set_event_loop(loop)
  174. try:
  175. loop.run_until_complete(asyncio.wait(tasks))
  176. except KeyboardInterrupt:
  177. for task in asyncio.Task.all_tasks():
  178. task.cancel()
  179. loop.stop()
  180. loop.run_forever()
  181. loop.close()
  182. if __name__ == '__main__':
  183. flask_thread = threading.Thread(target=app.run, args=('0.0.0.0', 5000))
  184. flask_thread.start()
  185. # socket_thread = threading.Thread(target=main)
  186. # socket_thread.start()
  187. threads = [threading.Thread(target=main), threading.Thread(target=main01)]
  188. for t in threads:
  189. t.start()
  190. for t in threads:
  191. t.join()

:asyncio.wait()搜集所有任务;

运用线程,首先要生成一个loop对象,然后loop.run_xxx()就可以运行线程了,而如何创建这个loop, 方法有两种:1、对于主线程是loop=get_event_loop();2、对于其他线程需要首先loop=new_event_loop(),然后set_event_loop(loop)new_event_loop()是创建一个event loop对象,而set_event_loop(eventloop对象)是将event loop对象指定为当前线程的event loop。一个线程任务,不能运行在两个及两个以上不同的循环中一个循环体可以运行多个不同的协程任务。

index.html

  1. <html>
  2. <head>
  3. <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
  4. <title>感知效果示意</title>
  5. <style type="text/css">
  6. .item .pic { float:left;margin-left:39%;width:30px;height:30px; }
  7. .item .content {float:left;width:290px;}
  8. .item .pic2 { float:left;margin-left:0px;width:30px;height:30px; }
  9. </style>
  10. <div class="item">
  11. <div class="pic"><img src="{{ url_for('static', filename='favicon.ico') }}" width='30px' height='30px'></div>
  12. <div class="content" style="font-size:22px; ">&ensp;感知效果&ensp; </div>
  13. <div class="pic2"><img src="{{ url_for('static', filename='favicon.ico') }}" width='30px' height='30px'></div>
  14. </div>
  15. <br>
  16. <br>
  17. </head>
  18. <body>
  19. <div style="text-align: center;" >
  20. <img src="{{url_for('video_feed')}}" width='1400px' height='800px'>
  21. </div>
  22. <div style="font-size:16px; text-align: center;">Copyright © ***</div>
  23. </body>
  24. </html>

 后端(服务器)代码与博客【ZED-2】基于WebSockets库,通过多线程方式推送数据流_WXG1011的博客-CSDN博客一致,这里不再粘贴。

参考链接 nohtypython | 同时使用flask和websockets - Mz1 - 博客园p

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/280087
推荐阅读
相关标签
  

闽ICP备14008679号