AI备忘录 - 抠图
type: channel
link: http://www.aiuai.cn/tag/抠图
items: Github 项目 - BackgroundMattingV2 之模型定义
items: Github 项目 - BackgroundMattingV2 之预测函数
items: 论文阅读 - Real-Time High-Resolution Background Matting
items: Deep Image Matting 之 Pytorch 实现[转]
items: 贝塞尔曲线数学原理及Python实现
items: Matting - 更换主体背景的实现
items: Matting - Background Matting 简单理解
items: 基于语义分割和Alpha blending的图像背景定制[译]
items: 阿里达摩院视觉算法-透明抠图[转]
items: Github 项目 - U2Net 网络及实现

Github 项目 - BackgroundMattingV2 之模型定义
type: item
date: 2020-12-27T14:01:00+00:00
description: 正如论文里所给出的 BackgroundMattingV2 网络结构图如下：网路结构包含两个网络组成：[1] - base 网络在将采样后的分辨率上输出粗略抠图结果;[2] - refine 网络仅对容易出错(error-prone)的图像部分进行处理，输出全分辨率的结果. 其能够节省冗余计算量，有助于调整耗时.1. 总体模型定义model.pyimport torch from torch import nn from torch.nn import functional as F from torchvision.models.segmentation.deeplabv3 import ASPP from .decoder import Decoder from .mobilenet import MobileNetV2Encoder from .refiner import Refiner from .resnet import ResNetEncoder from .utils import load_matched_state_dict class Base(nn.Module): """ A generic implementation of the base encoder-decoder network inspired by DeepLab. Accepts arbitrary channels for input and output. """ def __init__(self, backbone: str, in_channels: int, out_channels: int): super().__init__() #支持的 Encoder-Decoder Base 网络 assert backbone in ["resnet50", "resnet101", "mobilenetv2"] if backbone in ['resnet50', 'resnet101']: self.backbone = ResNetEncoder(in_channels, variant=backbone) self.aspp = ASPP(2048, [3, 6, 9]) self.decoder = Decoder([256, 128, 64, 48, out_channels], [512, 256, 64, in_channels]) else: self.backbone = MobileNetV2Encoder(in_channels) self.aspp = ASPP(320, [3, 6, 9]) self.decoder = Decoder([256, 128, 64, 48, out_channels], [32, 24, 16, in_channels]) def forward(self, x): x, *shortcuts = self.backbone(x) x = self.aspp(x) x = self.decoder(x, *shortcuts) return x def load_pretrained_deeplabv3_state_dict(self, state_dict, print_stats=True): # Pretrained DeepLabV3 models are provided by <https://github.com/VainF/DeepLabV3Plus-Pytorch>. # This method converts and loads their pretrained state_dict to match with our model structure. # This method is not needed if you are not planning to train from deeplab weights. # Use load_state_dict() for normal weight loading. # Convert state_dict naming for aspp module state_dict = {k.replace('classifier.classifier.0', 'aspp'): v for k, v in state_dict.items()} if isinstance(self.backbone, ResNetEncoder): # ResNet backbone does not need change. load_matched_state_dict(self, state_dict, p…

Github 项目 - BackgroundMattingV2 之预测函数
type: item
date: 2020-12-27T13:21:00+00:00
description: BackgroundMattingV2 提供了对图像、视频、网络摄像头的抠图实现，以及支持导出 ONNX 和 Torchscript.1. HomographicAlignment 图像对齐图像对齐函数，用于将背景与源图的匹配.inference_utils.pyimport numpy as np import cv2 from PIL import Image class HomographicAlignment: """ Apply homographic alignment on background to match with the source image. """ def __init__(self): self.detector = cv2.ORB_create() # ''' ORB 采用FAST(features from accelerated segment test)算法来检测特征点. FAST核心思想是, 找出那些卓尔不群的点，即拿一个点跟它周围的点比较， 如果它和其中大部分的点都不一样就可以认为它是一个特征点. ''' self.matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE) ''' 描述符匹配，特征匹配 ''' def __call__(self, src, bgr): src = np.asarray(src) bgr = np.asarray(bgr) keypoints_src, descriptors_src = self.detector.detectAndCompute(src, None) keypoints_bgr, descriptors_bgr = self.detector.detectAndCompute(bgr, None) matches = self.matcher.match(descriptors_bgr, descriptors_src, None) matches.sort(key=lambda x: x.distance, reverse=False) num_good_matches = int(len(matches) * 0.15) matches = matches[:num_good_matches] points_src = np.zeros((len(matches), 2), dtype=np.float32) points_bgr = np.zeros((len(matches), 2), dtype=np.float32) for i, match in enumerate(matches): points_src[i, :] = keypoints_src[match.trainIdx].pt points_bgr[i, :] = keypoints_bgr[match.queryIdx].pt # H, _ = cv2.findHomography(points_bgr, points_src, cv2.RANSAC) h, w = src.shape[:2] bgr = cv2.warpPerspective(bgr, H, (w, h)) #透视变换 msk = cv2.warpPerspective(np.ones((h, w)), H, (w, h)) # For areas that is outside of the background, # We just copy pixels from the source. bgr[msk != 1] = src[msk != 1] src = Image.fromarray(src) bgr = Image.fromarray(bgr) return src, bgr关于图像对齐可参考：[1] - Image Alignment (Feature Based) using OpenCV (C++/Python)[2] - 使用OpenCV实现基于特征的图像对齐2. 图像抠图inference_images.py对图像进行抠图(多线程).import argparse import torch import os import shutil from torch.nn import functional as F from torch.utils.data import DataLoader from torchvision import transforms as T from torchvision.transforms.functional import to_pil_i…

