如何在 python 中进行 alpha 抠图

2023-11-25

如何在 python 中进行 alpha 抠图?

更具体地说,如何提取图像的 alpha 通道,给定一个将像素标记为

  • 100% 前景(白色)
  • 100% 背景(黑色)
  • 或未知(灰色)

输入图像

enter image description here

输入三元图

enter image description here


使用库进行 alpha 抠图

这里有两个选项,都基于论文“自然图像抠图的封闭式解决方案”莱文和利辛斯基。

  • https://github.com/MarcoForte/close-form-matting
  • https://github.com/99991/matting

其背后的数学原理

  1. 计算矩阵L基于图像I它描述了相邻像素的相似程度:

matrix L

  1. 使用约束矩阵求解 alpha 的线性系统D和矢量b修复已知的 alpha 值:

solve for alpha

python 中的实现

import numpy as np
import numpy.linalg
import scipy.sparse
import scipy.sparse.linalg
from PIL import Image
from numba import njit

def main():
    # configure paths here
    image_path  = "cat_image.png"
    trimap_path = "cat_trimap.png"
    alpha_path  = "cat_alpha.png"
    cutout_path = "cat_cutout.png"

    # load and convert to [0, 1] range
    image  = np.array(Image.open( image_path).convert("RGB"))/255.0
    trimap = np.array(Image.open(trimap_path).convert(  "L"))/255.0

    # make matting laplacian
    i,j,v = closed_form_laplacian(image)
    h,w = trimap.shape
    L = scipy.sparse.csr_matrix((v, (i, j)), shape=(w*h, w*h))

    # build linear system
    A, b = make_system(L, trimap)

    # solve sparse linear system
    print("solving linear system...")
    alpha = scipy.sparse.linalg.spsolve(A, b).reshape(h, w)

    # stack rgb and alpha
    cutout = np.concatenate([image, alpha[:, :, np.newaxis]], axis=2)

    # clip and convert to uint8 for PIL
    cutout = np.clip(cutout*255, 0, 255).astype(np.uint8)
    alpha  = np.clip( alpha*255, 0, 255).astype(np.uint8)

    # save and show
    Image.fromarray(alpha ).save( alpha_path)
    Image.fromarray(cutout).save(cutout_path)
    Image.fromarray(alpha ).show()
    Image.fromarray(cutout).show()

@njit
def closed_form_laplacian(image, epsilon=1e-7, r=1):
    h,w = image.shape[:2]
    window_area = (2*r + 1)**2
    n_vals = (w - 2*r)*(h - 2*r)*window_area**2
    k = 0
    # data for matting laplacian in coordinate form
    i = np.empty(n_vals, dtype=np.int32)
    j = np.empty(n_vals, dtype=np.int32)
    v = np.empty(n_vals, dtype=np.float64)

    # for each pixel of image
    for y in range(r, h - r):
        for x in range(r, w - r):

            # gather neighbors of current pixel in 3x3 window
            n = image[y-r:y+r+1, x-r:x+r+1]
            u = np.zeros(3)
            for p in range(3):
                u[p] = n[:, :, p].mean()
            c = n - u

            # calculate covariance matrix over color channels
            cov = np.zeros((3, 3))
            for p in range(3):
                for q in range(3):
                    cov[p, q] = np.mean(c[:, :, p]*c[:, :, q])

            # calculate inverse covariance of window
            inv_cov = np.linalg.inv(cov + epsilon/window_area * np.eye(3))

            # for each pair ((xi, yi), (xj, yj)) in a 3x3 window
            for dyi in range(2*r + 1):
                for dxi in range(2*r + 1):
                    for dyj in range(2*r + 1):
                        for dxj in range(2*r + 1):
                            i[k] = (x + dxi - r) + (y + dyi - r)*w
                            j[k] = (x + dxj - r) + (y + dyj - r)*w
                            temp = c[dyi, dxi].dot(inv_cov).dot(c[dyj, dxj])
                            v[k] = (1.0 if (i[k] == j[k]) else 0.0) - (1 + temp)/window_area
                            k += 1
        print("generating matting laplacian", y - r + 1, "/", h - 2*r)

    return i, j, v

def make_system(L, trimap, constraint_factor=100.0):
    # split trimap into foreground, background, known and unknown masks
    is_fg = (trimap > 0.9).flatten()
    is_bg = (trimap < 0.1).flatten()
    is_known = is_fg | is_bg
    is_unknown = ~is_known

    # diagonal matrix to constrain known alpha values
    d = is_known.astype(np.float64)
    D = scipy.sparse.diags(d)

    # combine constraints and graph laplacian
    A = constraint_factor*D + L
    # constrained values of known alpha values
    b = constraint_factor*is_fg.astype(np.float64)

    return A, b

if __name__ == "__main__":
    main()

输出阿尔法

cat alpha

输出断流

cat cutout

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 python 中进行 alpha 抠图 的相关文章

