power bi 日期计算_Colorful计算案例(一):色卡的光谱计算、色度比对

5150f3428f6b9f6eda3ecc6f3003bf81.png

Colorful框架根据此文作了些许扩展,更新版本从此处下载。

入门Colorful的建议

Colorful本质上就是一个函数集合,真正的宝藏都在Mathematica中。私以为不用专门学习Mathematica软件。一般来说,只需掌握以下几个技巧就能愉快玩耍了:

  • 函数的定义与使用。函数选项“Options”的使用
  • 列表各种操作、列表运算符与构造(Table函数很重要)。
  • 各种语法糖,如Map /@、Apply @@、前缀@、后缀//等,帮助阅读和简写代码。可以收藏这个网址随时翻阅。
  • 查帮助文档和Mathematica Stack Exchange。前人踩坑,后人乘凉。
  • 先明确数学过程再写代码,事半功倍

这里再列举Colorful计算中非常常见又很奇怪的四个符号#、&、/@、%

解释如下:

  1. #与&配合,是就地构造一个新函数,操作紧接着的表达式。如:
Power[#, 2.2]& {.5, .5, .5}

这是对后面的像素做gamma2.2的反编码。

2. /@是Map函数的简写,用作批量处理:若函数的输入是元素,但想对一整个集合的元素作处理,一般用法是“函数/@集合”,这样函数集合中的每个元素都被单独处理,输出一个新的集合。如:

XYZ2LAB/@ {{1, 1, 1},{.5, .5, .5}}
XYZ2LAB[#]& /@ {{1, 1, 1},{.5, .5, .5}}

上两句等价,都是将像素集{{1, 1, 1},{.5, .5, .5}}从XYZ转到LAB(别忘了默认白点是D65哦)。

3. %符号指“上一个结果”。如:

Power[{.5, .5, .5}, 2.2];
% * 2

这两句话是,将{.5, .5, .5}做Gamma2.2的反编码,再这个像素加一档曝光。分号表示不输出该句结果。

常用的技巧不多,再辅以案例,入门很快。

光谱的色度计算:

色彩并不存在,色彩是人眼特性+大脑皮层产生的假象,现实中只存在不同波长的光,物理上可以确定一点的光谱能量分布(Spectral Power Distribution)。Colorful中,它是

的列向量,用
表示;

人眼或相机都有三种光感受器,每种光感受器都有一个特定的光谱敏感度函数,光感受器获得1个强度值的过程是:光谱敏感度函数与光谱能量分布内积。计算光谱的颜色,就是计算人类的色彩响应。通常将LMS视作视锥细胞真实的神经冲动值,而为工程计算方便,又将LMS作线性变换到XYZ坐标下。所以在色彩计算时,XYZ坐标就是绝对的色觉坐标,XYZ就是实实在在的颜色。

所以,用XYZ坐标表示的人类色觉的“光谱敏感度函数”,叫做XYZ坐标的色匹配函数(Color Matching Function)。在Colorful中,它是

矩阵,用
表示。

某光谱能量分布的色彩计算如下:

其中“.”指矩阵乘。如果已知某反射体的光谱反射率

,在某光源
的照射下,对应的色彩计算如下:

其中“*”代表矩阵对应项相乘,e表示曝光系数。在实际计算时,e通常设置为直接对光源曝光时Y=1的值,即e应满足以下方程:

统一曝光基准的处理有很多好处。原因之一是,当曝光基准不同时,L、A、B三个值都会不同,不好做比对。这个事实留给读者自己验证。

Colorful光谱计算举例

2月7日新增了一个示例文件Spectrum.nb,例子是爱色丽ColorChecker24色卡的光谱计算,以及与官方推荐Lab值的比对。下面给出过程详解。

关于ColorChecker 24 色卡

8b8878c2bcc1ddcca8aea5bd428b2daf.png

这是24色标准色卡,最初由Macbeth公司开发,该公司最终辗转并进爱色丽。进行色卡计算时要将每个色块的编码熟记于心:从深棕色延长边是A1、B1、C1...是字母递增。

色卡是一个高科技产品。为什么这么说呢?色卡不仅色彩准确,其光谱分布也是精确设计过的。很多人建议不要用手触摸色卡,防止色彩出现偏移,这个建议值得听取。通过染料调整,色卡的光谱反射率精确到了令人发指的地步,以其中的灰卡为例:

07ebefe860b529e14a0d3dabb0122515.png

爱色丽提供很多种产品,ColorChecker Classic、ColorChecker Classic Mini、ColorChecker Proof和摄影师常见的ColorChecker Passport等。还有一个视频专用版,但它与Passport色块设置不同。爱色丽版的ColorChecker24在2014年11月底进行过一次染料配方调整,其色度值有所不同,最大DE00达到了1.95。所以查表时一定看好发布日期和对应版本。

另外,产品版本有坑,数据标准也有坑,这里不细究,推荐阅读:BabelColor。

网络上流行的色度值表格是这个(因为标在维基百科上),可惜它是老版本的表格。官方给出的2014年后版本的LAB值表格在此,其LAB坐标的参考白点是D50(但它的排序有点问题)。今天的计算就用这个官方版本,我已经做好格式化放在/Data/ColorChecker/ColorChecker24_After _Nov2014Formatted.csv中了。

在一些情况下,仅有色度值是不够的,往往需要用光谱计算,所以很多第三方网站都给出了24色色卡的光谱数据。尽管官方声称他们从未发布过色卡的光谱数据,但自带的APP中却明文记录着...今天计算的主角就是它,同样做好格式化放在/Data/ColorChecker/ColorChecker24_spectral.csv中了。

但是官方并未说明光谱分布的技术信息,尤其没有说它是“某光源照射的结果”还是“色卡的光谱反射率”,而且测量方式、参考光源、与LAB数据的关系都没有提到,所以它几乎是不可用的。今天的任务就是有理有据地猜猜它到底是啥,是D50光源照射后的结果还是色卡的光谱反射率。

数据导入

使用Import函数将光谱源数据载入。Workspace才是工作目录,所以需要用到gCSDir变量获取Colorful的根目录。习惯把"rawData"作为载入数据的前缀:

rawDataCC24Spec = 
  Import[gCSDir <> "/Data/ColorChecker/ColorChecker24_spectral.csv"];
Dimensions[%]

第二句是查看导入列表的维度,结果是{24,36},这是24个光谱分布的集合。官方介绍其为380-730nm步进为10nm的数据,而Colorful需要的是380-720nm步进为5nm的数据,所以下一步我们要用插值做转换。基本是套路:

  • 用Table构造数据本身的波长范围与步进,命名SpecRange
  • 用Table函数使导入数据与对应波长组合成列表。得到24个有对应波长的光谱的集合
  • 用Interpolation函数对每一个光谱分布做插值,选项可以调整插值阶数,这里用1,也就是线性插值。得到24个插值函数的集合
  • 用Table函数构造新的光谱集合,从插值函数中选取380-720:5的数据,命名CC24Spec
(*用Table函数构造数据对应的光谱波长范围和波长步进,得到一个长度为36的列表(380-730:10)*)
SpecRange = Table[10 x + 380, {x, 0, 35}];

(*用Table函数将光谱源文件与对应波长结合,得到24个光谱的集合*)
Table[{SpecRange[[x]], #[[x]]}, {x, 1, 36}] & /@ rawDataCC24Spec;
(*用插值Interpolation函数对集合中每一个光谱做一阶插值,得到24个插值函数的集合*)
Interpolation[#, InterpolationOrder -> 1] & /@ %;
(*用Table函数从一阶插值函数中选出我们想要的值:380-720nm,步进5nm*)
CC24Spec = Table[#[s], {s, 380, 720, 5}] & /@ %;

代码中的符号较混杂,然而这就是Mathematica的风格...

光谱的色度计算

我们的目的是验证该数据是“色卡+光源”还是“色卡的反射率”。基本思路是:

  • 如果是“D50照射后的光谱能量分布”,则直接对数据算色度值,应更接近官方LAB数据;
  • 如果是“色卡的反射率”,则数据与光源作用,再算色度值,应更接近LAB数据。

先直接算色度值:

(*1.直接算色卡光谱反射率的颜色*)
CC24XYZ = CMFXYZ.(#) & /@ CC24Spec;

得到24个色块的XYZ值CC24XYZ,是一个像素集。

再算D50光源下的色度值。LSD50是内置现成的光谱光源。还记得吗?光源+反射介质的色度计算要乘曝光系数

,保证直对光源曝光时Y=1。而Y对应色匹配函数中的第二行,所以计算曝光系数
如下:
e = 1/(CMFXYZ[[2]].LSD50)

会发现结果为1。没错,光源在定义时就做好曝光标准化了。所以接下来不用考虑

的作用。

用#、&就地构造一个函数,它可以先与LSD50对应项相乘,再被

左乘。最后对CC24Spec集合中的每一元素进行操作,生成CCD24XYZD50。
(*2.计算在D65光源下,色卡呈现的颜色,最后用计算好的曝光值相乘。*)
CC24XYZD50 = CMFXYZ.(#*LSD50) & /@ CC24Spec;

两组数据的对比、白平衡的统一

至此,我们已经对光谱做好了两种不同的处理。先把它们画在一张图上对比,隆重推出Draw1976Compare函数:

Draw1976Compare[CC24XYZ, CC24XYZD50, "SizeRatio" -> 0.5]

ac587b0ad4f54e7c164e0c97397b2d43.png

比对色度时使用CIE 1976 uv坐标系,是因为在uv中,可以简单地用两点距离估算色偏(相比之下xy坐标系很不平均)。其中SizeRatio表示第二组数据点相对于第一组数据点大小的比例,默认0.8。大点对应CC24XYZ,小点对应加光源的CC24XYZD50。

我们发现两组数据差别很大,原因是它们的白平衡不统一。CCD24XYZ的白平衡是E,而CCD24XYZD50的白平衡是D50。

这时需要用到在标准白点之间变换的ChromaticAdaptation函数,函数中提供了XYZScaling、Bradford、VonKries三种方法,公认最有效的方法是Bradford(专栏以后会展开解释),这是PS使用的方案,也是该函数的默认方法。转换如下:

(*可以看出它们的白平衡不同。用Bradford方法做一个白平衡变换*)
CC24XYZWBD50 = 
  ChromaticAdaptation[#, "E", "D50", "Method" -> "Bradford"] & /@ 
   CC24XYZ;

再次比对:

Draw1976Compare[CC24XYZWBD50, CC24XYZD50, "SizeRatio" -> 0.5]

ec3ff02860987771c8600b146791a56e.png

可以发现它们已经非常接近了,主要的区别在蓝色部分。

如此,我们获得了两组数据:

  • CC24XYZWBD50,直接从光谱计算色度,并用白平衡调到D50的数据;若它与官方LAB值更接近,则光谱数据是“D50照射后的光谱能量分布”
  • CC24XYZD50,从光谱与光源作用再计算色度;若它与官方LAB值更接近,则光谱数据是“光谱反射率”

LAB数据的导入和处理

直接导入:

CC24A2014LAB = 
  Import[gCSDir <> 
    "/Data/ColorChecker/ColorChecker24_After_Nov2014Formatted.csv"];

转换成XYZ坐标。注意该LAB数据的参考白点是D50:

(*LAB转换成XYZ,白点D50*)
CC24A2014XYZ = LAB2XYZ[#, "refWP" -> "D50"] & /@ CC24A2014LAB;

如此,我们获得了按顺序排列的24个色块的XYZ值,CCD24A2014XYZ是一个像素集。

在进入色偏比对之前,总结一下处理流程和比对思路:

105917ae1bce14c3302d61ebeeeb9169.png

色偏比对

先用CIE 1976 uv坐标系做可视化比对:

(*比对光谱计算结果和官方给出结果*)
Draw1976Compare[CC24A2014XYZ, CC24XYZWBD50, "SizeRatio" -> 0.5]
Draw1976Compare[CC24A2014XYZ, CC24XYZD50, "SizeRatio" -> 0.5]

输出两张图:

06cc530a5674d246fd91e1233b87876e.png
直接算色度+白平衡调整与官方LAB比对

f4f54a797f928e35fe5370422f01212e.png
D50光源作用结果与官方LAB比对

可以发现,第二个结果色偏非常小,在uv坐标中几乎不可见;第一个结果色偏也不大,但蓝色部分有微小色偏。

这时就要用到色偏的定量计算,使用DE00LAB函数。

①.第一组数据

首先变换为LAB,白点D50。

(*首先把CCD24XYZWBD50转成LAB,白点D50。*)
XYZ2LAB[#, "refWP" -> "D50"] & /@ CC24XYZWBD50;

DE00LAB的输入是两个“像素”,而我们想对比两组像素集对应的像素,所以先用Table构造一个新数组,将一对对欲对比的像素捆在一起,并组成像素对的集合:

(*DE00对比的是两个像素,所以要把对应像素捆在一起,组成像素对的集合*)
Table[{CC24A2014LAB[[x]], %[[x]]}, {x, 1, 24}];

用DE00LAB对比该集合中的每个像素对。这里用到一个语法糖:

DE00LAB @@@ %

如果DE00LAB对比一个像素对,则要用到Apply函数,其简写是@@;若批量对比像素对的集合,就用到@@@了。当然,最好的方法是把代码保存下来,直接用。这句的结果给出每一对像素对的DE00色差,可以输出一下其中的最大值:

Max[%]

结果是1.38304,色偏已经肉眼不可分辨了;

②.第二组数据

直接算:

XYZ2LAB[#, "refWP" -> "D50"] & /@ CC24XYZD50;
Table[{CC24A2014LAB[[x]], %[[x]]}, {x, 1, 24}];
DE00LAB @@@ %;
Max[%]

结果是0.684686。

实验结论:官方软件中的光谱数据更接近于光谱反射率。

这个结果,在一定程度上证明了,10nm步进的光谱数据,也能保证一定精度;笔者也尝试了,若将插值阶数提高,能进一步提高精度(插值阶数对精度的影响可能取决于数据本身的平滑程度)。

读者可以试试让机器告诉你哪个色块有最大色偏。


该案例中使用的流程仅作练习用,实验结论仅作参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值