Realpha - 精确地恢复图片透明通道

2021-07-24 03:06:09 +08:00
 kkocdko

首先,这名字读作“re-alpha”,而不是“real-pha”,谢谢配合。

给个链接瞅瞅?

这是个 PWA:https://kkocdko.site/toy/realpha/

附带一篇破文章:https://kkocdko.site/post/202107231958/。本人英文水平极低,各位看到狗屁不通的地方可以喷我。

为什么需要这东西?

想象这样一个场景:你看中了某个 App 里头的一枚图标,然而这枚图标是用代码动态绘制出的,无法从安装包中提取。所以你选择截图。

然而这枚图标有半透明的部分,截图会导致透明通道丢失!怎么办?

让我们看看给半透明图片增加背景的算法:

var fgR, fgG, fgB, alpha;
var bgR, bgG, bgB;
var outR = fgR * aplha + bgR * (1 - aplha);

可以看出这是个二元一次方程,要想解出原图的颜色和透明通道值,需要两个式子联立。

于是,用调试工具强制更换 App 的背景颜色,截下两张图,输入到这个工具里头,你就能得到拥有准确透明通道的图片了。

还有什么特别的玩法?

你可以给手机换不同的纯色壁纸,得到不同背景色的截图之后,用此工具提取出透明的图片,再丢进 Photoshop 操作一番,做出不错的效果图(我的手机是透明的诶)。

用 Photoshop 不行么?

不行(说实话我不太确定,如果真能实现还请各位拍醒)。你当然可以抠图,然而这是不精确的,你永远无法凭空准确地还原出透明通道。

2057 次点击
所在节点    分享创造
13 条回复
wdhwg001
2021-07-24 03:41:38 +08:00
其实,PS 的混合模式就是普通地进行数学运算。

已知:减去就是相减,划分就是除法,正片叠底就是乘法。
out1=fg*α+bg1*(1-α)
out2=fg*α+bg2*(1-α)
那么两式相减,视α为未知数,得:
1-α=(out1-out2)/(bg1-bg2)

α=1-(out1-out2)/(bg1-bg2)
所以得 PS 步骤:
① 将 out1 图与 out2 图以“减去”混合,得 doc1
② 将 bg1 图与 bg2 图以“减去”混合,得 doc2
③ 将 doc1 与 doc2 图以“划分”混合,得 doc3
④ 将纯白色图与 doc3 图以“减去”混合,得 doc4
doc4 即为还原后的 alpha
回到式 1
out1=fg*α+bg1*(1-α)
将 fg 视为未知数,得
fg=(out1-bg1*(1-α))/α
所以得 PS 步骤:
① 将 bg1 图与 doc3 图以“正片叠底”混合,得 doc5
② 将 out1 图与 doc5 图以“减去”混合,得 doc6
③ 将 doc6 图与 doc4 图以“划分”混合,得 doc7
最后,我们把 doc7 套用 doc4 作为蒙版,就得到了最终结果。

未实际操作过,不对结果负责,深夜可能解错方程,结果也可能因 0-1 标准化而不可靠,并且多步骤会造成精度丢失,建议在 16 位模式下搞。
kkocdko
2021-07-24 03:49:17 +08:00
@wdhwg001 我的天还真的可以。。。我当时也改了半天混合模式,没倒腾出来,所以才写了这个工具。你这个方法应该是可行的,而且 PS 录制个动作,大量使用也不会麻烦,谢谢咯
wdhwg001
2021-07-24 03:51:26 +08:00
PS 的问题还包括它其实每一步都做一遍 clamp,把负数和大于 1 的都 clamp 掉,所以实际操作的时候如果遇到不准确的情况可以用一个低于 255 的灰色图去提前正片叠底(乘法)或者线性减淡(加法),把颜色范围弄得小一点,尽量避免被 clamp 。
wdhwg001
2021-07-24 04:06:17 +08:00
另外比较好用的还有:
变暗是 min
变亮是 max
实色混合是 A+B>=1?1:0
差值是|A-B|

非常不好用但唯一包括 SQRT 的是:
柔光:A<=0.5 ? 2*A*B+B*B*(1-2A) : 2*B*(1-A)+SQRT(B)*(2*A-1)

会玩不嫌麻烦的话甚至可以在 PS 里写 Shader
ericgui
2021-07-24 05:05:33 +08:00
ReAlpha,自然就知道是 re-alpha
secondwtq
2021-07-24 09:03:51 +08:00
PostgreSQL
maplerecall
2021-07-24 09:54:38 +08:00
这个其实就是 chroma key,如果图片本身颜色比较丰富,可能很难找到一个合适的色,因为和背景色接近的颜色会被当做透明被扣掉。
no1xsyzy
2021-07-24 16:52:03 +08:00
(可以搞个 GIMP 插件,然后宣称 GIMP 比 PS 牛逼(
no1xsyzy
2021-07-24 16:55:05 +08:00
@maplerecall 不是的,这是用两个纯色背景作差分。
wdhwg001
2021-07-26 14:26:56 +08:00
做了一个 Photoshop 录制动作出来,看实际的效果发现,颜色比较鲜艳的话会被弄浅一点,并且需要切换至 16 位颜色以避免色带。
https://user-images.githubusercontent.com/8943519/126942318-f032f5e3-6108-46f2-a461-6a06a2c50646.png
将扩展名改为 zip 后打开,然后将 ReAlpha.atn 导入。
执行时,需要提前准备好 out1 、out2 、bg1 、bg2 四个图层(名字不要错),并且四个图层的混合效果均需为“正常”。
wdhwg001
2021-07-26 14:39:04 +08:00
进行了一下色阶对比:
原始:
https://user-images.githubusercontent.com/8943519/126943582-73583cef-1554-4266-918a-e3e7964ac022.png

8-bit 色彩模式:
https://user-images.githubusercontent.com/8943519/126943596-24a2bb4d-fc71-4af5-b30e-c9b8dd3c1abd.png

16-bit 色彩模式:
https://user-images.githubusercontent.com/8943519/126943601-579577fe-db9f-4816-a2cd-850ac8b6353d.png

这种操作的色彩精度损失还是挺明显的,说明 Photoshop 在处理色彩的时候,因为每一步都需要把浮点色彩转换成整数色彩,在这个过程中精度损失会比较大。
kkocdko
2021-07-26 19:32:27 +08:00
@wdhwg001 那看来我这个工具还是有点用的咯~
不过我觉得可以做个 Photoshop 的插件,毕竟精度损失主要是因为中间过程太多?一步到位损失会小很多吧
wdhwg001
2021-07-26 22:51:12 +08:00
@kkocdko 是的,但其实最初 out1 和 out2 的合成就是有损的,而且是 8bit,所以永远做不到无损复原。

但中间过程使用更高精度的运算还是很有必要的,毕竟 PS 里每通道最高 16 位的整数色无论如何都会丢失信息。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/791447

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX