【PS算法理论探讨一】 Photoshop中两个32位图像混合的计算公式(含不透明度和图层混合模式)。
大家可以在网上搜索相关的主题啊,你可以搜索到一堆,不过似乎没有那一个讲的很全面,我这里抽空整理和测试一下数据,分享给大家。
我们假定有2个32位的图层,图层BG和图层FG,其中图层BG是背景层(位于下部),图层FG是前景层(位于上部),我们摸索其混合后的颜色的计算公式。
我们取一个点的像素做分析:
其中BG层某点的颜色为: B1 = 168 G1 = 99 R1= 114 A1 = 70
其中FG层某点的颜色为: B2= 80 G2 = 71 R2= 162 A2 = 135
场景一:两个图层直接叠加
即混合模式为正常,前景的不透明度为100%,如下所示:
得到的混合结果为 B = 97 G = 76 R = 153 A = 168
注意这些数据的格式都是 Format32bppArgb,而非Format32bppPArgb,即没有进行预乘的ARGB数据。
根据这些数据进行推算,得出以下规律,首先是结果色的A值计算公式如下:
其中ClampToByte函数的作用为限制括号内的数据在0和255之间,如果大于255,则取255,如果小于0,则取0值。
按照此公式复核下上面的结果看下:
结果正确。
对于RGB各分量,计算公式要复杂很多,经过推到和测试结果如下(以B分量为例):
把数据带入核算一下:
同理:
公式完全正确。
上面的计算如果要保证精度,则A值需要用浮点数保存,这样可能在某些场合下造成计算瓶颈,如果要全部用整数运算,可利用用Matlab的符号运算在做简化。
在matlab中用如下代码做测试:
syms B1 A1 B2 A2;
B =( B1 * A1 + B2 * A2 - A1 * A2 / 255 * B1) / (A1 + A2 - A1 * A2 / 255);
simplify(B)
得到结果:
B1 - (255*A2*(B1 - B2))/(255*A2 - A1*(A2 - 255))
这个结果只有一个除法,而且可以看到除法的分子和分母的数据也不会大于int32所能表达的范围。这样可借助于整数的除法实现结果。
场景二:仅仅改变图层混合模式
我们仅仅改变前景色图层的混合模式,而不改变其不透明度。以正片叠底模式为例,如下图所示:
此时前述两个颜色的混合值如下所示:
B = 91 G = 67 R = 133 A = 168
注意到A值并没有任何的变化。
此时,我们定义一个函数F,表示混合模式对两种的颜色影响,F(X, Y)表示某种混合模式下两种颜色值X和Y的混合结果,对于正片叠底,F(X,Y)的计算方法为:
F(X,Y) = X * Y / 255;
经过测试,这个时候的RGB分量的混合公式为:
把数据带入核算一下:
G和R的值就不进行重复的核算了。
这个计算式用Maltab去简化的话基本没有任何效果。
场景三:仅仅改变图层的不透明度
如下所示设置,前景层的不透明度为70%。
此时前述两个颜色的混合值如下所示:
B = 108 G = 80 R = 147 A = 139
所有的颜色都变了。
还是先来看A值,经过测试比对,此时A值的计算公式为:
其中O表示不透明度的值,有效范围是[0,100]。
核算一下:
对于A值,我们可以认为不透明度首先修改了改成的Alpha,然后再拿这个新的Alpha和底层的Alpha进行正常的混合。
对于RGB各分量,经过推到和测试结果如下(以B分量为例):
核算一下:
正确无误。
场景四:同时改变图层混合模式和不透明度
如下所示设置,同时设置混合模式为正片叠底,不透明度为70%。
此时前述两个颜色的混合值如下所示:
B = 103 G = 72 R = 130 A = 139
可以看到,A值和混合模式没啥关系,之和不透明度有关,直接用只改变不透明度时的公式:
那么RGB的变化,从前面的几个公式中可以猜测肯定是先下面这个式子了:
测试下:
完全正确。
那么在写代码的时候,我们最需要优化的就是这个情况的公式。不过用matlab测试这个公式没啥好优化的。
上述公式里其实有些ClampToByte函数是可以不需要的。
如果想时刻关注本人的最新文章,也可关注公众号:
【PS算法理论探讨一】 Photoshop中两个32位图像混合的计算公式(含不透明度和图层混合模式)。的更多相关文章
- 【PS算法理论探讨二】 Photoshop中图层样式之 投影样式 算法原理初探讨。
接下来几篇文章我们将稍微简单的探索下PS中多种图层混合模式的算法内部原理,因为毕竟没有这方面的官方资料,所以很多方面也只是本人自己的探索和实践,有可能和实际的情况有着较大的差异. 在PS的实践中,图层 ...
- Java中两个List对比的算法
Java中两个List对比的算法: // 测试数据 // tdcsDdt.add("Z"); // tdcsDdt.add("B"); // tdcsDdt ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- [转载] 散列表(Hash Table)从理论到实用(中)
转载自:白话算法(6) 散列表(Hash Table)从理论到实用(中) 不用链接法,还有别的方法能处理碰撞吗?扪心自问,我不敢问这个问题.链接法如此的自然.直接,以至于我不敢相信还有别的(甚至是更好 ...
- JavaScript中两个对象数组 属性undefined
var BaiduUsers = []; var UserArray = function(name, phone, id, id2) { this.name = name; this.phone = ...
- kd-tree理论以及在PCL 中的代码的实现(转载)
该文转自:https://www.cnblogs.com/li-yao7758258/p/6437440.html kd-tree理论以及在PCL 中的代码的实现 (小技巧记录:博客园编辑的网页界 ...
- BLDC有感FOC算法理论及其STM32软硬件实现
位置传感器:旋转编码器 MCU:STM32F405RGT6 功率MOS驱动芯片:DRV8301 全文均假设在无弱磁控制的情况下 FOC算法理论 首先,我们要知道FO ...
- OpenCV成长之路(3):模仿PhotoShop中魔术棒工具
本文的主题实际上是图像的颜色空间的转换,借助一个颜色选取程序来说明OpenCV中颜色转换函数的用法以及一些注意事项. 一.几种常见的颜色空间: RGB颜色空间:RGB采用加法混色法,因为它是描述各种“ ...
- 在db2中 两个数据库之间的两个表的联合查询
大家好,今天遇到了在db2中 两个数据库之间的两个表的联合查询 我知道oracle中有dblink,可是不知到db2的两个数据库联合查询怎么处理我找了类似于比如两个数据库: db1,db2用户名密码s ...
随机推荐
- 【TLS】-TLS/SSL笔记
目录 前言 概念 对称加密 非对称加密 公钥 单向加密 数字签名 基础 作用 SSL/TLS 模型 运作 问题&解答 基本过程 握手阶段 客户端发出请求(ClientHello) 服务器回应( ...
- 反转单词顺序列 牛客网 剑指Offer
反转单词顺序列 牛客网 剑指Offer 题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但 ...
- 虚拟化与kvm
cpu指令级别 传统中操作系统运行于R0中称之为特权级别,直接与硬件进行交互. 应用程序运行于r3级别称之为低权限,无法与硬件直接进行交互.也就是说程序是运行于用户态,系统运行于内核态中. 虚拟化要解 ...
- Jmeter 正则表达式提取Response Headers,Response Body里的值
实践过程中遇到需要提取Response Headers,Response Body里的值 一.获取Response Body的值,这里采用json提取器形式 1.Response Body返回值,如下 ...
- PTA 7-7 六度空间 (30分)
PTA 7-7 六度空间 (30分) "六度空间"理论又称作"六度分隔(Six Degrees of Separation)"理论.这个理论可以通俗地阐述为:& ...
- Java学习(十一)
今天学习了this和static关键字,这两个都是c++中学过的,但讲师还是讲了2个小时... 学得东西大部分都知道吧. this是当前对象的地址,类中带有static的方法不能使用this. 类中带 ...
- 《Python语言程序设计》【第1周】Python基本语法元素
实例:温度转化 #TempConvert.py 单行注释 ''' TemConvert.py ''' # 多行注释 TempStr = input("请输入带有符号的温度值: ") ...
- JS中innerHTML、outerHTML、innerText 、outerText、value的区别与联系?
1.innerHTML 属性 (参考自<JavaScript高级程序设计>294页) 在读模式下,innerHTML 属性返回与调用元素的所有子节点(包括元素.注释和文本节点)对应的 HT ...
- RocketMQ架构原理解析(二):消息存储
一.概述 由前文可知,RocketMQ有几个非常重要的概念: broker 服务端,负责存储.收发消息 producer 客户端1,负责产生消息 consumer 客服端2,负责消费消息 既然是消息队 ...
- ubuntu 首次登陆设置root密码
用过ubuntu的人都知道,ubuntu默认root密码是随机的,即每次开机都有一个新的root密码.我们可以在终端输入命令sudo passwd,然后输入当前用户的密码 给root用户设置密码 ...