# 图像处理机器视觉课程报告 **Repository Path**: dogeblog/Image_process_course_report ## Basic Information - **Project Name**: 图像处理机器视觉课程报告 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-09-27 - **Last Updated**: 2021-11-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 图像处理与机器视觉课程报告 # 一.问题描述 工厂中经常需要安全生产,故需要检测目前区域内是否有动态物体进入。 但是往往因为视频设备算力或者算法性能问题,无法准确判断动态物体是人还是其他物体。 故设计了一套系统,用于实时动态检测并且判定区域内是否出现人。 # 二.程序以及算法 ## 2.1程序主体流程 1. 检测设备进行高斯混合模型的动态检测 2. 将检测到的图片传输给云端算法 3. 由云端算法yolov5判断图片中是否有人,并且返回人的坐标 4. 检测设备根据云端算法返回的结果绘制图片并且按照时间保存。 ![image-20211105193854773](./image/all.png) ## 2.2高斯混合模型 ### 2.2.1算法原理讲解 ### 2.2.2代码实现 ```python import threading import time import cv2 import numpy as np import pprint import requests DETECTION_URL = "http://10.101.6.64:6666/v1/object-detection/yolov5s" def add_new_cam(rtsp_path, points): # 创建模型 mog = cv2.createBackgroundSubtractorMOG2() # 定义高斯混合模型对象 mog # gmg = cv2.bgsegm.createBackgroundSubtractorGMG() # knn = cv2.createBackgroundSubtractorKNN(detectShadows=False) # 绘制蒙版 cap = cv2.VideoCapture(rtsp_path) ret, frame = cap.read() mask = np.zeros(frame.shape, np.uint8) mask = cv2.fillPoly(mask, [points], (255, 255, 255)) # 初始化计时器用于判断时间 time_now = time.time() # cv2.imshow("mask", mask) while 1: ret, frame = cap.read() frame_to_save = frame.copy() frame_to_show = frame.copy() frame = cv2.bitwise_and(frame, mask) # 混合高斯模型 fgmask = mog.apply(frame) # 使用前面定义的高斯混合模型对象 mog 当前帧的运动目标检测,返回二值图像 gray_frame = fgmask.copy() kernel = np.ones((5, 5), np.uint8) gray_frame = cv2.morphologyEx(gray_frame, cv2.MORPH_OPEN, kernel) # 返回值: contours,轮廓的坐标。 hierarchy,各个框之间父子关系,不常用。 contours, hierarchy = cv2.findContours(gray_frame, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 绘制每一个轮廓框到原始图像 frame 中 for contour in contours: if cv2.contourArea(contour) < 1500: # 计算候选框的面积,如果小于1500,跳过当前候选框 continue (x, y, w, h) = cv2.boundingRect(contour) # 根据轮廓,得到当前最佳矩形框 cv2.rectangle(frame_to_show, (x, y), (x + w, y + h), (255, 255, 0), 2) # 将该矩形框画在当前帧 frame 上 # 根据时间间隔保存图片 interval = time.time() - time_now time_now = time.time() if interval > 1: print("Dynamic object detected,seding detect pic") threading.Thread(target=send_pic, args=(frame_to_save,)).start() cv2.imshow("gray", gray_frame) cv2.imshow("contours", frame_to_show) # 显示当前帧 cv2.waitKey(1) rtsp = 0 points = np.array([(0, 0), (1000, 0), (1000, 1000), (0, 1000)]) add_new_cam(rtsp, points) ``` 其中 ``` threading.Thread(target=send_pic, args=(frame_to_save,)).start() ``` 为发送检测的图片到yolov5服务进行推理 ## 2.3yolov5目标检测算法 ### 2.3.1算法讲解 YOLOv5 is a family of object detection architectures and models pretrained on the COCO dataset, and represents [Ultralytics](https://ultralytics.com/) open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. ### 2.3.2环境配置 运行yolov5需要pytorch框架,而pytorch的gpu版本需要英伟达推出的cuda环境。 因此采用了以下环节配置cuda环境: 1. **nvidia 显卡驱动安装** 有图形界面直接软件更新->附加驱动 就能找到nvidia驱动安装 无图形界面需要去[官网下载run文件](https://dogeblog.gitee.io/2021/09/02/docker之nvidia-docker安装/[https://www.nvidia.com/Download/index.aspx?lang=en-us)自行安装。 显卡必须是nvdia且高于一定算力 2. **docker 安装** 下载并安装 ``` wget -qO- https://get.docker.com/ | sh ``` 使非root用户可以直接运行docker ``` sudo usermod -aG docker 你的用户名 ``` 测试安装是否成功 ``` docker run hello-world ``` 3. **nvidia docker 安装** Ubuntu上的Docker CE可以使用Docker的官方的语句进行设置 ```shell curl https://get.docker.com | sh sudo systemctl start docker sudo systemctl enable docker ``` 设置稳定存储库和GPG密钥: ```shell distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \ && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list ``` 在更新包列表后安装nvidia-docker2包(和依赖项) ``` sudo apt-get update sudo apt-get install -y nvidia-docker2 ``` 设置默认运行时间后,重新启动Docker守护程序完成安装: ``` sudo systemctl restart docker ``` 4. **nvidia docker 运行** 去[nvidia cuda仓库](https://hub.docker.com/r/nvidia/cuda/tags)下载最新的docker 并 运行容器 ``` sudo docker run --rm --gpus all --name yolo nvidia/cuda:11.4.1-devel-ubuntu18.04 ``` 如果需要pytorch的docker,可以直接去[PyTorch | NVIDIA NGC](https://ngc.nvidia.com/catalog/containers/nvidia:pytorch/tags) 5. **torch 安装** 前往[PyTorch官网](https://pytorch.org/)选择你的环境信息得到安装命令 如 ```shell pip3 install torch==1.9.1+cu111 torchvision==0.10.1+cu111 torchaudio==0.9.1 -f https://download.pytorch.org/whl/torch_stable.html ``` ### 2.3.4算法搭建 ``` git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt ``` ### 2.3.5算法调用官方示例 ```python import torch # 加载模型 model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # or yolov5m, yolov5l, yolov5x, custom # 图片路径 img = 'https://ultralytics.com/images/zidane.jpg' # or file, Path, PIL, OpenCV, numpy, list # 推理接口 results = model(img) # 结果显示 results.print() # or .show(), .save(), .crop(), .pandas(), etc. ``` ### 2.3.6后台长期运行yolov5算法 安装screen ``` apt-get install screen -y ``` 通过screen运行程序 ``` screen -S yolocd yolov5/utils/flask_rest_apipython3 restapi.py ``` 退出screen并且保持运行 crtl a d ## 2.4flask网络框架 ### 2.4.1简介 flask 是基于python编写的一个轻量级网络框架 ### 2.4.2环境配置与安装 ``` pip install flask ``` ### 2.4.3服务器主体代码 采用了yolov5项目中自带的restfulapi 更改了其中的端口号,并且加上了日志文件生成的功能。 ```python """ Run a rest API exposing the yolov5s object detection model """ import argparse import io import logging import time import torch from PIL import Image from flask import Flask, request app = Flask(__name__) DETECTION_URL = "/v1/object-detection/yolov5s" @app.route(DETECTION_URL, methods=["POST"]) def predict(): if not request.method == "POST": return if request.files.get("image"): image_file = request.files["image"] image_bytes = image_file.read() img = Image.open(io.BytesIO(image_bytes)) start_time = time.time() results = model(img, size=640) # reduce size=320 for faster inference end_time = time.time() app.logger.info('infer time {}s'.format(str(end_time-start_time))) return results.pandas().xyxy[0].to_json(orient="records") if __name__ == "__main__": parser = argparse.ArgumentParser(description="Flask API exposing YOLOv5 model") parser.add_argument("--port", default=6666, type=int, help="port number") args = parser.parse_args() handler = logging.FileHandler('flask.log') logging_format = logging.Formatter('%(asctime)s %(message)s') handler.setFormatter(logging_format) app.logger.addHandler(handler) model = torch.hub.load("ultralytics/yolov5", "yolov5l", force_reload=False ) # force_reload to recache app.run(host="0.0.0.0", port=args.port) # debug=True causes Restarting with stat ``` ### 2.4.4客户端部分代码 ```python def send_pic(frame_to_save): time_start_send = time.time() # 保存图片 image_data = cv2.imencode('.png', frame_to_save)[1].tobytes() # with open ("data.txt",'w') as f: # f.write(str({"image": image_data})) response = requests.post(DETECTION_URL, files={"image": image_data}).json() time_end_send = time.time() print("detect complete,cousumed {} s".format(str(time_end_send - time_start_send))) # pprint.pprint(response) save_flag = 0 for obj in response: if obj['name'] == 'person' and obj['confidence'] > CONFIDENCE: x1, y1, x2, y2 = int(obj['xmin']), int(obj['ymin']), int(obj['xmax']), int(obj['ymax']) cv2.rectangle(frame_to_save, (x1, y1), (x2, y2), (255, 255, 0), 2) save_flag += 1 if save_flag > 0: cv2.imwrite(filename="image/" + str(time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())) + ".jpg", img=frame_to_save) print(str(time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime())),'detected {} people'.format(str(save_flag))) ``` ### 2.4.5查看日志文件得到运行情况 ``` grep flask.log ``` 部分结果如下 ```shell 2021-09-27 03:03:43,794 infer time 0.08984136581420898s 2021-09-27 03:03:54,405 infer time 0.06490826606750488s 2021-09-27 03:04:05,195 infer time 0.08911895751953125s 2021-09-27 03:04:14,550 infer time 0.08931612968444824s 2021-09-27 03:04:23,533 infer time 0.08862948417663574s 2021-09-27 03:04:46,589 infer time 0.10284876823425293s 2021-09-27 03:05:04,673 infer time 0.06704258918762207s 2021-09-27 03:05:15,910 infer time 0.08734679222106934s 2021-09-27 03:05:38,870 infer time 0.10628700256347656s 2021-09-27 03:05:46,495 infer time 0.06697845458984375s 2021-09-27 03:06:19,265 infer time 0.10350394248962402s 2021-09-27 03:06:31,174 infer time 0.08736324310302734s 2021-09-27 03:06:32,962 infer time 0.0879511833190918s 2021-09-27 03:06:38,889 infer time 0.06657600402832031s 2021-09-27 03:06:43,692 infer time 0.0663297176361084s 2021-09-27 03:06:45,123 infer time 0.08658337593078613s 2021-09-27 03:06:49,458 infer time 0.08734583854675293s 2021-09-27 03:06:52,401 infer time 0.06574249267578125s 2021-09-27 03:07:03,808 infer time 0.08645200729370117s 2021-09-27 03:07:14,878 infer time 0.06605339050292969s 2021-09-27 03:07:42,774 infer time 0.10903763771057129s 2021-09-27 03:08:02,369 infer time 0.07390356063842773s 2021-09-27 03:08:11,318 infer time 0.1408219337463379s 2021-09-27 03:08:11,322 infer time 0.15143203735351562s 2021-09-27 03:08:13,024 infer time 0.08304357528686523s 2021-09-27 03:08:17,973 infer time 0.08363032341003418s 2021-09-27 03:08:22,080 infer time 0.06549215316772461s ``` ## 2.5检测区域设定功能编写 ### 2.5.1原理 **动态检测时**: 使用fillpoly方法做一个图像蒙版,其中需要检测的区域为255,其他区域都为0。之后把蒙版和原图进行与操作,把原图除了蒙版以外区域全部置零,而蒙版处不变。 **目标检测时**:每个通过yolov5预测到的目标,都会对其坐标中心进行判定,如果坐标中心位于代码,则保留该预测目标,否则舍弃。 ### 2.5.2主要代码 设定参数 ```python detect_region = [0.5, 0, 1, 1] # 检测区域划定x1,y1 ,x2,y2 cam_width, cam_height = 1280, 720 # 摄像头分辨率 detect_x1, detect_y1 = int(detect_region[0] * cam_width), int(detect_region[1] * cam_height) detect_x2, detect_y2 = int(detect_region[2] * cam_width), int(detect_region[3] * cam_height) points = np.array([(detect_x1, detect_y1), (detect_x2, detect_y1), (detect_x2, detect_y2), (detect_x1, detect_y2)]) # 动态检测使用mask与bitewise_and运算划定区域 ret, frame = cap.read() mask = np.zeros(frame.shape, np.uint8) mask = cv2.fillPoly(mask, [points], (255, 255, 255)) while (1): ret, frame = cap.read() frame_to_save = frame.copy() frame_to_show = frame.copy() frame = cv2.bitwise_and(frame, mask) # 目标检测判断物体中心是否处于区域内的判定 if detect_x1 <= center_x <= detect_x2 and detect_y1 <= center_y <= detect_y2: ``` # 三.最终结果 ### 3.1动态检测效果 在cpu为4800u的笔记本上可以稳定保持30fps,且cpu占用仅为8% ![image-20210927095502617](./image/image-20210927095502617.png) ### 3.2目标检测效果 在gtx1070笔记本上搭建推理服务,可以稳定运行。 ![image-20210927111857749](./image/image-20210927111857749.png) ![image-20210927110538194](./image/image-20210927110538194.png) 单张图片的传输与推理时间约为0.2秒 算法推理时间约为0.08秒 显卡占用为1.4g,功耗为36w左右 # 四.实验总结 总体效果符合预期,还有以下需要后期优化的点 1.网络传输 如果需要在嵌入式设备运行,需要注意网络传输条件,尽量采用网线传输,防止外部网络信号不佳产生设备掉线从而无法传输图片。 2.动态检测性能优化 以及代码尽量采用C++编写,保证嵌入式设备的性能占用较小。 3.目标检测性能优化 可以采用nvidia tensorrt推理服务,并且采用nginx转发提高并发量。 实验结果为640 * 640大小的图片,yolov5l在rtx3090上推理速度3毫秒一张,最大并发量约为1400张一秒。