【python】OpenCV—Mask RCNN for Object Detection and Instance Segmentation

news2024/11/17 17:28:45

在这里插入图片描述

文章目录

  • 1、任务描述
  • 2、MASR RCNN 网络结构
  • 3、方法实现
  • 4、结果展示
  • 5、涉及到的库
    • getPerfProfile
  • 6、参考

1、任务描述

在这里插入图片描述

利用 mask rcnn 网络,进行图片和视频的目标检测和实例分割

2、MASR RCNN 网络结构

在这里插入图片描述

3、方法实现

# Copyright (C) 2018-2019, BigVision LLC (LearnOpenCV.com), All Rights Reserved.
# Author : Sunita Nayak
# Article : https://www.learnopencv.com/deep-learning-based-object-detection-and-instance-segmentation-using-mask-r-cnn-in-opencv-python-c/
# License: BSD-3-Clause-Attribution (Please read the license file.)
# This work is based on OpenCV samples code (https://opencv.org/license.html)

import cv2 as cv
import argparse
import numpy as np
import os.path
import sys
import random

# Initialize the parameters
confThreshold = 0.5  # Confidence threshold
maskThreshold = 0.3  # Mask threshold

parser = argparse.ArgumentParser(description='Use this script to run Mask-RCNN object detection and segmentation')
parser.add_argument('--image', help='Path to image file.')
parser.add_argument('--video', help='Path to video file.', default="cars.mp4")
parser.add_argument("--device", default="gpu", help="Device to inference on")
args = parser.parse_args()

"""
python mask_rcnn.py --image ./images/person.jpg --device cpu
python mask_rcnn.py --video ./cars.mp4 --device cpu
"""


