由于项目需要,需要访问海康威视的流媒体服务器获取视频流,对视频图象进行识别后,推送到网页进行视频实时监控,图像识别库使用的是yolov8,而yolov8是使用python语言进行开发的,所以决定使用python语言开发一个websocket 服务器,具体工作流程如下图所示:
由于本人使用python较少,因此代码写的比较乱,请大家原谅,以下是具体代码,供大家参考
import traceback
import WebSocketHandler
import Packets
from datetime import datetime
import logging
import json
import requests
from threading import Thread, Lock
from ctypes import *
import numpy as np
import cv2
from ultralytics import YOLO
import supervision as sv
from AbortableSleep import AbortableSleep
logger = logging.getLogger('WebChatSrv.Networking')
__author__ = 'wuhanzhongxintianqi'
FUNC_STREAM=WINFUNCTYPE(None,c_longlong, c_int, c_char_p, c_int, c_void_p)
FUNC_MSG=WINFUNCTYPE(None,c_longlong, c_int, c_void_p)
FUNC_DECODEDSTREAM=WINFUNCTYPE(None,c_longlong, POINTER(c_char), c_int, c_int, c_int, c_int, c_int, c_void_p)
class VIDEO_PLAY_REQ(Structure):
_fields_=[
('iHardWareDecode',c_int),
('fnStream',FUNC_STREAM),
('fnMsg',FUNC_MSG),
('fnDecodedStream',FUNC_DECODEDSTREAM),
('pUserData',c_void_p),
('szReserve',c_char*64),
]
class hikplayer:
def __init__(self, videosocket:videowebsocket):
self.dll=WinDLL('F:/hkplayer/bin/VideoSDK.dll')
self.dll.Video_Init.argtypes=[c_char_p]
self.dll.Video_Init.restype=c_int
self.dll.Video_Fini.argtypes=[]
self.dll.Video_Fini.restype=c_int
self.dll.Video_GetLastError.argtypes=[]
self.dll.Video_GetLastError.restype=c_int
self.dll.Video_StartAsynPreview.argtypes=[c_char_p,c_void_p,POINTER(VIDEO_PLAY_REQ)]
self.dll.Video_StartAsynPreview.restype=c_longlong
self.dll.Video_StartPreview.argtypes=[c_char_p,c_void_p,POINTER(VIDEO_PLAY_REQ)]
self.dll.Video_StartPreview.restype=c_longlong
self.dll.Video_StopPreview.argtypes=[c_longlong]
self.dll.Video_StopPreview.restype=c_int
self.videosocket=videosocket
self.hikHandle=-1
self.cb_msgCallback=FUNC_MSG(self.cb_msgCallback)
self.cb_decodedDataCallback=FUNC_DECODEDSTREAM(self.cb_decodedDataCallback)
self.dll.Video_Init(None)
self.box_annotator = sv.BoxAnnotator(
thickness=2,
text_thickness=2,
text_scale=1
)
self.queue_obj=[]
self.abortable_sleep=AbortableSleep()
self.isWebsocketServerRunning=False
self.isSendStreamRunning=False
self.bookLock = Lock()
async def sendstream(self, webSocket):
self.isSendStreamRunning=True
while self.isSendStreamRunning:
try:
img=None
self.bookLock.acquire()
if (len(self.queue_obj)>0):
img=self.queue_obj.pop()
self.bookLock.release();
if (not img==None):
await webSocket.send(img)
except Exception as e:
print(e)
self.isSendStreamRunning=False
def stop(self):
self.isSendStreamRunning=False
self.abortable_sleep.abort()
if (self.hikHandle>0):
self.dll.Video_StopPreview(self.hikHandle)
self.hikHandle=-1
self.bookLock.acquire()
self.queue_obj.clear()
self.bookLock.release();
def play(self,url:str):
req=VIDEO_PLAY_REQ()
req.iHardWareDecode=0
req.pUserData=c_void_p(0)
req.fnStream=FUNC_STREAM(0)
#req.fnMsg=FUNC_MSG(0)
#req.fnDecodedStream=FUNC_DECODEDSTREAM(0)
req.fnMsg=self.cb_msgCallback
req.fnDecodedStream=self.cb_decodedDataCallback
self.hikHandle=self.dll.Video_StartAsynPreview(bytes(url,'ascii'),None,byref(req))
def translate(self,name)->str:
return name
if (name=='person'):
return '人员'
elif (name=='tv'):
return '显示屏'
elif (name=='clock'):
return '仪表'
elif (name=='chair'):
return '椅子'
else:
return name
def cb_decodedDataCallback(self,i64PlayHandle:c_longlong, pDataArray:POINTER(c_char), iDataLen:c_int, iWidth:c_int, iHeight:c_int, iFrameType:c_int, iTimeStamp:c_int, pUserData:c_void_p):
YUV = np.frombuffer(pDataArray[:iDataLen],dtype=np.uint8, count=iDataLen).reshape(iHeight*3//2,iWidth)
bgr = cv2.cvtColor(YUV, cv2.COLOR_YUV420p2BGR)
#bgr=cv2.cvtColor(YUV,cv2.COLOR_YUV2BGR)
result = self.videosocket.model(bgr, agnostic_nms=True)[0]
detections = sv.Detections.from_yolov8(result)
labels = [
f"{self.translate(self.videosocket.model.model.names[class_id])} {confidence:0.2f}"
for _, _, confidence, class_id,_
in detections
]
bgr = self.box_annotator.annotate(
scene=bgr,
detections=detections,
labels=labels
)
_,enc=cv2.imencode('.png', bgr)
self.bookLock.acquire()
self.queue_obj.append(enc.tobytes())
if (len(self.queue_obj)>50):
self.queue_obj.clear()
self.bookLock.release();
#cv2.imshow('t',bgr)
#cv2.waitKey(5)
def cb_msgCallback(self,i64PlayHandle:c_longlong, iMsg:c_int, pUserData:c_void_p):
print(iMsg)
def __del__(self):
self.stop()
class Clients(object):
def __init__(self, server):
self._clients = []
self._id = 0
self.ipackets = Packets.IncomingPackets()
self.server = server
def __contains__(self, item):
if isinstance(item, Clients.Client):
return item in self._clients
elif isinstance(item, int):
return not self.get_client(item) is None
else:
return False
def get_client(self, id):
if not isinstance(id, int):
raise ValueError('id is not instance of int')
for c in self._clients:
if c.id == id:
return c
return None
def new_client(self, socket):
if not isinstance(socket, WebSocketHandler.WebSocketHandler):
raise ValueError('socket is not instance of WebSocketHandler')
if socket not in self:
cl = self.Client(self._id, socket, self)
self._id += 1
self._clients.append(cl)
return cl
else:
raise ValueError('socket already has client')
def remove_client(self, client):
client.logger.info('Disconn