这篇文章的内容是以 《使用MMDetection进行目标检测、实例和全景分割》 为基础,需要安装好 MMDetection 的运行环境,同时完成目标检测、实例分割和全景分割的功能实践,之后再看下面的内容。

想要实现AI抠图去背景的需求,我们需要利用 OpenMMLab 项目 MMDetection 模型库中的实例分割(Instance Segmentation)模型,来帮我们完成最核心的分类、分割图片物体任务。

接下来的主要操作是在 demo.py 编写和调试代码,首先编写下面的代码:

import cv2
import mmcv
from copy import deepcopy
from mmdet.apis import init_detector, inference_detectorconfig_file = 'configs/scnet/scnet_r50_fpn_1x_coco.py'  # 配置文件路径
checkpoint_file = 'checkpoints/scnet/scnet_r50_fpn_1x_coco-c3f09857.pth'  # 预训练模型加载路径
device = 'cpu'  # cpu|gpu
model = init_detector(config_file, checkpoint_file, device=device)  # 构建模型
img_raw = mmcv.imread('demo/demo.jpg')  # 待推理图像的原始 numpy.ndarray 对象img_h = img_raw.shape[0]  # 图像高度像素值
img_w = img_raw.shape[1]  # 图像宽度像素值result = inference_detector(model, img_raw)  # 推理的结果
img_result = model.show_result(img_raw, result)  # 结果图像的 numpy.ndarray 对象
model.show_result(img_raw, result, out_file='demo/demo_result.jpg')  # 将结果图像另存为文件

执行 demo.py 文件后,项目下面会生成 demo/demo_result.jpg 文件:

之前,我们是通过另存为文件的方式,来可视化推理的结果,现在,我们要进一步的解析推理结果。由模型文件名称 scnet_r50_fpn_1x_coco-c3f09857.pth 可知,这是个使用 coco 数据集训练出来的预训练模型,所以我们需要用 coco 数据集的定义方式去解析推理结果。

demo.py 文件里继续编写,提前定义一个存储和解析推理结果的 coco_80_dict 字典:

