如何在PHP中获取YOLOv4 Python目标检测的输出结果?
问题描述
使用YOLOv4的Python目标检测脚本,终端运行时可正常打印检测到的物体及对应置信度,但通过PHP调用时返回空结果,var_dump($output)返回NULL。补充测试发现:Python脚本在PHP调用时无法写入文件,终端运行则正常;此前YOLOv3可轻松实现PHP调用,不清楚YOLOv4有何变化。
核心代码片段:
- Python脚本
yolo_video.py中通过print输出检测结果 - PHP调用代码使用
shell_exec执行Python命令
解决方案
1. 强制刷新Python输出缓冲区
Python的print默认在非交互模式下会缓冲输出,导致PHP无法实时捕获结果。修改print语句添加flush=True参数:
# 替换原输出代码 print("found", flush=True) print(confidences[i], flush=True) print(class_names[classIds[i]], flush=True)
或在脚本开头全局设置强制刷新:
import sys sys.stdout = sys.stderr = open('/dev/stdout', 'w', buffering=1)
2. 捕获标准错误输出
shell_exec仅捕获标准输出(stdout),若Python脚本出错输出到标准错误(stderr),不会被PHP捕获。修改PHP代码将stderr重定向到stdout:
$command = escapeshellcmd('python3 yolo_video.py -i video.mp4 -o video_out.avi 2>&1'); $output = shell_exec($command); var_dump($output);
此操作可暴露脚本执行时的权限、路径或依赖错误。
3. 修复权限与路径问题
- 权限问题:PHP运行用户(通常为www-data)可能无脚本或视频文件的读写权限,执行以下命令开放权限:
chown -R www-data:www-data /绝对路径/到/yolov4目录 chmod -R 755 /绝对路径/到/yolov4目录 - 相对路径问题:PHP调用时的工作目录与终端不同,将脚本中的相对路径改为绝对路径:
base_path = "/绝对路径/到/yolov4目录" weights = glob.glob(f"{base_path}/yolo/*.weights")[0] labels = glob.glob(f"{base_path}/yolo/*.txt")[0] cfg = glob.glob(f"{base_path}/yolo/*.cfg")[0]
4. 禁用CV2图形界面
PHP运行环境无图形界面,cv2.waitKey(1)会导致脚本阻塞或出错。修改循环逻辑并添加-d 0参数禁用显示:
- Python脚本替换循环:
while True: (grabbed, frame) = vc.read() if not grabbed: break frame = cv2.resize(frame, (args.height, args.width)) detect(frame, net, layer) if writer is not None: writer.write(frame) - PHP调用添加参数:
$command = escapeshellcmd('python3 yolo_video.py -i video.mp4 -o video_out.avi -d 0 2>&1');
5. 使用proc_open替代shell_exec
proc_open可实时捕获stdout和stderr,比shell_exec更可靠:
$descriptorspec = [ 0 => ["pipe", "r"], // 标准输入 1 => ["pipe", "w"], // 标准输出 2 => ["pipe", "w"] // 标准错误 ]; $process = proc_open('python3 yolo_video.py -i video.mp4 -o video_out.avi -d 0', $descriptorspec, $pipes); if (is_resource($process)) { $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); foreach ($pipes as $pipe) fclose($pipe); proc_close($process); echo "输出结果:<br>" . nl2br($stdout); echo "错误信息:<br>" . nl2br($stderr); }
内容的提问来源于stack exchange,提问作者Ryan D
相关产品推荐
相关产品推荐

