diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/billiard.iml b/.idea/billiard.iml
new file mode 100644
index 0000000..f721fe6
--- /dev/null
+++ b/.idea/billiard.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..5d56808
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,461 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..a95a050
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..42b05f7
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app.py b/app.py
index abdc605..665d848 100644
--- a/app.py
+++ b/app.py
@@ -1,9 +1,13 @@
import cv2
import json
import time
+import torch
import requests
+import threading
+import numpy as np
import supervision as sv
+from datetime import datetime
from ultralytics import YOLO
from flask import Flask,request,Response
from multiprocessing import Process, Event
@@ -39,33 +43,78 @@ def stop(id):
@app.route('/show',methods=['POST'])
def show():
- print(request.data)
+ # print(request.json)
+ data = request.json["content"]
+ info(data)
return 'ok'
+def info(data):
+ balls = data["balls"]
+ table = data["table"]
+ text = f"table:{table:>3} "
+ for i in range(16):
+ ball = "#" if "ball"+str(i) in balls else " "
+ text += f"| {i} : {ball} "
+ print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),text)
+
def worker(id,source,region=None,stream=False):
if region == None:
region = 10
else:
region = int(region)
+ print("start loading model...",id,source,region)
model = YOLO('./best.pt')
+ print("start loaded model!!!")
balls = {}
count = 0
- print(source)
+ delay = 0
+ bgn = 0
try:
cap = cv2.VideoCapture(source)
if not cap.isOpened():
print("Error opening video stream.")
+ if source.endswith(".mp4"):
+ fps = cap.get(cv2.CAP_PROP_FPS)
+ delay = 1000.0 / fps
+ print("start video stream... ", fps, delay)
while True:
+ use = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ if bgn != 0 and delay != 0 and time.time()*1000 - bgn < 2*delay:
+ print("sleep",2*delay - (time.time()*1000 - bgn))
+ time.sleep((2*delay - (time.time()*1000 - bgn))/1000)
+ bgn = (time.time()*1000)
ret, frame = cap.read()
+ del(ret)
+ del(frame)
+ ret, frame = cap.read()
+ use += " read:"+str((time.time()*1000) - bgn)
if not ret:
print("Error read video stream.")
- break
- result = model.track(frame,show=False,stream=False,persist=True,device=int(id)%4)
+ cap = cv2.VideoCapture(source)
+ if not cap.isOpened():
+ print("Error opening video stream..")
+ cap = cv2.VideoCapture(source)
+ time.sleep(1)
+ if not cap.isOpened():
+ print("Error opening video stream...")
+ time.sleep(3)
+ if not cap.isOpened():
+ print("Error opening video stream....")
+ break
+ continue
+ result = model.track(frame,device=int(id)%4,tracker='botsort.yaml')
+ use += " track:"+str((time.time()*1000) - bgn)
+ del(ret)
+ del(frame)
result = result[0]
detections = sv.Detections.from_yolov8(result)
if result.boxes.id is not None:
detections.tracker_id = result.boxes.id.cpu().numpy().astype(int)
- detections = detections[(detections.tracker_id != None)]
+ else:
+ detections.tracker_id = np.array([])
+ detections.conf = np.array([])
+ detections.xyxy=np.empty((0, 4), dtype=np.float32)
+ # detections = detections[(detections.tracker_id != None)]
count += 1
names = {}
@@ -84,15 +133,21 @@ def worker(id,source,region=None,stream=False):
balls[name] = ball
names[name] = True
names = {}
+ use += " names:"+str((time.time()*1000) - bgn)
if count < region:
continue
- json_data = json.dumps({"table":id,"balls":balls,"time":int(time.time()*1000)})
+ data = {"table":id,"balls":balls,"time":int(time.time()*1000)}
+ info(data)
+ json_data = json.dumps(data)
balls = {}
count = 0
+ use += " dump:"+str((time.time()*1000) - bgn)
if not stream:
yield json_data
else:
yield f"data: {json_data}\n\n"
+ use += " yield:"+str((time.time()*1000) - bgn)
+ print("model.track",use)
except GeneratorExit:
print("Client disconnected at", time.ctime())
@@ -102,21 +157,47 @@ def workerloop(stop_event,id,source,target=None,region=None):
try:
gen = worker(id,source,region)
for data in gen:
+ use = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ bgn = (time.time()*1000)
if stop_event.is_set():
break
json_data = json.loads(data)
- # 设置请求头
- headers = {
- "Content-Type": "application/json"
- }
+ use += " loads:"+str((time.time()*1000) - bgn)
text = json.dumps({"content":json_data})
- print(text)
- response = requests.post(target, data=text, headers=headers)
+ use += " dumps:"+str((time.time()*1000) - bgn)
- print(response.text)
+ # 创建并启动线程
+ thread = threading.Thread(target=post_request, args=(target, text))
+ thread.start()
+
+ use += " post:"+str((time.time()*1000) - bgn)
+ print("workerloop",use)
finally:
gen.close()
+def post_request(url, data):
+ use = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ bgn = (time.time()*1000)
+ headers = {
+ "Content-Type": "application/json"
+ }
+ response = requests.post(url, data=data,headers=headers)
+ use += " post:"+str((time.time()*1000) - bgn ) +"ms"
+ print("post_request",use,response.text)
+# import pstats
+# import cProfile
+# def test_function():
+# url = "rtmp://rtmp03open.ys7.com:1935/v3/openlive/L05874022_1_1?expire=1726389273&id=625006970167889920&t=2c7f371063e4ad672cb7a7c34b2a236e9ff37b02052f818c9c4fe7ae9632cd0e&ev=100"
+# gen = worker(0,url,5)
+# count = 0
+# for data in gen:
+# count += 1
+# if count > 10:
+# break
+
if __name__ == '__main__':
+ # cProfile.run('test_function()', 'test_function.profile')
+ # p = pstats.Stats('test_function.profile')
+ # p.sort_stats('cumulative').print_stats(100) # Top 10 by cumulative time
app.run("0.0.0.0",threaded=True)
diff --git a/botsort.yaml b/botsort.yaml
new file mode 100644
index 0000000..922a5c0
--- /dev/null
+++ b/botsort.yaml
@@ -0,0 +1,18 @@
+# Ultralytics YOLO 🚀, AGPL-3.0 license
+# Default YOLO tracker settings for BoT-SORT tracker https://github.com/NirAharon/BoT-SORT
+
+tracker_type: botsort # tracker type, ['botsort', 'bytetrack']
+track_high_thresh: 0.3 # threshold for the first association
+track_low_thresh: 0.1 # threshold for the second association
+new_track_thresh: 0.5 # threshold for init new track if the detection does not match any tracks
+track_buffer: 10 # buffer to calculate the time when to remove tracks
+match_thresh: 0.8 # threshold for matching tracks
+# min_box_area: 10 # threshold for min box areas(for tracker evaluation, not used for now)
+# mot20: False # for tracker evaluation(not used for now)
+
+# BoT-SORT settings
+gmc_method: sparseOptFlow # method of global motion compensation
+# ReID model related thresh (not supported yet)
+proximity_thresh: 0.1
+appearance_thresh: 0.25
+with_reid: False
\ No newline at end of file
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 7d39345..068a16a 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -12,6 +12,8 @@ services:
runtime: nvidia
environment:
NVIDIA_VISIBLE_DEVICES: all
+ PYTHONUNBUFFERED: 1
+ # OPENCV_FFMPEG_READ_ATTEMPTS: 16384
logging:
driver: "json-file"
options:
diff --git a/ez.py b/ez.py
new file mode 100644
index 0000000..b5e490e
--- /dev/null
+++ b/ez.py
@@ -0,0 +1,40 @@
+import cv2
+import time
+
+# 获取 ezopen 协议的 URL
+url = "rtmp://rtmp03open.ys7.com:1935/v3/openlive/L05874022_1_1?expire=1726487667&id=625419662355599360&t=228dca5d37b6bead201e80cca3fc5fe74140242278e4eb51a99bcce593cae027&ev=100"
+
+# 创建 VideoCapture 对象
+cap = cv2.VideoCapture(url)
+
+cv2.namedWindow("Video", cv2.WINDOW_NORMAL) # Create a named window
+cv2.resizeWindow("Video", 640, 384) # Resize this window
+
+start_time = time.time()
+count = 0
+
+# 获取视频帧
+while True:
+ ret, frame = cap.read()
+ if time.time() - start_time < 1: # 循环运行直到1秒过去
+ count += 1
+ else:
+ print(count)
+ start_time = time.time()
+ count = 0
+
+ # print(ret)
+ if not ret:
+ print("Error read video stream.")
+ break
+ # 显示视频帧
+ cv2.imshow("Video", frame)
+ # print("0000000000000",ret)
+ # 等待用户按下任意键退出
+ key = cv2.waitKey(1)
+ if key == 27:
+ break
+
+# 释放资源
+cap.release()
+cv2.destroyAllWindows()
diff --git a/show.py b/show.py
new file mode 100644
index 0000000..760001f
--- /dev/null
+++ b/show.py
@@ -0,0 +1,245 @@
+import cv2
+import json
+import time
+import logging
+import threading
+import requests
+import supervision as sv
+
+from datetime import datetime
+from ultralytics import YOLO
+from flask import Flask,request,Response
+from multiprocessing import Process, Event
+
+app = Flask(__name__)
+
+@app.route('/show',methods=['POST'])
+def show():
+ # print(request.json)
+ data = request.json["content"]
+ balls = data["balls"]
+ table = data["table"]
+ text = f"table:{table:>3} "
+ for i in range(16):
+ ball = "#" if "ball"+str(i) in balls else " "
+ text += f"| {i} : {ball} "
+ print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),text)
+ return 'ok'
+import re
+@app.route('/mj',methods=['POST'])
+def mj():
+ print(request.json)
+ if request.json["progress"] == "100%":
+ print(request.json["imageUrl"])
+ sendmsg(request.json["imageUrl"])
+ download_image(request.json["imageUrl"], "MJ", request.json["state"])
+ return 'ok'
+
+@app.route('/cq',methods=['POST'])
+def cq():
+ print(request.json)
+ if request.json["post_type"] != "message":
+ return 'ok'
+ if request.json["message_type"] != "group":
+ return 'ok'
+ if request.json["group_id"] != 116277572:
+ return 'ok'
+ # if request.json["user_id"] != 2132960:
+ # return 'ok'
+
+ thread = threading.Thread(target=handle, args=(request.json,))
+ thread.start()
+ return "ok"
+
+def handle(data):
+ print(data['raw_message'])
+
+ # 正则表达式来匹配URL
+ url_pattern = re.compile(r'url=(.*?)\]')
+
+ # 使用findall来找到所有的URL
+ urls = re.findall(url_pattern, data['raw_message'])
+
+ result = re.sub(r'\[.*?\]', '', data['raw_message'])
+ result = result.replace('\r\n', '')
+
+ name = data["sender"]["card"] or data["sender"]["nickname"]
+
+ base64Array = []
+ # 输出找到的URL
+ for url in urls:
+ print(url)
+
+ download_image(url, "QQ", name)
+ # 从URL下载图片
+ response = requests.get(url)
+ response.raise_for_status() # 如果请求失败,此处将引发异常
+
+ # 将图片数据转换为Base64编码的字节数组
+ image_base64_bytes = base64.b64encode(response.content)
+
+ # 如果您需要将其转换为字符串,您可以使用.decode('utf-8')将字节数组转换为字符串
+ image_base64_str = image_base64_bytes.decode('utf-8')
+
+ # 打印Base64编码的字节数组
+ # print(image_base64_bytes)
+ base64Array.append('data:image/jpeg;base64,'+image_base64_str)
+
+ if len(base64Array) == 0:
+ return 'ok'
+ prompt = 'game assets,game ui,animal,flower,plant,forest,cute,baby,magical,spirit,fairy,elf,glowing light,anime style,seeming very happy,from above,ultra detailed,soft,on white background'
+ if result != '':
+ prompt = result
+ # 示例调用
+ params = {
+ 'base64Array':base64Array,
+ 'notifyHook': 'http://hk.luanhailiang.cn:5000/mj',
+ 'prompt': prompt,
+ 'state': name
+ }
+
+ response = imagine(params)
+ print(response.json())
+ time.sleep(3)
+ params['prompt'] = prompt + " --iw 2 --niji 5"
+ params['state'] = name+"_niji"
+ response = imagine(params)
+ print(response.json())
+ time.sleep(3)
+ params['prompt'] = prompt + " --iw 2 --style raw"
+ params['state'] = name+"_raw"
+ response = imagine(params)
+ print(response.json())
+
+ return 'ok'
+
+def download_image(url, t, name):
+ """
+ 从指定URL下载图片并保存到本地文件。
+
+ :param url: 图片的URL。
+ :param local_filename: 要保存图片的本地文件名。
+ """
+
+ local_filename = f"y:\美术\参考收集\{t}\{datetime.now().strftime('%Y%m%d%H%M%S')}_{name}"
+ response = requests.get(url)
+ if response.status_code == 200: # HTTP状态码200表示请求成功
+ # 获取Content-Type响应头
+ content_type = response.headers['Content-Type']
+ # 判断图片格式
+ ext = ""
+ if 'jpeg' in content_type or 'jpg' in content_type:
+ ext = '.jpg'
+ print('The image is in JPEG format.')
+ elif 'png' in content_type:
+ ext = '.png'
+ print('The image is in PNG format.')
+ elif 'gif' in content_type:
+ ext = '.gif'
+ print('The image is in GIF format.')
+ elif 'webp' in content_type:
+ ext = '.webp'
+ print('The image is in WEBP format.')
+ else:
+ ext = '.png'
+ print(f'Unknown image format: {content_type}')
+ local_filename += ext
+ with open(local_filename, 'wb') as f:
+ f.write(response.content)
+ print(f"Image successfully downloaded to {local_filename}")
+ else:
+ print(f"Error downloading image, HTTP status code: {response.status_code}")
+
+
+import base64
+import requests
+
+
+def imagine(params):
+ """
+ 提交Imagine任务
+
+ :param params: imagineDTO,一个字典,包含以下键:
+ - base64Array: 垫图base64数组
+ - notifyHook: 回调地址, 为空时使用全局notifyHook
+ - prompt: 提示词
+ - state: 自定义参数
+ :return: 返回服务器的响应
+ """
+ # API端点
+ url = 'http://127.0.0.1:8080/mj/submit/imagine'
+
+ # 发送POST请求
+ response = requests.post(url, json=params)
+
+ # 如果需要,处理响应(例如,检查响应状态,解析响应主体等)
+
+ return response
+
+
+def sendmsg(url):
+ # 设置 go-cqhttp 服务的 URL 和端口
+ api_url = 'http://localhost:5700/send_msg'
+
+ # 设置要发送的消息参数
+ data = {
+ 'group_id': 5464741, # 接收消息的用户的 QQ 号
+ 'message_type': 'group', # 消息类型
+ 'message': f'[CQ:image,file={url}]' # 消息内容,使用 CQ码 格式
+ }
+
+ # 发送 POST 请求到 go-cqhttp 服务
+ response = requests.post(api_url, data=data)
+
+ # 输出响应
+ print(response.json())
+
+if __name__ == '__main__':
+
+ # # 这是包含URL的示例文本
+ # text = '[CQ:image,file=42c93be3dbe10bfa79ad93ce1baed561.image,subType=1,url=https://gchat.qpic.cn/gchatpic_new/1183464602/691534145-2408237736-42C93BE3DBE10BFA79AD93CE1BAED561/0?term=2&is_origin=0][CQ:image,file=42c93be3dbe10bfa79ad93ce1baed561.image,subType=1,url=https://gchat.qpic.cn/gchatpic_new/1183464602/691534145-2408237736-42C93BE3DBE10BFA79AD93CE1BAED561/0?term=2&is_origin=0]'
+
+ # # 正则表达式来匹配URL
+ # url_pattern = re.compile(r'url=(.*?)\]')
+
+
+
+ # # 使用findall来找到所有的URL
+ # urls = re.findall(url_pattern, text)
+
+ # # 输出找到的URL
+ # for url in urls:
+ # print(url)
+
+
+
+ # # 从URL下载图片
+ # response = requests.get(url)
+ # response.raise_for_status() # 如果请求失败,此处将引发异常
+
+ # # 将图片数据转换为Base64编码的字节数组
+ # image_base64_bytes = base64.b64encode(response.content)
+
+ # # 如果您需要将其转换为字符串,您可以使用.decode('utf-8')将字节数组转换为字符串
+ # image_base64_str = image_base64_bytes.decode('utf-8')
+
+ # # 打印Base64编码的字节数组
+ # # print(image_base64_bytes)
+
+ # # 示例调用
+ # params = {
+ # 'base64Array': ['data:image/jpeg;base64,'+image_base64_str],
+ # 'notifyHook': 'http://hk.luanhailiang.cn:5000/mj',
+ # 'prompt': 'character design, game assets, game ui, cute, soft',
+ # 'state': ''
+ # }
+
+ # response = imagine(params)
+ # print(response.json())
+
+
+
+
+
+ app.logger.setLevel(logging.ERROR)
+ app.run("0.0.0.0",port=8000,threaded=True)
diff --git a/test.py b/test.py
index a712d35..f3cc25c 100644
--- a/test.py
+++ b/test.py
@@ -3,9 +3,10 @@ from urllib import parse
from ultralytics import YOLO
# Configure the tracking parameters and run the tracker
-model = YOLO('best.pt')
-source2 = "rtmp://rtmp03open.ys7.com:1935/v3/openlive/L05874022_1_1?expire=1726487667&id=625419662355599360&t=228dca5d37b6bead201e80cca3fc5fe74140242278e4eb51a99bcce593cae027&ev=100"
+# model = YOLO('best.pt')
+# source2 = "rtmp://rtmp03open.ys7.com:1935/v3/openlive/L05874022_1_1?expire=1726487667&id=625419662355599360&t=228dca5d37b6bead201e80cca3fc5fe74140242278e4eb51a99bcce593cae027&ev=100"
# source = parse.urlencode({"source": source2})
# source = "./videos/123.mp4"
-results = model.track(source=source2, conf=0.3, iou=0.5, show=True)
-
+# results = model.track(source=source2, conf=0.3, iou=0.5, show=True)
+model = YOLO('best.pt')
+results = model.track(source="./videos/123.mp4", tracker='botsort.yaml', show=True)
diff --git a/videos/123123.mp4 b/videos/123123.mp4
new file mode 100644
index 0000000..619a13d
--- /dev/null
+++ b/videos/123123.mp4
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:50f1d450d1e975b5a16160021777e2daf928db5ec5a90c9d7691a9a7cb3c7ad3
+size 15405787