# Draw the predicted bounding box, colorize and show the mask on the image
def drawBox(frame, classId, conf, left, top, right, bottom, classMask):
    # Draw a bounding box.
    cv.rectangle(frame, (left, top), (right, bottom), (255, 178, 50), 3)

    # Print a label of class.
    label = '%.2f' % conf
    if classes:
        assert (classId < len(classes))
        label = '%s:%s' % (classes[classId], label)  # 'person:1.00'

    # Display the label at the top of the bounding box
    labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
    top = max(top, labelSize[1])
    cv.rectangle(frame, (left, top - round(1.5 * labelSize[1])), (left + round(1.5 * labelSize[0]), top + baseLine),
                 (255, 255, 255), cv.FILLED)
    cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 0), 1)

    # Resize the mask, threshold, color and apply it on the image
    classMask = cv.resize(classMask, (right - left + 1, bottom - top + 1))
    mask = (classMask > maskThreshold)
    roi = frame[top:bottom + 1, left:right + 1][mask]

    # color = colors[classId%len(colors)]
    # Comment the above line and uncomment the two lines below to generate different instance colors
    colorIndex = random.randint(0, len(colors) - 1)
    color = colors[colorIndex]

    frame[top:bottom + 1, left:right + 1][mask] = ([0.3 * color[0], 0.3 * color[1], 0.3 * color[2]] + 0.7 * roi).astype(
        np.uint8)

    # Draw the contours on the image
    mask = mask.astype(np.uint8)
    contours, hierarchy = cv.findContours(mask, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    cv.drawContours(frame[top:bottom + 1, left:right + 1], contours, -1, color, 3, cv.LINE_8, hierarchy, 100)


# For each frame, extract the bounding box and mask for each detected object
def postprocess(boxes, masks):
    # Output size of masks is NxCxHxW where
    # N - number of detected boxes
    # C - number of classes (excluding background)
    # HxW - segmentation shape
    numClasses = masks.shape[1]  # 90
    numDetections = boxes.shape[2]  # 100

    frameH = frame.shape[0]  # 531
    frameW = frame.shape[1]  # 800

    for i in range(numDetections):  # traverse top 100 ROI
        box = boxes[0, 0, i]  # (1, 1, 100, 7) -> (7,)
        # array([0.        , 0.        , 0.99842095, 0.7533724 , 0.152397  , 0.92448074, 0.9131955 ], dtype=float32)
        mask = masks[i]  # (100, 90, 15, 15) -> (90, 15, 15)
        score = box[2]  # 0.99842095
        if score > confThreshold:
            classId = int(box[1])

            # Extract the bounding box
            left = int(frameW * box[3])
            top = int(frameH * box[4])
            right = int(frameW * box[5])
            bottom = int(frameH * box[6])

            left = max(0, min(left, frameW - 1))
            top = max(0, min(top, frameH - 1))
            right = max(0, min(right, frameW - 1))
            bottom = max(0, min(bottom, frameH - 1))

            # Extract the mask for the object
            classMask = mask[classId]

            # Draw bounding box, colorize and show the mask on the image
            drawBox(frame, classId, score, left, top, right, bottom, classMask)


# Load names of classes
classesFile = "mscoco_labels.names"
classes = None

"""
person
bicycle
car
motorcycle
airplane
bus
train
truck
boat
traffic light
fire hydrant

stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe

backpack
umbrella


handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle

wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
couch
potted plant
bed

dining table


toilet

tv
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator

book
clock
vase
scissors
teddy bear
hair drier
toothbrush
"""

with open(classesFile, 'rt') as f:
    classes = f.read().rstrip('\n').split('\n')

# Give the textGraph and weight files for the model
textGraph = "./mask_rcnn_inception_v2_coco_2018_01_28.pbtxt"
modelWeights = "./mask_rcnn_inception_v2_coco_2018_01_28/frozen_inference_graph.pb"

# Load the network
net = cv.dnn.readNetFromTensorflow(modelWeights, textGraph)

if args.device == "cpu":
    net.setPreferableBackend(cv.dnn.DNN_TARGET_CPU)
    print("Using CPU device")
elif args.device == "gpu":
    net.setPreferableBackend(cv.dnn.DNN_BACKEND_CUDA)
    net.setPreferableTarget(cv.dnn.DNN_TARGET_CUDA)
    print("Using GPU device")

# Load the classes
colorsFile = "colors.txt"
with open(colorsFile, 'rt') as f:
    colorsStr = f.read().rstrip('\n').split('\n')
    # ['0 255 0', '0 0 255', '255 0 0', '0 255 255', '255 255 0', '255 0 255', '80 70 180',
    # '250 80 190', '245 145 50', '70 150 250', '50 190 190']

colors = []  # [0,0,0]
for i in range(len(colorsStr)):
    rgb = colorsStr[i].split(' ')
    color = np.array([float(rgb[0]), float(rgb[1]), float(rgb[2])])
    colors.append(color)

"""
[array([  0., 255.,   0.]), array([  0.,   0., 255.]), array([255.,   0.,   0.]), array([  0., 255., 255.]), 
array([255., 255.,   0.]), array([255.,   0., 255.]), array([ 80.,  70., 180.]), array([250.,  80., 190.]), 
array([245., 145.,  50.]), array([ 70., 150., 250.]), array([ 50., 190., 190.])]
"""

winName = 'Mask-RCNN Object detection and Segmentation in OpenCV'
cv.namedWindow(winName, cv.WINDOW_NORMAL)

outputFile = "mask_rcnn_out_py.avi"
if (args.image):
    # Open the image file
    if not os.path.isfile(args.image):
        print("Input image file ", args.image, " doesn't exist")
        sys.exit(1)
    cap = cv.VideoCapture(args.image)
    outputFile = args.image[:-4] + '_mask_rcnn_out_py.jpg'
elif (args.video):
    # Open the video file
    if not os.path.isfile(args.video):
        print("Input video file ", args.video, " doesn't exist")
        sys.exit(1)
    cap = cv.VideoCapture(args.video)
    outputFile = args.video[:-4] + '_mask_rcnn_out_py.avi'
else:
    # Webcam input
    cap = cv.VideoCapture(0)

# Get the video writer initialized to save the output video
if (not args.image):
    vid_writer = cv.VideoWriter(outputFile, cv.VideoWriter_fourcc('M', 'J', 'P', 'G'), 28,
                                (round(cap.get(cv.CAP_PROP_FRAME_WIDTH)), round(cap.get(cv.CAP_PROP_FRAME_HEIGHT))))

while cv.waitKey(1) < 0:

    # Get frame from the video
    hasFrame, frame = cap.read()

    # Stop the program if reached end of video
    if not hasFrame:
        print("Done processing !!!")
        print("Output file is stored as ", outputFile)
        cv.waitKey(3000)
        break

    # Create a 4D blob from a frame.
    blob = cv.dnn.blobFromImage(frame, swapRB=True, crop=False)  # (1, 3, 531, 800)

    # Set the input to the network
    net.setInput(blob)

    # Run the forward pass to get output from the output layers
    boxes, masks = net.forward(['detection_out_final', 'detection_masks'])
    """
    (1, 1, 100, 7)  top 100 RoI, (0, classid, score, x0, y0, x1, y1)
    (100, 90, 15, 15) 100 RoI, 90 classes, 15*15 feature maps size
    """

    # Extract the bounding box and mask for each of the detected objects
    postprocess(boxes, masks)

    # Put efficiency information.
    t, _ = net.getPerfProfile()
    label = 'Mask-RCNN Inference time for a frame : %0.0f ms' % abs(t * 1000.0 / cv.getTickFrequency())
    cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))

    # Write the frame with the detection boxes
    if (args.image):
        cv.imwrite(outputFile, frame.astype(np.uint8));
    else:
        vid_writer.write(frame.astype(np.uint8))

    cv.imshow(winName, frame)