随机推荐

  • 仅当成功保存父对象时才保存对 has_many 关联的更改吗?

    假设每个Project has many Tasks If I do some project tasks list of tasks some project save 即使保存失败 项目的任务也会更新 如果list of tasks由新
  • 在 emacs 中将预处理器指令缩进为 C 代码

    默认情况下 Emacs 不缩进预处理器代码 我知道它有历史根源 但现在已经过时了 然而 具有大量未缩进的 ifdef 的代码很难阅读 所以我想让 emacs 自动缩进给我类似的东西 void myfunc int foo ifdef BAR
  • Python mysql.connector InternalError:关闭游标时发现未读结果

    我想从光标读取部分结果 然后关闭它而不读取所有结果 cursor close raises InternalError Unread result found 是否可以关闭游标而不迭代所有结果或使用缓冲选项 Update 我的查询得到大约
  • Visual Studio Code 无法使用“code”命令打开

    当我尝试从命令行打开 VSCode 时code 我收到错误 MacOS Electron No such file or directory 我怎样才能解决这个问题 如果您遇到以下错误 usr local bin code line 6 u
  • 在同一个 UI 中使用 QVTKWidget 和 QOpenGLWidget?

    我正在开发一个使用自定义子类的项目QOpenGLWidget显示一些效果图 结束时paintGL 它调用小部件的方法update 方法触发重绘事件 如果它可见 现在我想添加一个额外的QVTKWidget到我的用户界面 我通过使用这样的东西来
  • 在条形图中设置轴标签和刻度线的不同位置

    我想重新对齐 偏移条形图的 x 轴和相关刻度线 这应该很简单 但我很难找到答案 下面是一些包含 24 个类别的示例数据 xval c 1 24 count c 0 03 0 03 0 08 0 06 0 11 0 4 0 3 0 5 0 5
  • 为什么 Safari 不接受 GZIP 压缩?

    我这里有一个相当大的 JavaScript 文件 我想将其嵌入到我的网站中 HTTP 服务器足够智能 可以在将文件传送到浏览器之前对其进行 GZIP 不过 我用 Google Chrome 和 Safari 进行了测试 在 Chrome 上
  • spring TransactionTemplate 和 SimpleJdbcTemplate 是线程安全的吗?

    我目前正在处理的代码中 有一个单例被许多线程使用 除了 TransactionTemplate 和 SimpleJdbcTemplate 的两个字段之外没有状态 这两个字段在单例的函数中用于访问数据库 这安全吗 还是我应该在需要时创建一个新
  • ./ 和 ~/ 之间的区别

    创建文件路径和 URL 时 我注意到很多时候路径以 or 以以下开头的文件路径有什么区别 and 它们各自的含义是什么 为了完整起见 Just path是一个名为的文件或目录path在当前目录中 path是一个名为的文件或目录path在当前
  • 如何更新 Rails 语言环境 YML 文件而不丢失注释和变量?

    我正在构建一个 Ruby 脚本来更改 config locales yml Rails 语言环境文件的内容 这些文件包含许多有用的注释和变量 通过加载 更新和转储它们 我丢失了这些注释和变量 如何以编程方式更新 YAML 文件 同时保留注释
  • 分支在 ?: 运算符?

    对于现代硬件上的典型现代编译器 运算符结果会产生影响指令管道的分支吗 换句话说 调用这两种情况以避免可能的分支 哪个更快 bool testVar someValue Used later purge white purge black 或
  • 如何隐藏 Html 日历面板中的年份部分?

    有没有办法隐藏年份部分 html 日历面板 只显示日历上的月份和日期部分 不幸的是 没有简单的答案 但是您可以使用替代方法 通过使用 JavaScript 强制用户仅输入月份和日期 var year new Date getFullYear
  • 按 ID 删除数百万行的最佳方法

    我需要从 PG 数据库中删除大约 200 万行 我有一个需要删除的 ID 列表 然而 我尝试做到这一点的任何方法都需要几天的时间 我尝试将它们放入表中并以 100 为一批进行操作 4 天后 该操作仍在运行 仅删除了 2972 68 行 我必
  • 带有数字和默认键盘的 UITextField

    为 邮政编码 邮政编码 字段创建了一个 UITextField 其键盘类型为 UIKeyboardTypeDefault 我想使用默认键盘 但希望默认显示数字和符号与字母相对应 当您在 Contacts app 中输入地址时 Apple 会
  • 使用 crontab 运行脚本时无法导入 Python MySQL 模块

    我正在使用 crontab 运行需要 MySQLdb 模块的 python 脚本 当我从命令行运行此脚本时 一切正常 但是 尝试使用 crontab 运行它会引发此错误 Traceback most recent call last Fil
  • Apple 的文本渲染如何绘制字体没有的字形?

    我对字体和编码有了基本的了解 但最近我不得不在我的舒适区之外做一些事情 转动字符 0x2716 重乘 x 变为CGPathRef 我使用了核心文本CTFontGetGlyphsForCharacters来完成这项工作 我明白 一个CGGly
  • 无法将不可变值作为 inout 参数传递:文字不可变,为什么?

    我想做一个函数来交换两个变量 但对于新的 swift 我不能使用 var import UIKit func swapF inout a Int inout with b Int print x a and y b a b b a prin
  • 如何在 Symfony 2 中通过伪造登录来测试 ACL 进行开发

    我正在开发基于 Symfony 2 的 Web 应用程序的一部分 与许多应用程序一样 需要身份验证和授权 我如何继续开发 通过传递或伪造登录来考虑 ACL 在文档中 login check身份验证和会话部分是否透明 我想我可能需要实现一个版
  • 用于调整窗口大小的自定义挂钩

    我正在创建一个自定义挂钩来捕获浏览器窗口大小 以便让我知道它是否是移动的 目前 我的问题是 React 告诉我它无法在 useEffect 挂钩中保留 screenSize 的变量值 我该如何解决这个问题 export default fu
  • 如何在 python 中进行 alpha 抠图

    如何在 python 中进行 alpha 抠图 更具体地说 如何提取图像的 alpha 通道 给定一个将像素标记为 100 前景 白色 100 背景 黑色 或未知 灰色 输入图像 输入三元图 使用库进行 alpha 抠图 这里有两个选项 都