coco_80_dict = {'person': {'index': 0, 'id': 1, 'describe': '人'},'bicycle': {'index': 1, 'id': 2, 'describe': '自行车'},'car': {'index': 2, 'id': 3, 'describe': '车'},'motorcycle': {'index': 3, 'id': 4, 'describe': '摩托车'},'airplane': {'index': 4, 'id': 5, 'describe': '飞机'},'bus': {'index': 5, 'id': 6, 'describe': '公交车'},'train': {'index': 6, 'id': 7, 'describe': '火车'},'truck': {'index': 7, 'id': 8, 'describe': '卡车'},'boat': {'index': 8, 'id': 9, 'describe': '船'},'traffic light': {'index': 9, 'id': 10, 'describe': '红绿灯'},'fire hydrant': {'index': 10, 'id': 11, 'describe': '消防栓'},'stop sign': {'index': 11, 'id': 13, 'describe': '停车标志'},'parking meter': {'index': 12, 'id': 14, 'describe': '停车收费表'},'bench': {'index': 13, 'id': 15, 'describe': '板凳'},'bird': {'index': 14, 'id': 16, 'describe': '鸟'},'cat': {'index': 15, 'id': 17, 'describe': '猫'},'dog': {'index': 16, 'id': 18, 'describe': '狗'},'horse': {'index': 17, 'id': 19, 'describe': '马'},'sheep': {'index': 18, 'id': 20, 'describe': '羊'},'cow': {'index': 19, 'id': 21, 'describe': '牛'},'elephant': {'index': 20, 'id': 22, 'describe': '大象'},'bear': {'index': 21, 'id': 23, 'describe': '熊'},'zebra': {'index': 22, 'id': 24, 'describe': '斑马'},'giraffe': {'index': 23, 'id': 25, 'describe': '长颈鹿'},'backpack': {'index': 24, 'id': 27, 'describe': '背包'},'umbrella': {'index': 25, 'id': 28, 'describe': '雨伞'},'handbag': {'index': 26, 'id': 31, 'describe': '手提包'},'tie': {'index': 27, 'id': 32, 'describe': '领带'},'suitcase': {'index': 28, 'id': 33, 'describe': '手提箱'},'frisbee': {'index': 29, 'id': 34, 'describe': '飞盘'},'skis': {'index': 30, 'id': 35, 'describe': '雪橇'},'snowboard': {'index': 31, 'id': 36, 'describe': '滑雪板'},'sports ball': {'index': 32, 'id': 37, 'describe': '运动球'},'kite': {'index': 33, 'id': 38, 'describe': '风筝'},'baseball bat': {'index': 34, 'id': 39, 'describe': '棒球棒'},'baseball glove': {'index': 35, 'id': 40, 'describe': '棒球手套'},'skateboard': {'index': 36, 'id': 41, 'describe': '滑板'},'surfboard': {'index': 37, 'id': 42, 'describe': '冲浪板'},'tennis racket': {'index': 38, 'id': 43, 'describe': '网球拍'},'bottle': {'index': 39, 'id': 44, 'describe': '瓶'},'wine glass': {'index': 40, 'id': 46, 'describe': '酒杯'},'cup': {'index': 41, 'id': 47, 'describe': '杯'},'fork': {'index': 42, 'id': 48, 'describe': '叉子'},'knife': {'index': 43, 'id': 49, 'describe': '刀'},'spoon': {'index': 44, 'id': 50, 'describe': '汤匙'},'bowl': {'index': 45, 'id': 51, 'describe': '碗'},'banana': {'index': 46, 'id': 52, 'describe': '香蕉'},'apple': {'index': 47, 'id': 53, 'describe': '苹果'},'sandwich': {'index': 48, 'id': 54, 'describe': '三明治'},'orange': {'index': 49, 'id': 55, 'describe': '橙'},'broccoli': {'index': 50, 'id': 56, 'describe': '西兰花'},'carrot': {'index': 51, 'id': 57, 'describe': '胡萝卜'},'hot dog': {'index': 52, 'id': 58, 'describe': '热狗'},'pizza': {'index': 53, 'id': 59, 'describe': '披萨'},'donut': {'index': 54, 'id': 60, 'describe': '甜甜圈'},'cake': {'index': 55, 'id': 61, 'describe': '蛋糕'},'chair': {'index': 56, 'id': 62, 'describe': '椅子'},'couch': {'index': 57, 'id': 63, 'describe': '沙发'},'potted plant': {'index': 58, 'id': 64, 'describe': '盆栽植物'},'bed': {'index': 59, 'id': 65, 'describe': '床'},'dining table': {'index': 60, 'id': 67, 'describe': '餐桌'},'toilet': {'index': 61, 'id': 70, 'describe': '厕所'},'tv': {'index': 62, 'id': 72, 'describe': '电视'},'laptop': {'index': 63, 'id': 73, 'describe': '笔记本电脑'},'mouse': {'index': 64, 'id': 74, 'describe': '鼠标'},'remote': {'index': 65, 'id': 75, 'describe': '遥控器'},'keyboard': {'index': 66, 'id': 76, 'describe': '键盘'},'cell phone': {'index': 67, 'id': 77, 'describe': '手机'},'microwave': {'index': 68, 'id': 78, 'describe': '微波炉'},'oven': {'index': 69, 'id': 79, 'describe': '烤箱'},'toaster': {'index': 70, 'id': 80, 'describe': '烤面包机'},'sink': {'index': 71, 'id': 81, 'describe': '水槽'},'refrigerator': {'index': 72, 'id': 82, 'describe': '冰箱'},'book': {'index': 73, 'id': 84, 'describe': '书'},'clock': {'index': 74, 'id': 85, 'describe': '时钟'},'vase': {'index': 75, 'id': 86, 'describe': '花瓶'},'scissors': {'index': 76, 'id': 87, 'describe': '剪刀'},'teddy bear': {'index': 77, 'id': 88, 'describe': '泰迪熊'},'hair drier': {'index': 78, 'id': 89, 'describe': '吹风机'},'toothbrush': {'index': 79, 'id': 90, 'describe': '牙刷'},
}

