将PaddleDetection识别图像推流到浏览器
2024-10-22 14:52:45

将PaddleDetection识别图像推流到浏览器

经过之前的学习,我们已经能成功将人脸的是否瞌睡特征识别处理了。那么下面我们即将介绍使用ffmpeg将识别后的内容推送到RTMP服务器(SRS),并且使得客户端能浏览识别结果。

这一步是非常关键的,因为它将允许您将实时的识别结果传送到在线平台,使您能够实时监测和分享这些信息。通过将识别的内容流式传输到 RTMP 服务器,您可以为客户端提供一个实时、可视化的接口,以便他们能够及时了解到人脸瞌睡特征的状态。

在接下来的过程中,我们将优化流程,确保识别结果能够顺利传送到 RTMP 服务器,并且为客户端提供一个用户友好的界面,以便他们能够轻松地浏览和访问这些重要的识别信息。这将有助于提高监测和管理人员瞌睡情况的效率和准确性。

1693736341949

ffmpeg安装

FFmpeg(Fast Forward MPEG)是一个开源多媒体框架,它提供了一组用于处理音频、视频和多媒体数据的工具和库。FFmpeg 可以执行多种多媒体处理任务,包括:

  1. 音频和视频编解码: FFmpeg 可以用于将音频和视频从一种格式转换为另一种格式,包括不同的编解码器和容器格式。它支持许多常见的音频和视频编解码器,如H.264、H.265、AAC、MP3等。
  2. 流媒体处理: FFmpeg 可以用于处理和转码实时音频和视频流,以便进行实时流媒体传输。这使得它非常适用于视频会议、直播流、视频监控等应用。
  3. 图像和音频处理: FFmpeg 支持图像和音频处理,包括剪切、裁剪、调整大小、合并、提取、添加字幕、水印等操作。
  4. 屏幕录制: FFmpeg 可以用于屏幕录制,捕获计算机屏幕上的活动并将其编码为视频文件。
  5. 多媒体信息检索: FFmpeg 还包含用于检索多媒体文件信息的工具,例如文件格式、编解码器详细信息、流信息等。
  6. 音频和视频编辑: 虽然 FFmpeg 提供了基本的音频和视频处理工具,但它通常被用作底层库,供其他多媒体编辑软件和工具使用。

FFmpeg 是跨平台的,可以在多个操作系统上运行,包括Linux、Windows、macOS等。由于其强大的功能和开源性质,FFmpeg 被广泛用于多媒体应用程序、流媒体服务、视频编辑工具、视频转换工具等各种领域。它提供了丰富的命令行工具和API,使开发人员可以轻松地执行各种多媒体处理任务。

http://ffmpeg.org/download.html#build

1693735394030

https://www.gyan.dev/ffmpeg/builds/

1693735441746

1693735604350

修改推理代码加入推流

改造predict_video函数

修改PaddleDetection的deploy/infer.py文件约453行,加入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 在顶部引入
import subprocess

# ========================================================================
# RTMP服务器地址
rtmp_server = r'rtmp://127.0.0.1:1935/live/12345678'
sizeStr = '{}x{}'.format(width, height)
print(sizeStr)
command = ['ffmpeg',
'-y', '-an', # 无需询问即可覆盖输出文件
'-f', 'rawvideo', # 强制输入或输出文件格式
'-vcodec', 'rawvideo', # 设置视频编解码器。这是-codec:v的别名
'-pix_fmt', 'bgr24', # 设置像素格式
'-s', sizeStr, # 设置图像大小
'-r', '25', # 设置帧率
'-i', '-', # 输入
'-c:v', 'libx264', # 编解码器
'-pix_fmt', 'yuv420p', # 像素格式
'-preset', 'ultrafast', # 调节编码速度和质量的平衡
'-f', 'flv', # 强制输入或输出文件格式
'-tune', 'zerolatency', # 视频类型和视觉优化
rtmp_server]
pipe = subprocess.Popen(command, shell=False, stdin=subprocess.PIPE)
# ------------------------------------------------------------------------

改造后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def predict_video(self, video_file, camera_id):
video_out_name = 'output.mp4'
if camera_id != -1:
capture = cv2.VideoCapture(camera_id)
else:
capture = cv2.VideoCapture(video_file)
video_out_name = os.path.split(video_file)[-1]
# Get Video info : resolution, fps, frame count
width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(capture.get(cv2.CAP_PROP_FPS))
frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
print("fps: %d, frame_count: %d" % (fps, frame_count))

if not os.path.exists(self.output_dir):
os.makedirs(self.output_dir)
out_path = os.path.join(self.output_dir, video_out_name)
fourcc = cv2.VideoWriter_fourcc(* 'mp4v')
writer = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
index = 1

# ========================================================================
# RTMP服务器地址
rtmp_server = r'rtmp://127.0.0.1:1935/live/12345678'
sizeStr = '{}x{}'.format(width, height)
print(sizeStr)
command = ['ffmpeg',
'-y', '-an', # 无需询问即可覆盖输出文件
'-f', 'rawvideo', # 强制输入或输出文件格式
'-vcodec', 'rawvideo', # 设置视频编解码器。这是-codec:v的别名
'-pix_fmt', 'bgr24', # 设置像素格式
'-s', sizeStr, # 设置图像大小
'-r', '25', # 设置帧率
'-i', '-', # 输入
'-c:v', 'libx264', # 编解码器
'-pix_fmt', 'yuv420p', # 像素格式
'-preset', 'ultrafast', # 调节编码速度和质量的平衡
'-f', 'flv', # 强制输入或输出文件格式
'-tune', 'zerolatency', # 视频类型和视觉优化
rtmp_server]
pipe = subprocess.Popen(command, shell=False, stdin=subprocess.PIPE)
# ------------------------------------------------------------------------