根据 bbox 的类别,取 mask 输出特征图对应类别的通道特征 classMask = mask[classId]

画 mask 的时候,先 resize 到 bbox 的大小,再借助了 cv2.findContoursdrawContours 绘制出轮廓

4、结果展示

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述

输入图片

在这里插入图片描述

输出结果

在这里插入图片描述


看看视频的结果

cars_mask_rcnn_out

5、涉及到的库

getPerfProfile

getPerfProfile 是 OpenCV 库中用于获取深度学习模型推理性能概况的一个函数。该函数主要用于分析模型中各层的执行时间,帮助开发者了解模型性能瓶颈和优化方向。

一、功能

getPerfProfile 函数返回一个包含模型各层执行时间的向量(或类似结构),单位通常为毫秒或秒,具体取决于函数实现和调用方式。

通过这个函数,开发者可以获取到模型推理过程中每一层所消耗的时间,进而分析哪些层是性能瓶颈,需要进一步优化。
使用场景

在使用 OpenCV 进行深度学习模型推理时,尤其是在对实时性要求较高的应用场景中,如视频处理、实时监控系统等,使用 getPerfProfile 函数可以帮助开发者评估和优化模型性能。

二、示例代码

import cv2  
  
# 加载预训练模型  
net = cv2.dnn.readNet("model.xml", "model.bin")  
  
# 假设有一个输入图像 blob  
blob = cv2.dnn.blobFromImage(...)  
  
# 设置输入并进行推理  
net.setInput(blob)  
outputs = net.forward()  
  
# 获取性能概况  
t, _ = net.getPerfProfile()  
 
# 假设 t 是以秒为单位的时间,转换为毫秒并打印  
print("Inference time: %.2f ms" % (t * 1000.0))  
  
# 如果需要更详细的每层时间,可以遍历 t  
# 注意:这里的 t 可能是一个向量,包含了多层的执行时间  
for layer_idx, layer_time in enumerate(t):  
    print(f"Layer {layer_idx}: {layer_time * 1000.0} ms")

三、注意事项

getPerfProfile 函数的返回值和单位可能因 OpenCV 的不同版本或不同的深度学习后端(如 DNN 模块支持的 TensorFlow、Caffe、PyTorch 等)而有所不同。

