基于Python的图像处理与机器视觉系统

一.问题描述

工厂中经常需要安全生产,故需要检测目前区域内是否有动态物体进入。

但是往往因为视频设备算力或者算法性能问题,无法准确判断动态物体是人还是其他物体。

故设计了一套系统,用于实时动态检测并且判定区域内是否出现人。

二.程序以及算法

2.1程序主体流程

  1. 检测设备进行高斯混合模型的动态检测

  2. 将检测到的图片传输给云端算法

  3. 由云端算法yolov5判断图片中是否有人,并且返回人的坐标

  4. 检测设备根据云端算法返回的结果绘制图片并且按照时间保存。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Nxl88JJ-1641958264198)(./image/all.png)]

2.2高斯混合模型

2.2.1算法原理讲解

2.2.2代码实现

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 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文件自行安装。

    显卡必须是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的官方的语句进行设置

    curl https://get.docker.com | sh
    sudo systemctl start docker
    sudo systemctl enable docker
    

    设置稳定存储库和GPG密钥:

    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仓库下载最新的docker 并 运行容器

    sudo docker run --rm --gpus all --name yolo  nvidia/cuda:11.4.1-devel-ubuntu18.04
    

    如果需要pytorch的docker,可以直接去PyTorch | NVIDIA NGC

  5. torch 安装

    前往PyTorch官网选择你的环境信息得到安装命令

    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算法调用官方示例

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

更改了其中的端口号,并且加上了日志文件生成的功能。

"""
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客户端部分代码

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

部分结果如下

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主要代码

设定参数

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%

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DucCi91M-1641958264200)(./image/image-20210927095502617.png)]

3.2目标检测效果

在gtx1070笔记本上搭建推理服务,可以稳定运行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PlXC7fSo-1641958264200)(./image/image-20210927111857749.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CFk03lKp-1641958264201)(./image/image-20210927110538194.png)]

单张图片的传输与推理时间约为0.2秒

算法推理时间约为0.08秒

显卡占用为1.4g,功耗为36w左右

四.实验总结

总体效果符合预期,还有以下需要后期优化的点

1.网络传输

如果需要在嵌入式设备运行,需要注意网络传输条件,尽量采用网线传输,防止外部网络信号不佳产生设备掉线从而无法传输图片。

2.动态检测性能优化

以及代码尽量采用C++编写,保证嵌入式设备的性能占用较小。

3.目标检测性能优化

可以采用nvidia tensorrt推理服务,并且采用nginx转发提高并发量。

实验结果为640 * 640大小的图片,yolov5l在rtx3090上推理速度3毫秒一张,最大并发量约为1400张一秒。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值