while (1):
ret, frame = capture.read()
if not ret:
break
print('detect frame: %d' % (index))
index += 1
results = self.predict_image([frame[:, :, ::-1]], visual=False)

im = visualize_box_mask(
frame,
results,
self.pred_config.labels,
threshold=self.threshold)
im = np.array(im)
writer.write(im)

if camera_id != -1:
cv2.imshow('Mask Detection', im)
pipe.stdin.write(im.tostring())
if cv2.waitKey(1) & 0xFF == ord('q'):
break
writer.release()

增加函数boxinfo

得到推理结果的标签信息以及对该标签的打分信息

1
2
3
4
5
6
7
8
9
10
11
def boxinfo(np_boxes, labels, threshold=0.5):
expect_boxes = (np_boxes[:, 1] > threshold) & (np_boxes[:, 0] > -1)
np_boxes = np_boxes[expect_boxes, :]

results = []
for dt in np_boxes:
clsid, bbox, score = int(dt[0]), dt[2:], dt[1]
if len(bbox) == 4:
results.append({"label": labels[clsid], "score": score})

return results

一段时间内出现瞌睡次数的累计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import time

# 初始化计时器和事件计数器
start_time = time.time()
event_counter = 0

# 模拟事件,每隔一秒发生一次,持续10秒
for _ in range(10):
# 模拟事件发生
event_counter += 1
print("Event occurred!")

# 等待一秒
time.sleep(1)

# 检查是否已经过了5秒
current_time = time.time()
if current_time - start_time >= 5:
# 输出累计的事件次数
print(f"Events in the last 5 seconds: {event_counter}")
# 重置计时器和事件计数器
start_time = current_time
event_counter = 0

Predict_video最终改造成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
def predict_video(self, video_file, camera_id):
# video_out_name = 'output.mp4'
if camera_id != -1:
capture = cv2.VideoCapture(camera_id)
else:
capture = cv2.VideoCapture(video_file)
# video_out_name = os.path.split(video_file)[-1]
# Get Video info : resolution, fps, frame count
width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(capture.get(cv2.CAP_PROP_FPS))
frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
print("fps: %d, frame_count: %d" % (fps, frame_count))

if not os.path.exists(self.output_dir):
os.makedirs(self.output_dir)
# out_path = os.path.join(self.output_dir, video_out_name)
# fourcc = cv2.VideoWriter_fourcc(* 'mp4v')
# writer = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
index = 1

# ========================================================================
# RTMP服务器地址
rtmp_server = r'rtmp://127.0.0.1:1935/live/12345678'
sizeStr = '{}x{}'.format(width, height)
print(sizeStr)
command = ['ffmpeg',
'-y', '-an', # 无需询问即可覆盖输出文件
'-f', 'rawvideo', # 强制输入或输出文件格式
'-vcodec', 'rawvideo', # 设置视频编解码器。这是-codec:v的别名
'-pix_fmt', 'bgr24', # 设置像素格式
'-s', sizeStr, # 设置图像大小
'-r', '25', # 设置帧率
'-i', '-', # 输入
'-c:v', 'libx264', # 编解码器
'-pix_fmt', 'yuv420p', # 像素格式
'-preset', 'ultrafast', # 调节编码速度和质量的平衡
'-f', 'flv', # 强制输入或输出文件格式
'-tune', 'zerolatency', # 视频类型和视觉优化
rtmp_server]
pipe = subprocess.Popen(command, shell=False, stdin=subprocess.PIPE)
# ------------------------------------------------------------------------

# 初始化计时器和事件计数器
start_time = time.time()
event_counter = 0

while (1):
ret, frame = capture.read()
if not ret:
break
print('detect frame: %d' % (index))
index += 1
results = self.predict_image([frame[:, :, ::-1]], visual=False)

print("\n\n==============================================\n")
# label score
result = boxinfo(results['boxes'], self.pred_config.labels)
print(result)
print("\n\n==============================================\n")

# 条件判断 累加
if len(result) > 0:
if result[0]['score'] > 0.5 and result[0]['label'] == 'bicycle':
event_counter += 1


im = visualize_box_mask(
frame,
results,
self.pred_config.labels,
threshold=self.threshold)
im = np.array(im)
# writer.write(im)

if camera_id != -1:
cv2.imshow('Mask Detection', im)
pipe.stdin.write(im.tostring())
if cv2.waitKey(1) & 0xFF == ord('q'):
break

# 检查是否已经过了5秒
current_time = time.time()
if current_time - start_time >= 5:
# 输出累计的事件次数
print("\n\n🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕🚕\n")
print(f"5秒内发生的次数: {event_counter}")
print("\n\n🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩🤩\n")

if event_counter > 60:
print('打瞌睡')
response = requests.post('http://127.0.0.1:5000/targetsleep')
if response.status_code == 200:
# 打印响应内容
print(response.text)
else:
print('请求失败,状态码:', response.status_code)

# 重置计时器和事件计数器
start_time = current_time
event_counter = 0

# writer.release()