在使用该函数时,请确保您的 OpenCV 版本支持该功能,并仔细阅读相关文档以了解其具体用法和注意事项。

由于深度学习模型的复杂性和多样性,getPerfProfile 函数提供的性能数据仅供参考,实际的优化工作还需要结合模型的具体结构和应用场景进行。

6、参考

  • 论文解读
    【Mask RCNN】《Mask R-CNN》

  • tensorflow 代码解读
    Mask RCNN without Mask

  • OpenCV进阶(7)在 OpenCV中使用 Mask RCNN实现对象检测和实例分割

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2136811.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv5改进 | 模块缝合 | C3 融合Self-Calibrated Convolutions丰富特征图【CVPR2020】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv5入门 改…

pgrouting实战应用

1&#xff09;下载地区地区数据&#xff08;下载数据是XYZM 四位数据&#xff09; 2&#xff09;下载裁剪行政区数据 3&#xff09;使用arcgis pro添加路网数据和行政区数据 4&#xff09;裁剪数据&#xff0c;仅历下行政区路网 5&#xff09;arcgis pro要素转线&#xff0…

基础GAN生成式对抗网络(pytorch实验)

&#xff08;Generative Adversarial Network&#xff09; 一、理论 https://zhuanlan.zhihu.com/p/307527293?utm_campaignshareopn&utm_mediumsocial&utm_psn1815884330188283904&utm_sourcewechat_session 大佬的文章中的“GEN的本质”部分 二、实验 1、数…

SIP ACK method

SIP ACK同样在RFC3261中定义。 ACK仅仅用于对INVITE request的response的回复&#xff0c;例如在通话结束时&#xff0c;MO要断开连接&#xff0c;此时就会生成一条BYE 消息。BYE不会经过代理&#xff0c;而是直接路由到MT。MT通过200 (OK) 响应确认收到 BYE&#xff0c;然后就…

vagrant+virtualbox+ubuntu22.04无法上网问题

一、过程 vagrantfile配置私有网络 config.vm.network "private_network", ip: "192.168.56.10"启动虚拟机&#xff0c;可以ping通百度的实际IP&#xff0c;ping不通域名修改/etc/netplan/50-vagrant.yaml&#xff0c;配置DNS network:renderer: Networ…

计算机毕业设计Python知识图谱美团美食推荐系统 美团餐厅推荐系统 美团推荐系统 美食价格预测 美团爬虫 美食数据分析 美食可视化大屏

《Python知识图谱美团美食推荐系统》开题报告 一、研究背景与意义 随着信息技术的飞速发展和互联网应用的普及&#xff0c;人们的消费习惯逐渐从线下转移到线上&#xff0c;外卖行业迎来了前所未有的发展机遇。美团作为国内领先的生活服务电子商务平台&#xff0c;拥有庞大的…

基于SpringBoot+Vue的考务报名平台(带1w+文档)

基于SpringBootVue的考务报名平台(带1w文档) 基于SpringBootVue的考务报名平台(带1w文档) 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进…

026.(娱乐)魔改浏览器-任务栏图标右上角加提示徽章

一、目标&#xff1a; windows中&#xff0c;打开chromium&#xff0c;任务栏中会出现一个chromium的图标。我们的目标是给这个图标的右上角&#xff0c;加上"有1条新消息"的小提示图标&#xff0c;也叫徽章(badge)注意&#xff1a;本章节纯属娱乐&#xff0c;有需要…

【DS】AVL树

目录 AVL树的介绍AVL树节点的定义认识AVL树的抽象图AVL树的插入BSTree规则插入更新平衡因子平衡因子的判断 AVL树的旋转左单旋右单旋左右双旋右左双旋 AVL树的验证AVL树的查找AVL树的性能 在上篇搜索二叉树末尾提到过&#xff0c;得益于搜索二叉树的性质&#xff1a;大于根往右…