论文阅读 - Real-Time High-Resolution Background Matting
type: item
date: 2020-12-26T13:39:00+00:00
description: 论文：Real-Time High-Resolution Background Matting作者：Shanchuan Lin Andrey Ryabtsev Soumyadip Sengupta团队：cs.washington.eduHomepage - Real-Time High Resolution Background MattingGithub - PeterL1n/BackgroundMattingV2针对视频背景抠图，该论文的几个着重点：[1] - 实时且高分辨率, 在 GPU 上，4K 分辨率(3840x2160) 30fps; HD 分辨率(1920x1080) 60 fps.[2] - 基于背景抠图(background matting)，其需要单独捕捉一帧背景图，以用于重建 alpha matte 和前景层.[3] - 最关键的挑战是，高分辨率 alpha matte 的计算，在实时处理高分辨率图像的同时，保持发丝级细节.[4] - 采用两个神经网络，base 网络计算低分辨率结果; refine 网络对高分辨率图像所选择的图片块( selective patches) 上进一步处理.[5] - 两个视频和图像抠图数据集：VideoMatte240K 和 PhotoMatte 13K/85.1. 抠图数据集获取大量、高分辨率、高质量的、由人工标注的抠图数据集是非常难的.1.1. 公开数据集Adobe Deep Image Matting 数据集提供了 269 张人物训练样本和 11 张测试图像，分辨率平均为 1000x1000.Attention-Guided Hierarchical Structure Aggregation for Image Matting 中362 张人物相关的训练样本和 11 张测试样本，分辨率平均为 1700x2000.以上两个数据集共 631 张训练样本，是远远不够的.1.2. VideoMatte240KVideoMatte240K 中采集了 484 段高分辨率绿幕(green screen) 视频，并采用色度键抠图(Chroma-key)软件 Adobe After Effects 生成了 240709 张 alpha mattes 和 foregrounds 的视频帧.其中，384 段视频的分辨率为 4K, 100 段视频的分辨率为 HD. 根据 479:5 的比例将视频划分为 tran 和 validataion 数据集. 如图：1.3. PhotoMatte13K/85PhotoMatte13K/85 中采集了 13665 张图像集合，这些图像是采用摄影棚质量的光照，在绿幕前的相机所拍摄的，并采用色度键抠图算法(Chroma-key) 和手工调整以及错误修正所提取的 mattes.根据 13165:500 的比例划分为 train 和 validation 数据集. 数据集图像分辨率平均为 2000x2500，包括了一些头发.2. 算法细节给定图像 I 以及捕捉的背景 B, 算法会预测输出 alpha matte $\alpha$ 和前景 F, 基于如下公式，其可以被任何背景来组合，$$ I' = \alpha F + (1 - \alpha) B' $$其中，$B'$ 为新背景.相比于直接求解前景，这里求解的是前景残差 $F^{R} = F - I$. 因此，F 可以通过添加适当的约束将 $F^R$ 和输入图像 I 相加:$$ F = max(min( F^{R} + I, 1), 0) $$高分辨率抠图是很有挑战的，因为直接进行深度网络计算，其计算量和内存消耗是不切实际的. 如图所示：人物 mattes 往往是非常稀疏的，大面积的像素要么是背景($\alpha=0$)，要么是前景($\alpha = 1$)，仅有少量的区域包含更多的细节，如头发、眼镜、人物轮廓等周围.对此，相比于设计直接在高分辨率图像直接操作的一个网络，这里采用了两个网络：[1] - base 网络 $G_{base}$ - 对低分辨率图像进行处理;[2] - refinement 网络 $G_{refine}$ - 基于低分辨率预测结果，从原始图像分辨率选择特定图像块进行处理.网络结构如图：给定原始输入图像 I 和捕捉的背景图 B，首先采用缩放因子 $c$ 进行将采样到 $I_c$ 和 $B_c$. $G_{base}$ 采用 $I_c$ 和 $B_c$ 作为输入，并预测输出粗略的 alpha matte $\alpha_c$、foreground residual $F_c^R$、error prediction map $E_c$ 以及 hidden feature $H_c$. $G…