推理结果 result 的长度为 len(result) == 2,其中:

  • 检测框 result[0] 的长度固定为 len(result[0]) == 80,因为 coco 数据集用于检测、分割的部分共有 80 个类别

    • 检测框的解析方式

      • 长度为 5 的列表,内容分别代表的是 [x1, y1, x2, y2, 置信度]
    • 检测框的数据示例
      [array([[2.54207230e+02, 1.04094536e+02, 2.62954681e+02, 1.12405502e+02, 7.87650794e-02],[3.75357147e+02, 1.20013657e+02, 3.81758453e+02, 1.33114960e+02, 6.91782460e-02],[5.32841248e+02, 1.09704865e+02, 5.40237061e+02, 1.24966133e+02, 1.59687027e-02],[6.22804871e+02, 1.05815277e+02, 6.35152161e+02, 1.15566162e+02, 5.09093935e-03]], dtype=float32),array([], shape=(0, 5), dtype=float32),array([[4.81168701e+02, 1.10373505e+02, 5.23180786e+02, 1.30380783e+02, 9.89862204e-01],[4.32057190e+02, 1.04940285e+02, 4.83949829e+02, 1.32065140e+02, 9.75807786e-01],[8.68552148e-01, 1.12007828e+02, 6.18107605e+01, 1.44267593e+02, 9.75750148e-01],[6.08653687e+02, 1.11829590e+02, 6.35857971e+02, 1.37511154e+02, 9.74755704e-01],[2.66471069e+02, 1.05501320e+02, 3.26720917e+02, 1.27970596e+02, 9.69615817e-01],[1.91124908e+02, 1.08998817e+02, 2.99086731e+02, 1.55649002e+02, 9.68829334e-01],[3.98783081e+02, 1.11128929e+02, 4.33258514e+02, 1.33113083e+02, 9.66077983e-01],......[2.54207230e+02, 1.04094536e+02, 2.62954681e+02, 1.12405502e+02, 5.26814163e-03]], dtype=float32),......array([[3.7397647e+02, 1.3353706e+02, 4.3298822e+02, 1.8852022e+02, 2.0611383e-01],[2.1776900e+02, 1.7274181e+02, 4.5755392e+02, 3.8911337e+02, 6.3707083e-03]], dtype=float32),array([], shape=(0, 5), dtype=float32)
      ]
      
  • 分割对象 result[1] 的长度固定为 len(result[1]) == 80,同样代表 coco 数据集里的 80 个类别
    • 分割对象的解析方式,是一个 2 维数组

      • 1 个维度代表图像的高度
      • 2 个维度代表图像的框度
      • 具体的 bool 值用于判断下标 [h][w] 的像素点是否为识别目标的分割像素点,以抠图需求为例
        • True 表示下标 [h][w] 的像素点应该被保留
        • False 表示下标 [h][w] 的像素点应该被去掉
    • 分割对象的数据示例
      [[array([[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],...,[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False]]),array([[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],...,[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False]]),array([[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],...,[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False],[False, False, False, ..., False, False, False]])],...,[],[]
      ]
      

因为推理结果 result 的组织结构是 result [0=检测框,1=分割对象] [coco 80 个类别的顺序下标],这种组织结构不方便我们提取抠图的数据,所以需要将推理结果 result 拆解后存储到前面定义好 coco_80_dict 字典中。

demo.py 文件里继续编写,拆解推理结果 result 数据,以方便我们提取抠图的结构存储到 coco_80_dict 字典:

for cc_key, cc_value in coco_80_dict.items():coco_80_dict[cc_key]['number'] = len(result[0][cc_value['index']])coco_80_dict[cc_key]['detection'] = result[0][cc_value['index']]coco_80_dict[cc_key]['segmentation'] = result[1][cc_value['index']]

此时 coco_80_dict 字典的数据结构如下所示:

{'person': {'index': 0,'id': 1,'describe': '人','number': 4,'detection': 检测框 list[[x1, y1, x2, y2, 置信度]],'segmentation': 分割对象 list[[h][w]=是否为识别目标的分割像素点]},......'toothbrush': {'index': 79,'id': 90,'describe': '牙刷','number': 0,'detection': array([], shape=(0, 5), dtype=float32),'segmentation': []}
}