计算机毕业设计Python深度学习垃圾邮件分类检测系统 朴素贝叶斯算法 机器学习 人工智能 数据可视化 大数据毕业设计 Python爬虫 知识图谱 文本分类

基于朴素贝叶斯的邮件分类系统设计 摘要&#xff1a;为了解决垃圾邮件导致邮件通信质量被污染、占用邮箱存储空间、伪装正常邮件进行钓鱼或诈骗以及邮件分类问题。应用Python、Sklearn、Echarts技术和Flask、Lay-UI框架&#xff0c;使用MySQL作为系统数据库&#xff0c;设计并实…

java: 程序包org.junit.jupiter.api不存在

明明idea没有报错&#xff0c;引用包也没问题&#xff0c;为啥提示java: 程序包org.junit.jupiter.api不存在&#xff1f; 配置&#xff01;还TMD是配置&#xff01; 如果是引用包的版本不对或者其他&#xff0c;直接就是引用报错或者pom里面飘红了。 这个应该是把generat…

微服务-- Sentinel的使用

目录 Sentinel&#xff1a;微服务的哨兵 生态系统景观 sentinel与spring cloud Hystrix 对比 Sentinel 主要分为两部分 Sentinel安装与使用 Sentinel的控制规则 流控规则 流控规则的属性说明 新增流控规则 关联流控模式 SentinelResource注解的使用 SentinelResou…

如何将自己的项目发布到Maven中央仓库

1.背景 本教程为2024年9月最新版 我有一个java项目想发布到maven中央仓库&#xff0c;然后任何人都可以在pom文件中引用我写的代码 引用格式如下&#xff1a; <!-- 这是引用rocketmq的坐标 --> <dependency><groupId>org.apache.rocketmq</groupId>&l…

炫酷HTML蜘蛛侠登录页面

全篇使用HTML、CSS、JavaScript&#xff0c;建议有过基础的进行阅读。 一、预览图 二、HTML代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-w…

ESP8266做httpServer提示Header fields are too long for server to interpret

CONFIG_HTTP_BUF_SIZE512 CONFIG_HTTPD_MAX_REQ_HDR_LEN1024 CONFIG_HTTPD_MAX_URI_LEN512CONFIG_HTTPD_MAX_REQ_HDR_LEN由512改为1024

C++ | Leetcode C++题解之第404题左叶子之和

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isLeafNode(TreeNode* node) {return !node->left && !node->right;}int sumOfLeftLeaves(TreeNode* root) {if (!root) {return 0;}queue<TreeNode*> q;q.push(root);int ans 0;while …

氢能源多旋翼无人机技术详解

1. 技术背景与优势 随着全球对低碳、环保和高效能源解决方案的需求日益增长&#xff0c;氢能源作为一种清洁、高效的能源形式&#xff0c;在多个领域展现出巨大的应用潜力。在无人机领域&#xff0c;氢能源多旋翼无人机因其独特的优势逐渐受到关注。相比传统锂电池无人机&…

Linux sh命令

目录 一. 基本语法二. 选项2.1 -c 字符串中读取内容&#xff0c;并执行2.1.1 基本用法2.1.2 获取当前目录下失效的超链接 2.2 -x 每个命令执行之前&#xff0c;将其打印出来2.3 结合Here文档使用 一. 基本语法 ⏹Linux 和 Unix 系统中用于执行 shell 脚本 或 运行命令 的命令。…

【我的 PWN 学习手札】Fastbin Double Free

前言 Fastbin的Double Free实际上还是利用其特性产生UAF的效果&#xff0c;使得可以进行Fastbin Attack 一、Double Free double free&#xff0c;顾名思义&#xff0c;free两次。对于fastbin这种单链表的组织结构&#xff0c;会形成这样一个效果&#xff1a; 如果我们mallo…

卡西莫多的手信

通过网盘分享的文件&#xff1a;卡西莫多的手信2022-2024.9.15-A5.pdf 链接: 百度网盘 请输入提取码 提取码: gig1