Deep Image Matting 之 Pytorch 实现[转]
type: item
date: 2020-11-26T12:06:00+00:00
description: 原文：Pytorch 抠图算法 Deep Image Matting 模型实现 - 2019.07.21GitHub: deep_image_matting_pytorch作者：公输睚信 - 简书本文旨在实现抠图算法 Semantic Human Matting 的第二阶段模型 M-Net，也即 Deep Image Matting. 值得说明的是，本文实现的模型与原始论文略有出入，除了模型的输入层有细微差别之外，损失函数也作了简化(但无本质差别). 本文训练数据来源于爱分割公司开源的 aisegmentcn/matting_human_datasets，总共包含 34426 张图片和对应的 alpha 通道，数据量非常大，能公开特别值得点赞. 但同时因为标注数据的 alpha 通道精度不高，导致训练后测试效果较差. 建议使用 Deep Image Matting 的数据集训练. 图：Semantic Human Matting 抠图模型总的来说，Semantic Human Matting 论文提出的自动抠图的思路特别清晰明了(如上图)，对于一张待抠图像，首先通过语义分割模型(即 T-Net)分割出前景 Fs、背景 Bs 和未知区域 Us，Fs+Bs+Us=1. 广义的认为前景Fs和未知区域Us组成一个三分图Trimap. 此时，再利用 Deep Image Matting(即 M-Net) 即可高质量的完成抠图. 本文只关注该模型的第二阶段(M-Net). M-Net 接受待抠图像(前景与背景的 RGB 3通道合成)以及语义分割模型输出的3通道预测(Fs，Bs，Us) 拼接而成的 6 通道输入，经过编码器提取图像特征之后，由解码器得到预测Alpha($\alpha _r$). 如果语义分割模型分割的精度较高，那么可以认为 Fs 和 Bs 对应的区域已经很好的抠出了大部分的前景和背景，唯一需要提升准确率的是待抠对象的边缘区域，所以模型的第二阶段 M-Net 的目的就是细化的预测边缘区域(这正是 Deep Image Matting 要干的事情)，两部分结合即得到最终的预测：$$ F_s + U_s \alpha _r $$公式可以这样理解：$$ 预测的前景 = 确定区域上的前景 + 未知区域上的前景 $$即：$$ P(前景) = P(确定区域上前景) + P(未知区域上前景) $$根据全概率公式，符号化表达为：$$ \alpha = P(F) = P(F|known) P(known) + P(F|unknown) P(unknown) $$$$ \alpha = \frac{F_s}{F_s + B_s}(F_s + B_s) + \alpha _r U_s = F_s + U_s \alpha _r $$但上述公式存在一个缺陷，即如果待抠目标外有大块噪声，则最终的预测也消除不了这个噪声，如下图：图：语义分割之后的前景带有外部噪声(衣服左侧的小照片)为了消除第一阶段可能包含的外部噪声，本文的在实现 M-Net 的时候做了一个小的改动：第二阶段的输入改为由待抠图像 + Fs 组成的 4通道图片(此时，相当于将 Fs 看成是三分图 trimap)，并且将第二阶段的预测作为最终的预测. 另外，第二阶段损失函数简化为只用 alpha 通道的损失更好.1. DIM 模型实现Deep Image Matting 原文的模型如下：图：Deep Image Matting 论文模型模型先通过一个编码器提取特征，之后经过一个解码器预测一个初始的 alpha 通道，这个预测值效果已经很好，但作者为了进一步提升抠图的精度，又额外的接了几层细化的小网络，然后将细化后的输出作为整个模型的最终输出. 具体来说，首先将待抠图像(3 通道)以及事先准备好的三分图(trimap)合成一个 4 通道图像，然后经过 VGG16 的前 13 个卷积层以及之后的 1 个全连接层(看成是 1x1 的卷积层)，总共 14 个卷积层提取图像特征(此时已做了 5 个最大池化，因此图像分辨率下降了 32 倍，如果输入是 320x320，那么特征映射的分辨率就变成了 10x10)，这是模型的编码器阶段. 接下来对图像特征进行解码，即开始解码器阶段. 解码器使用 6 个卷积层(5x5 的卷积核)和 5 个 反池化层，每个反池化层将特征映射的分辨率提升 2 倍，因此解码器的输出与模型输入的大小一样. 这里，使用反池化层的效果要比直接使用转置卷积(deconvolution)的效果要好. 虽然他们都是为了提升图像分辨率，但使用转置卷积并不能很好的抠出细节，而使用反池化层却可以抠图头发丝等非常细的前景. 为了最求极致效果，作者又接了一个小网络，将待抠图像和编码器预测的 alpha 通…

