基于Python的视频采集设备的图像处理与机器视觉

一.问题描述

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

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

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

二.程序以及算法

2.1程序主体流程

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

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

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

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

在这里插入图片描述

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 http://www.biyezuopin.vip
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()
    http://www.biyezuopin.vip
    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%

在这里插入图片描述

3.2目标检测效果

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

在这里插入图片描述
在这里插入图片描述

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

算法推理时间约为0.08秒

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

四.实验总结

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

1.网络传输

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

2.动态检测性能优化

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

3.目标检测性能优化

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

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值