接下来以位于图像中心位置的板凳为例,把板凳的检测框和分割对象可视化成图像文件,我们开始解析,首先可视化板凳的检测框。

demo.py 文件里继续编写,读取第 1 个板凳的检测框( coco_80_dict['bench']['detection'][0] ),并将其可视化:

img_detection = deepcopy(img_raw)  # 深拷贝原始 numpy.ndarray 对象
img_detection_data = coco_80_dict['bench']['detection'][0]  # 第1个板凳的检测框
img_detection_data_x1 = int(img_detection_data[0])
img_detection_data_y1 = int(img_detection_data[1])
img_detection_data_x2 = int(img_detection_data[2])
img_detection_data_y2 = int(img_detection_data[3])
print(f'目标置信度 = {img_detection_data[4]*100}%')  # 绘制比较麻烦,就直接打印for x_i in range(img_detection_data_x1, img_detection_data_x2):img_detection[img_detection_data_y1, x_i] = [0,0,255]  # 重置为 [0,0,255] 即红色像素点img_detection[img_detection_data_y2, x_i] = [0,0,255]for y_i in range(img_detection_data_y1, img_detection_data_y2):img_detection[y_i, img_detection_data_x1] = [0,0,255]img_detection[y_i, img_detection_data_x2] = [0,0,255]cv2.imwrite(f'demo/demo_result_detection.jpg', img_detection)

执行 demo.py 文件后,控制台会打印 目标置信度 = 99.38850998878479%,然后项目下面会生成 demo/demo_result_detection.jpg 文件:

demo.py 文件里继续编写,读取第 1 个板凳的分割对象( coco_80_dict['bench']['segmentation'][0] ),并将其可视化:

img_segmentation = deepcopy(img_raw)  # 深拷贝原始 numpy.ndarray 对象
img_segmentation_data = coco_80_dict['bench']['segmentation'][0]  # 第1个板凳的分割对象
for h_i in range(img_h):for w_i in range(img_w):# 通过分割对象的 bool 值来判断像素点是否需要去除(重置为 [255,255,255] 即纯白背景)if not img_segmentation_data[h_i, w_i]:img_segmentation[h_i, w_i] = [255,255,255]cv2.imwrite(f'demo/demo_result_segmentation.jpg', img_segmentation)

执行 demo.py 文件后,项目下面会生成 demo/demo_result_segmentation.jpg 文件:

最后,就是抠图最后一步,把现在的 3 通道图像数据改成 4 通道(添加透明度的通道),输出透明背景的图像文件。

demo.py 文件里继续编写,读取第 1 个板凳的分割对象( coco_80_dict['bench']['segmentation'][0] ),先添加透明度通道再并将其可视化:

img_segmentation_png_raw = deepcopy(img_raw)  # 深拷贝原始numpy.ndarray对象
img_segmentation_png = np.full((img_h, img_w, 4), 0, dtype='uint8')  # 创建(图像高,图像宽,4通道)大小的numpy.ndarray对象
img_segmentation_png_data = coco_80_dict['bench']['segmentation'][0]
for h_i in range(img_h):for w_i in range(img_w):if img_segmentation_png_data[h_i, w_i]:img_segmentation_png[h_i, w_i] = np.append(img_segmentation_png_raw[h_i, w_i], 255)cv2.imwrite(f'demo/demo_result_segmentation_png.png', img_segmentation_png)

执行 demo.py 文件后,项目下面会生成 demo/demo_result_segmentation_png.png 文件:

至此,就完成了Python调用MMDetection实现AI抠图去背景的功能!