贝塞尔曲线数学原理及Python实现
type: item
date: 2020-11-24T12:15:00+00:00
description: 贝赛尔工具在 photoshop 中叫“钢笔工具”；在 CorelDraw 中翻译成“贝赛尔工具”；而在 Fireworks 中叫“画笔”. 它是用来“画线”造型的一种专业工具. 当然还有很多工具也可以完成画线的工作，例如常用的photoshop里的直线、喷枪、画笔工具，Fireworks里的直线、铅笔和笔刷工具，CorelDraw里的自由笔，手绘工具等等.很多设计师应该都知道贝塞尔曲线，习惯用 PS 的会用钢笔工具，习惯用AI 的会用贝塞尔，因为它所绘制出来的曲线很容易受控制，也很美观. 下面深入了解下贝塞尔曲线的数学原理和公式.在数学中，贝塞尔曲线又分为很多种，如，一阶贝塞尔曲线、二阶贝塞尔曲线、三阶贝塞尔曲线，等等. 除了一阶贝塞尔曲线是直线外，剩下的多阶贝塞尔曲线都是抛物线. 贝塞尔曲线由起点、终点和控制点组成，根据控制点的个数和位置决定了这个曲线的最终样式.1. 原理贝塞尔曲线的数学原理 - 2017.01.26先在一个平面内任选 3 个不共线的点，依次用线段连接，如图：在第一条线段上任选一个点 D，计算该点到线段起点的距离 AD，与该线段总长 AB 的比例.根据上一步得到的比例，从第二条线段上找出对应的点 E，使得 AD:AB = BE:BC.连接这两点 DE.从新的线段 DE 上再次找出相同比例的点 F，使得 DF:DE = AD:AB=BE:BC.到这里，就确定了贝塞尔曲线上的一个点 F. 接下来，稍微回想一下中学所学的极限知识，让选取的点 D 在第一条线段上从起点 A 移动到终点 B，找出所有的贝塞尔曲线上的点 F. 所有的点找出来以后，也就得到了这条贝塞尔曲线.如果想象不出来，可以看下面的动画.到这里，已经大概了解贝塞尔曲线绘制的过程了.下面看公式.2. 公式以下公式中：$B(t)$ 为 $t$ 时间下点的坐标； $P_0$ 为起点；$P_n$ 为终点，$P_i$ 为控制点.2.1. 一阶贝塞尔曲线一阶贝塞尔曲线只有起点和终点，并没有控制点，所以绘制出来的图形仅仅只是一条直线，那么在时间 t 为 1 秒的情况下，其公式为：$$ B(t) = (1 - t) P_0 + tP_1, t \in [0, 1] $$意义：由 $P_0$ 至 $P_1$ 的连续点， 描述的一条线段.2.2. 二阶贝塞尔曲线二阶贝塞尔曲线只存在一个控制点，此时从起点到终点的线段发生变化，具体的变化是由控制点的位置而改变的. 图中，绿色的线段为红色曲线的切线.$$ B(t) = (1 - t)^2 P_0 + 2t(1 - t)P_1 + t^2 P_2, t \in [0, 1] $$仅仅只是简单的一元二次方程式.原理：由 $P_0$ 至 $P_1$ 的连续点 $Q_0$，描述一条线段；由 $P_1$ 至 $P_2$ 的连续点 $Q_1$，描述一条线段；由 $Q_0$ 至 $Q_1$ 的连续点 $B(t)$，描述一条二次贝塞尔曲线.Python 示例如：#!/usr/bin/python3 #!--*-- coding: utf-8 --*-- import numpy as np import matplotlib.pyplot as plt P0, P1, P2 = np.array([[0, 0], [2, 4], [5, 3]]) # 定义贝塞尔曲线 P = lambda t: (1 - t)**2 * P0 + 2 * t * (1 - t) * P1 + t**2 * P2 # 在 [0, 1] 范围内的 50 个点上验证贝塞尔曲线 points = np.array([P(t) for t in np.linspace(0, 1, 50)]) # 分别获取点的 x 坐标和 y 坐标 x, y = points[:, 0], points[:, 1] # plt.plot(x, y, 'b-') plt.plot(*P0, 'r.') plt.plot(*P1, 'r.') plt.plot(*P2, 'r.') plt.show()如：可以看到，曲线从第一个控制点处开始，到最后一个控制点处结束. 这个结果对任意数量的点都成立.从P0到P2，P1 完全决定了曲线的形状。移动 P1：贝塞尔曲线总是包含在控制点形成的多边形中. 这个多边形因此被称为控制多边形，或者贝塞尔多边形. 这个属性也适用于任意数量的控制点，这使得它们在使用软件时的操作非常直观.控制多边形还具有以下特性：包含曲线的面积最小，称为凸包.2.3. 高阶贝塞尔曲线[1] - 三阶[2] - 四阶[3] - 五阶从三阶开始贝塞尔曲线就开始显得复杂了，高阶的通用公式如下：$$ P_i^k = (1 - t) P_i^{k-1} + t P_{i+1}^{k-1} …

