引言
下面展示的是我们在智能车运行过程中的前端推理实现,通过摄像头捕捉图像并实时进行推理处理。本部分记录了前端推理实现的详细步骤和代码示例。
前端推理实现
前端推理程序是智能车实时处理图像数据的重要部分,通过调用后台推理服务,实现对图像的实时分析与处理。以下是前端推理实现的代码。
-
导入必要的库 首先,我们需要导入相关库:
#!/usr/bin/python # -*- coding: utf-8 -*- import zmq import cv2 import numpy as np import time import json import subprocess import os, sys # 添加上两层目录 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) import psutil from log_info import logger
-
zmq
用于网络通信。 -
cv2
用于图像处理。 -
numpy
用于数组操作。 -
time
用于时间控制。 -
json
用于处理JSON格式的数据。 -
subprocess
用于执行系统命令。 -
os
和sys
用于操作系统相关功能。 -
psutil
用于获取系统进程信息。 -
logger
用于记录日志。
-
辅助函数 定义一些辅助函数,用于获取ZMQ客户端和Python进程信息:
def get_zmp_client(port): context = zmq.Context() socket = context.socket(zmq.REQ) res = socket.connect(f"tcp://127.0.0.1:{port}") return socket def get_python_processes(): python_processes = [] for proc in psutil.process_iter(['pid', 'name', 'cmdline']): try: if 'python' in proc.info['name'].lower() and len(proc.info['cmdline']) > 1 and len(proc.info['cmdline'][1]) < 100: info = [proc.info['pid'], proc.info['cmdline'][1]] python_processes.append(info) except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass return python_processes
-
定义Bbox类 编写
Bbox
类,用于处理边界框的转换和归一化:
class Bbox: def __init__(self, box=None, rect=None, size=[640, 480]) -> None: self.size = np.array(size) / 2 self.size_concat = np.concatenate((self.size, self.size)) if box is not None: box_np = np.array(box) if (np.abs(box_np) < 2).all(): self.box_normalise = box_np self.box = self.denormalise(box_np, self.size) else: self.box = box_np self.box_normalise = self.normalise(box_np, self.size) self.rect = self.box_to_rect(self.box, self.size) elif rect is not None: self.rect = np.array(rect) self.box = self.rect_to_box(self.rect, self.size) self.box_normalise = self.normalise(self.box, self.size) def get_rect(self): return self.rect def get_box(self): return self.box @staticmethod def normalise(box, size): return box / np.concatenate((size, size)) @staticmethod def denormalise(box_nor, size): return (box_nor * np.concatenate((size, size))).astype(np.int32) @staticmethod def rect_to_box(rect, size): pt_tl = rect[:2] pt_br = rect[2:] pt_center = (pt_tl + pt_br) / 2 - size box_wd = pt_br - pt_tl return np.concatenate((pt_center, box_wd)).astype(np.int32) @staticmethod def box_to_rect(box, size): pt_center = box[:2] box_wd = box[2:] pt_tl = (size + pt_center - box_wd / 2).astype(np.int32) pt_br = (size + pt_center + box_wd / 2).astype(np.int32) rect = np.concatenate((pt_tl, pt_br)) max_size = np.concatenate((size, size))*2 np.clip(rect, 0, max_size, out=rect) return rect
-
定义客户端接口类 编写
ClintInterface
类,用于与后台推理服务进行通信:
class ClintInterface: configs = [ {'name':'lane', 'infer_type': 'LaneInfer', 'params': [], 'port':5001, 'img_size':[128, 128]}, {'name':'task', 'infer_type': 'YoloeInfer', 'params': ['task_model3'], 'port':5002, 'img_size':[416, 416]}, {'name':'front', 'infer_type':'YoloeInfer', 'params': ['front_model2'], 'port':5003, 'img_size':[416, 416]}, {'name':'ocr', 'infer_type':'OCRReco', 'params': [], 'port':5004,'img_size':None}, {'name':'humattr', 'infer_type':'HummanAtrr', 'params': [], 'port':5005, 'img_size':None}, {'name':'mot', 'infer_type':'MotHuman', 'params': [], 'port':5006, 'img_size':None} ] def __init__(self, name): logger.info("{}连接服务器...".format(name)) model_cfg = self.get_config(name) self.img_size = model_cfg['img_size'] self.client = self.get_zmp_client(model_cfg['port']) infer_back_end_file = "infer_back_end.py" self.check_back_python(infer_back_end_file) flag = False while True: if self.get_state(): if flag: logger.info("") break print('.', end='', flush=True) time.sleep(1) flag = True logger.info("{}连接服务器成功".format(name)) def check_back_python(self, file_name): dir_file = os.path.abspath(os.path.dirname(__file__)) file_path = os.path.join(dir_file, file_name) if not os.path.exists(file_path): raise Exception("后台脚本文件不存在") py_lists = get_python_processes() for py_iter in py_lists: if file_name in py_iter[1]: return else: logger.info("开启{}脚本, 后台运行中, 请等待".format(file_name)) cmd_str = 'python3 ' + file_path + ' &' subprocess.Popen(cmd_str, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(1) def get_config(self, name): for conf in self.configs: if conf['name'] == name: return conf @staticmethod def get_zmp_client(port): context = zmq.Context() socket = context.socket(zmq.REQ) res = socket.connect(f"tcp://127.0.0.1:{port}") return socket def __call__(self, *args, **kwds): return self.get_infer(*args, **kwds) def get_state(self): data = bytes('ATATA', encoding='utf-8') self.client.send(data) response = self.client.recv() response = json.loads(response) return response def get_infer(self, img): if self.img_size is not None: img = cv2.resize(img, self.img_size) img = cv2.imencode('.jpg', img)[1].tobytes() data = bytes('image', encoding='utf-8') + img self.client.send(data) response = self.client.recv() response = json.loads(response) return response
-
主函数 编写主函数,启动前端推理客户端:
def main_client(): from camera import Camera cap = Camera(2, 640, 480) infer_client = ClintInterface("ocr") last_time = time.time() while True: img = cap.read() dets_ret = infer_client.get_infer(img[300:, 200:460]) print(dets_ret) cv2.imshow("img", img) key = cv2.waitKey(1) if key == ord('q'): break fps = 1 / (time.time() - last_time) last_time = time.time() print("fps:", fps) cap.close() cv2.destroyAllWindows()
-
停止进程函数 编写停止进程的函数:
def stop_process(py_str): py_lists = get_python_processes() for py_procees in py_lists: pid_id, py_name = py_procees[0], py_procees[1] if py_str in py