Python调用MMDetection实现AI抠图去背景相关推荐

  1. python实现简单的api接口-简单实现Python调用有道API接口(最新的)

    # ''' # Created on 2018-5-26 # # @author: yaoshuangqi # ''' import urllib.request import urllib.pars ...

  2. 图像抠图去背景技术从传统算法到深度学习到商用:如何快速使用JAVA/PHP/Python/ShellCommand 实现人像抠图去背景-调用PicUP.AI抠人像接口API实现人像抠图

    图像抠图去背景技术从传统算法到深度学习 图像去背景(抠图)是图像编辑中的关键技术 三分图(trimap)的概念 PicUP.AI [链接](https://www.picup.ai). 实测例子 AP ...

  3. Python图片批量自动抠图去背景

    图片批量自动抠图去背景 今天发现个好东西啊,叫片刻抠图(pickwant.com),是一个在线对图片自动抠图去除背景的网站.只要上传图片,就可以自动把背景去掉把目标对象抠出来. 不管是动物.汽车或各种 ...

  4. (二)Python环境配置:AI实时抠图、AI实时抠像、PaddlePaddle模型、虚拟现实视频会议、沉浸式会议场景

    (二)Python环境配置:AI实时抠图.AI实时抠像.PaddlePaddle模型.虚拟现实视频会议.沉浸式会议场景.人像去背景.图像去背景.视频背景消除 摘要:此文承接上一篇博文,是在软件编程之前 ...

  5. 【AI选股】如何通过python调用通达信-小达实现AI选股(量化又多了一个选股工具)

    文章目录 前言 一.通达信-小达是什么? 二.使用步骤 1. 引入browser_cookie3库 2. 通达信-小达 AI选股源代码 总结 前言 ChatGPT火遍网络,那么有没有可以不用写公式就可 ...

  6. python调用百度AI识别文字和表格

    python调用百度AI识别文字和表格 获取账户信息 1.需要先注册百度AI,获得ID和密钥.百度AI社区关于注册的详细说明:https://ai.baidu.com/forum/topic/show ...

  7. Python——调用百度AI实现图片上文字识别

    Python--调用百度AI实现图片上文字识别 简介 步骤 安装百度AI库 注册百度AI开放平台 调用glob库 调用AipOcr库识别文字 可能会遇到的问题 批量操作 简介 Python免费调用百度 ...

  8. 【应用】Python调用百度AI实现图片上表格识别

    [应用]Python调用百度AI实现图片上表格识别 简介 步骤 安装百度AI库 注册百度AI开放平台 调用AipOcr库识别表格文字 可能遇到的问题 批量操作 简介 Python免费调用百度AI实现图 ...

  9. 【AI选股】如何通过python调用wencai包实现AI选股(小白也能学会)

    如何通过python调用wencai包实现AI选股 前言 一.wencai问财如何实现AI选股? 1.实用基础篇(wencai选股函数与使用方法) 2.进阶发挥篇(附可转债数据处理演示) 3.数据分析 ...

最新文章

  1. Ubuntu 16.04 命令行 关机 or 重启
  2. Android 调试工具集合
  3. 最近面试,笔试题中的一道sql题
  4. php mysqli不识别,不识别数据库PHP MYSQLi中的密码
  5. android listview中item通过viewpager实现
  6. 2012年我读过的十本好书
  7. javaee编程题_在JavaEE中使用CDI的简单面向方面的编程(AOP)
  8. gitlab CI/CD 知识点查阅
  9. Oracle中rownum用法总结
  10. How to enable/disable EWF
  11. VLAN、OSPF、GRE或IPSEC配置作业与抓包内容(新手入门)
  12. html怎样使字数占相同位,《古对今》教案
  13. 正点原子ATK-LORA-01无线串口代码移植+STM32F103C8T6(标准库)
  14. 软件测试多长时间可以学习,软件测试学习多长时间啊?好学吗?
  15. <Linux>计算机体系结构和操作系统
  16. 酒水知识(六大基酒之朗姆酒_Rum)
  17. 教授专栏08| 徐岩:青年震荡与青年危机
  18. PKI(公、私钥加密,数字签名、数字证书)技术理解
  19. Node.js躬行记(18)——半吊子的可视化搭建系统
  20. JAVA程序员面试总结

热门文章

  1. delphi 数字转换成中文
  2. 计算机类2019ei中国会议,EI会议期刊系列 2019 - EI会议期刊系列-工学
  3. Goproxy(Go模块代理)的使用与配置
  4. 视频笔记_所长林超跨学科工具箱
  5. 年薪20万,30万,50万,哪个最难突破?
  6. 罗永浩发布锤子手机系统 6月15日开放下载
  7. STM32F4 SPI DMA
  8. Linux下的几种负载均衡技术小结
  9. ABB机器人备份的那些事儿
  10. php逐行的读取文件内容