Matting - 更换主体背景的实现
type: item
date: 2020-11-15T09:58:00+00:00
description: 1. 颜色背景实现如下：#!/usr/bin/python3 #!--*-- coding: utf-8 --*-- import numpy as np from PIL import Image import matplotlib.pyplot as plt img_file = 'test.jpg' png_file = './test.png' img_pil = Image.open(img_file) png_pil = Image.open(png_file) alpha = png_pil.split()[-1] ## pillow #im = Image.new('RGBA', png_pil.size, (255, 0, 255)) #im.paste(im, mask=im) # opencv bg = Image.new("RGB", png_pil.size, (255, 0, 255)) fg = np.array(img_pil, np.float32) alpha= np.expand_dims(np.array(alpha) / 255,axis=2) im = alpha * fg + (1 - alpha) * bg im = im.astype(np.uint8) # plt.figure(figsize=(12, 10)) plt.subplot(131) plt.imshow(img_pil) plt.subplot(132) plt.imshow(alpha) plt.subplot(133) plt.imshow(im) plt.show()如，左原图，中alpha图，右新背景图.2. 图片背景#!/usr/bin/python3 #!--*-- coding: utf-8 --*-- from PIL import Image img_file = 'test.jpg' png_file = './test.png' # bg = Image.open(bg_file) png_pil = Image.open(png_file) if png_pil.size != bg.size: png_pil = png_pil.resize(bg.size) r, g, b, alpha = png_pil.split() fg = Image.merge('RGB', (r, g, b)) out = Image.composite(fg, bg, png_pil)

Matting - Background Matting 简单理解
type: item
date: 2020-09-20T02:24:29+00:00
description: 论文： Background Matting: The World is Your Green Screen - CVPR2020Projects：Background Matting: The World is Your Green ScreenGithub: senguptaumd/Background-MattingBlog: Background Matting: The World is Your Green Screen - MediumBackground Matting 示例：图：手持智能手机相机，拍摄同一场景的两张照片 - 一张有目标(如，人物)和一张无目标；采用对抗损失(adversarial loss) 的神经网络来重建 alpha matte 和前景(foreground)；最后合并结果到新的背景(backgroud).1. Matting 问题Matting 是将图像分解为前景和背景的处理，以便于将前景合并到新的背景上. 这也是绿幕(green screen) 的关键技术，被广泛应用于视频生产、图形和APPs 中.Matting 问题的建模，将图像的每个像素表示为前景和背景的组合：$$ C = F * \alpha + B * (1 - \alpha) $$Matting 问题的求解是，给定图像 C，计算每个像素的前景F、背景B 和透明度alpha.由于图像有 RGB 三个通道，该公式需要基于 3 个已知量来求解 7 个未知量，问题是难以求解的.1.1. Matting 与 Segmentation一种可行方式是，采用分割(segmentation) 将前景从图像中分离出来. 但是，尽管分割技术近年取得了很大进步，其并没有解决 matting 公式里的问题.分割是对图像中每个像素分配一个二值标签(0, 1)，以表示背景和前景，而不是求解连续的 alpha 值. Segmention 和 Matting 的区别可以如下图简单例示：图：Segmentation 采用 DeepLabv3+ 得到. 图中，边缘区域，尤其是头发，是由 0-1 之间的真实 alpha 值的. 因此，分割的二值性导致前景边界周围出现严格边界，留下可见的不好效果. 解决了部分透明度和前景问题，对第二帧的合成更有利.1.2. Matting 与背景提取Is This Method Like Background Subtraction?Matting 问题和另一个接近的问题是，是否和背景提取类似呢？首先，如果使用任意背景组合这么简单，电影产业就不会每年花费大量美元投资在绿幕(green screens) 上.图：背景提取并不能对于任意拍摄背景取得较好效果.此外，背景提取并不能解决 alpha 值的问题，与分割一样存在相同的硬边缘问题. 且，当背景和前景比较相似、背景存在运动时，背景提取也不能很好的解决.2. 使用任意拍摄的背景Using A Casually Captured Background由于 matting 是比 segmentation 更难得问题，即使是采用深度学习技术，往往需要再利用其他信息来解决 matting 无约束问题.比如，很多算法需要采用 trimap 或手工标注的已知前景、背景和未知区域. 尽管其对于单张图片是可行的，但视频的标注是极其费时的，因此并不是视频抠图的一个可行研究方向.而这里，采用拍摄的背景作为真实背景的一种估计. 其使得前景和 alpha 值得求解更容易. 称之为“随意拍摄(casually captured)”背景，因为其包含轻微的抖动、颜色差一、轻微阴影、或者与前景相似的颜色.图：拍摄过程. 当目标离开场景后，再拍摄的一张背景有助于算法.图：拍摄的输入、背景和新背景组合后的结果.需要注意的是，这张图片是很有挑战的，因为其前景颜色和背景颜色非常相似(尤其是的头发周围). 而且，其是采用手持设备拍摄的，会包含轻微的背景抖动.“We call it a casually captured background because it can contain slight movements, color differences, slight shadows, or similar colors as the foreground.”2.1. 拍摄建议尽管本文算法能够处理一定的背景干扰，但如果背景是固定的且最好是室内，其效果会更好. 例如，算法对于由于目标所导致的存在高度可见阴影、背景移动(如水流、车流、树木) 或大曝光变化的情况时，是效果不好的. 图：失败情况. 人物在移动的喷泉前面.此外，还推荐在视频结束时，让人物离开场景；然后从连续的视频中拉出那一帧画面. 许多智能手机对于视频模式切换到照片…

基于语义分割和Alpha blending的图像背景定制[译]
type: item
date: 2020-09-12T11:31:00+00:00
description: 原文：Whiten/customize the background of images using Semantic Segmentation and Alpha Blending - 2019.12.26作者：Shilpi Bhattacharyya图：语义分割和 alpha blending 技术用于改变图像的背景.图：使用语义分割和 alpha blending 的处理流程. 将背景区域像素值设为 0.完整实现：https://github.com/shilpibhattacharyya/customizing_image_backgrounds是否有使用 Photoshop 进行图像背景白化(whiten)和改变时抓狂的时候呢？有的话，请进入语义分割.1. 语义分割语义分割是一种将图像中每个像素进行归类的图像分析任务. 类似于人的方式，当人在看一幅图像时，知道图像的每个像素属于哪一类.更多关于语义分割的资料，可参考：Image Segmentation - 2018.11.05这里采用 DeepLabV3 进行语义分割，alpha blending 进行将原图融合到新背景.图：输入图像采用 Deeplab 模型语义分割处理. 期望输出是，覆盖在输入图像上的语义标签. 语义分割模型关注与对图像中每个像素分配语义标签，如sky, person, car 等.DeepLab 是 Google Brain 提出的语义分割结构，其是一种先进的语义分割深度学习模型. 其系列主要有：DeepLabv1 - 采用 atrous conv 来显式地控制网络中所计算的特征图的分辨率；DeepLabv2 - 采用 atrous spatial pyramid pooling(ASPP) 来鲁棒的分割物体，其在不同的采样率和有效接受野进行多尺度处理(using atrous spatial pyramid pooling (ASPP) to robustly segment objects at multiple scales with filters at multiple sampling rates and effective fields-of-views)；DeepLabv3 - 采用图像层(image-level)特征来增强 ASPP 模块，以捕获更大范围的特征. 此外，还包含 batch normalization 参数来提升模型训练. 具体来说，在训练和验证阶段，采用 atrous conv 提取不同输出步长(output strides)的输出特征，有效的增强了在步长=16 的 BN 训练，且验证阶段在步长=8时获得了更好的效果.google - deeplab2. 语义分割实现2.1. 分割输出解码函数：将 2D 分割图像转换为 RGB 图像，其中每一个标签被映射到对应的颜色.import numpy as np def decode_segmap(image, nc=21): label_colors = np.array([(0, 0, 0), # 0=background # 1=aeroplane, 2=bicycle, 3=bird, 4=boat, 5=bottle (128, 0, 0), (0, 128, 0), (255, 255, 255), (0, 0, 128), (128, 0, 128), # 6=bus, 7=car, 8=cat, 9=chair, 10=cow (0, 128, 128), (128, 128, 128), (64, 0, 0), (192, 0, 0), (64, 128, 0), # 11=dining table, 12=dog, 13=horse, 14=motorbike, 15=person (192, 128, 0), (64, 0, 128), (192, 0, 128), (64, 128, 128), (255, 255, 255), # 16=potted plant, 17=sheep, 18=sofa, 19=train, 20=tv/monitor (0, 64, 0), (128, 64, 0), (0, 192, 0), (128, 192, 0), (0, 64, 128)]) r = np.zeros_like(image).astype(np.uint8) g = np.zeros_like(image).astype(np.uint8) b = np.zeros_like(image).astype(np.uint8) for l in range(0, nc): idx = image == l r[idx] = label_co…

阿里达摩院视觉算法-透明抠图[转]
type: item
date: 2020-09-06T11:07:00+00:00
description: 原文：达摩院视觉算法黑科技之透明抠图 -2020.07.13出处：阿里云视觉智能开放平台论文：Segmenting Transparent Objects in the Wild - 2020Github - Segment_Transparent_Objects简介： 透明抠图问题作为抠图问题的一种，其采用的方法和模型构建与通常的模型有所不同，透明抠图需要将环境光、折射率的影响纳入计算，而一般的折射光图又很难获得，因此透明抠图的模型在过去一直难以建立，或者说很难达到令人满意的效果，达摩院视觉算法团队通过双分支解码器（Object Mask获取，Opacity预测），颜色纠正模块，对图像实现高精度透明抠图.1. 透明抠图 vs 非透明抠图物体的抠图问题可以定义为求解以下的公式，即给定图像I，求解前景颜色F、背景颜色B和Alpha matte的线性组合:$$ I = \alpha F + (1 - \alpha)B, \alpha \in [0, 1] $$对于透明物体而言，它展现在观察者眼中的颜色是由其前景颜色，背景颜色以及环境光线经过前景物体自我反射折射混合而成的，因此，它的公式会更加复杂一些：$$ I = \alpha F + (1 - \alpha)B + \Phi, \alpha \in [0, 1] $$$$ \Phi = \iint R(\omega \rightarrow p) E(\omega) d \omega dp $$Φ表示的是环境光的影响, 它是所有光线E(w)与反射率方程R乘积在所有点上的二重积分，求解很复杂[1]，导致实现精确的透明抠图是一个非常困难的问题. 因此，现有透明抠图研究的目标也是实现视觉感受“真实”的抠图而已，并非追求完全真实的抠图结果.2. 透明抠图-现有研究SOTA的Matting算法在同时提供原图和对应trimap的情况下，可以的实现对半透物体的处理（如下图为GCA-Matting[2]的效果），但tripmap在实际的图像的处理中难以获取，限制了这类算法其在业务中的使用. TOM-Net[3] 将透明抠图问题视为折射流的估计问题，网络支持对单图输入,经过三分支的编解码器网络，分别预测图像的Object Mask，attenuative mask，flow mask(折射流图)，并可以通过折射流信息进一步在新的背景进行合成. 该方法的局限性在于其假设物体必须全部为无色透明物体，并且在训练过程中需要折射流图作为label, 而折射流图在真实世界是非常难以获取的，因此该方法的训练数只能依赖于图形学合成，与真实透明图像的分布无法一致（图像的语义合理性存疑，例如玻璃杯在山前悬浮）. 经过我们在实际数据上的测试，该方法在实际图像的表现并不理想. Segmenting Transparent Objects in the Wild[4]提出了基于语义分支和边缘分支结构的真实世界透明物体分割网络，通过边界注意力模块（Boundary Attention Modeule）增强对透明物体的分割精度，并发布了目前数量最大的透明物体分割标注数据集Trans10K. 然而，文章提出的算法和发布的数据集都是处理到语义分割层面，并没有对物体的透明度做进一步处理. 3. 透明抠图-问题简化考虑到透明抠图问题本身难以求解，而且数据构建也非常困难，在实际的应用场景中，为保证同时保证算法的泛化能力和抠图效果，我们对问题进行了简化， 我们假设所需处理的物体的透明部分是无色的，且所在环境的背景颜色分布相对均匀. 在这样的条件下，背景的自发光或反射光的颜色可以认为是全局一致的颜色，不会出现多种颜色叠加的情况，Φ的估计就只是和背景颜色相关了. 特别的，如果预知背景的颜色，可以通过将其作为先验引入Φ中，对结果进行背景杂色的抑制及去除.4. 透明抠图-模型设计我们的模型输入为单张图像，首先提取其深层特征. 然后进行语义级别的分割和提取，力求完整准确地获得物体所在图像区域（Mask）. 同步进行对图像物体不透明度(Opacity)的预测. 而不透明度(Opacity)的预测由于在训练的时候没有进行语义的约束，容易存在非主体区域的噪声影响，因此，将两者进行融合可以将透明信息约束在主体范围内. 最后，对于已知背景颜色先验的场景（如已知是绿幕），我们可以引入颜色纠正模块，实现对背景透出的杂色进行去除. 对于背景颜色未知，但饱和度低的场景，抠图结果也依然可用. 5. 透明抠图-结果与应用在已知背景颜色先验的情况下，可以通过颜色纠正模块对背景透出的杂色进行去除（左到右：实拍图，Opacity, 直接抠图结果，色偏纠正结果）对于背景颜色未知，但饱和度低的场景，抠图结果也依然可用，例如下面几组展示图. 目前在车辆分割算法上，我们已经实现了基于透…

Github 项目 - U2Net 网络及实现
type: item
date: 2020-07-06T04:22:00+00:00
description: 论文：U^2-Net: Going Deeper with Nested U-Structure for Salient Object Detection - 2020作者：Xuebin Qin， Zichen Zhang， Chenyang Huang， Masood Dehghan， Osmar R.Zaiane， MartinJagersand团队：University of Alberta, Edmonton, CanadaGithub - U-2-NetU2Net，即U^2-Net(U square Net).1. U2Net 网络结构U2Net 网络结构如下图，其类似于编码-解码(Encoder-Decoder)结构的 U-Net. U2Net 每个 stage 由新提出的 RSU模块(residual U-block) 组成. 例如，En_1 即为基于 RSU 构建的.其优势在于：[1] - 提出 RSU 模块，融合不同尺寸接受野的特征，以捕获更多不同尺度的上下文信息(contextual information).[2] - 基于 RSU 模块的 池化(pooling) 操作，在不显著增加计算成本的前提下，增加了整个网络结构的深度(depth).1.1. RSU 模块RSU, ReSidual Ublock, 用于捕获 intra-stage 的 multi-scales 特征. 其结构如图：图: (a) Plain CNN, PLN. (b) Residual-like block, RES. (c) Dense-like block, DSE. (d) Inception-like block, INC. (e) Residual U-block, RSU.RSU 模块和 residual block 对比：注：PPM, pyramdi pooling modules.1.2. 损失函数类似于论文 Holistically-nested edge detection(HED)，U2Net 训练的损失函数定义为：$$ \mathcal{L} = \sum_{m=1}^M w_{side}^{(m)} \mathcal{l}_{side}^{(m)} + w_{fuse}\mathcal{l}_{fuse} $$其中，M=6, 为U2Net 的 Sup1, Sup2, ..., Sup6 stage. $\mathcal{l}_{side}^{(m)}$ 为 Sup1, Sup2, ..., Sup6 输出的显著图(saliency map) $S_{side}^{(m)}$ 的损失函数.$\mathcal{l} _{fuse}$ 为最终融合输出的显著图$S_{fuse}$ 的损失函数.$w_{fuse}$ 为每个损失函数的权重.对于每个 $\mathcal{l}$，采用标准的二值交叉熵损失函数：$$ \mathcal{l} = - \sum_{(r, c)}^{(H, W)}[P_{G_{(r, c)}} log P_{S(r, c)} + (1 - P_{G(r, c)}) log(1 - P_{S(r, c)})] $$其中，$(r, c)$ 为像素坐标；(H, W) 为图像尺寸，height 和 width.$P_{G(r, c)}$ 和 $P_{S(r, c)}$ 分别表示 GT 像素值和预测的显著概率图(saliency probability map).2. U2Net 输出结果可视化U2Net的输出结果，如图：3. U2Net 实现Github - U-2-Net3.1. U2Net 和 U2NetPu2net.py:import torch import torch.nn as nn from torchvision import models import torch.nn.functional as F class REBNCONV(nn.Module): def __init__(self,in_ch=3,out_ch=3,dirate=1): super(REBNCONV,self).__init__() self.conv_s1 = nn.Conv2d(in_ch,out_ch,3,padding=1*dirate,dilation=1*dirate) self.bn_s1 = nn.BatchNorm2d(out_ch) self.relu_s1 = nn.ReLU(inplace=True) def forward(self,x): hx = x xout = self.relu_s1(self.bn_s1(self.conv_s1(hx))) return xout ## up…