ImageMagick 示例 -- 颜色基础与通道
- 什么是颜色?
- RGB 色彩空间
- CMY 色彩空间
- CMYK 色彩空间
- 伽马校正
- 显示器的伽马
- sRGB 色彩空间校正
- 颜色名称冲突
- 分离通道图像
- 从色彩空间得到灰度通道
- 其他通道分离方法
- 合并 RGB 通道图像
- 合并非 RGB 通道图像
- 生成 HSL 色相环
- 感知色彩空间(Lab、Luv)
-
替换图像中的颜色 (替换特定颜色)
- 替换图像中的某种颜色
- Floodfill 绘制
- Floodfill 操作符
- Fuzz 因子,匹配相近颜色
- Fuzz 因子距离
- Fuzz 因子与透明颜色
ImageMagick 所处理的栅格图像(一般来说),基本上由一组独立的点或颜色像素组成的数组构成。修改这些独立的点以及它们的表示方式,正是本节要讨论的内容。在下一节中,我们将讨论对整幅图像的颜色进行更通用的全局修改。
什么是颜色?
要真正理解颜色,你需要确切地知道颜色到底是什么。在物理世界中,颜色其实是一种错觉。我们之所以能看到颜色,是因为我们的眼睛以一种非常特殊而有限的方式感知物理世界。基本上,我们的眼睛里有针对红、绿、蓝的专门感受器,以及一个用于周边视觉和弱光条件的次要感受器。后者正是我们在夜间只能看到灰色的原因。
更多信息请参见 Wikipedia, Cone Cells,右图是典型人眼对不同波长光线的响应曲线。正因如此,我们只以红、绿、蓝电磁波长来感知世界,这也是为什么图像和图像处理通常都围绕红、绿、蓝(即 RGB)展开。然而事情也并非如此简单。我们的每一种颜色感受器实际上都对一段波长范围作出响应。例如当我们看到黄色光时,我们实际上是同时用红色和绿色感受器来感知这束光。如果我们的颜色感受器是严格的纯红色和纯绿色探测器,我们将完全看不到任何黄色。彩虹中实际上会出现“空缺”。这意味着电视或电脑显示器其实是在欺骗我们,让我们看到黄色——显示器只是发出恰当混合的红光和绿光,而非真正的黄光。我们的颜色感受器所感受到的强度与纯黄光所产生的相同,结果我们就看到了黄色,尽管实际上我们看到的是两种不同的颜色频率。我们根本无法分辨纯黄色与红绿光混合之间的差别。同样地,蓝红(紫)色实际上并不作为单一特定波长存在,而只能作为至少两种颜色频率的混合而存在,尽管严格来说紫罗兰色是我们确实会响应的一个特定频率,主要由蓝色感受器,以及另外两个感受器极轻微地响应。注意我们实际上还有第四种视觉感受器,但它不感知颜色,而是一种弱光探测器,用于夜视,此时锥体感受器已不能很好地工作。这就是为什么夜晚看起来是单色的,月光看上去全是灰色。这种感受器也很可能正是 sRGB 色彩空间(见下文)对极暗颜色具有一个奇怪线性分量的原因。旁注:其他动物拥有与我们不同的感受器。蜜蜂以及大多数其他昆虫拥有针对紫外线的感受器,因此对它们而言,我们印刷的图像、电视和广告牌大概没什么意义。这些人造图像在它们看来很可能更像一幅相当糟糕的伪彩色图像,而非我们人类被欺骗所看到的近乎完美的色彩。有些动物有 4 种颜色感受器,而另一些只有一种(黑白)或两种。还有一些动物对运动的感知远胜于对任何特定颜色的感知。例如公牛看不到红色,但能看到蓝紫色和绿色波长,而一块挥舞的斗篷会以一种耀眼的“运动”颜色呈现。对公牛来说,显示器 50/60Hz 的刷新周期,大概看起来像是一团“运动”,而不是任何有意义的图像!更多信息请参见 Wikipedia, Color Vision 和 Wikipedia, Color。
RGB 色彩空间与通道
所以 RGB 色彩空间实际上是一种用红、绿、蓝三个值来表示图像的方式,它能骗使我们以为自己看到了真实世界中的某物。因此图像可以存储为 3 个值数组,其中三个值共同构成一个待显示的像素或颜色点。这三个值数组中的每一个都被称为一个通道,它其实就是一幅灰度图像,表示要为我们某一种颜色感受器生成的光量。例如,下面是一幅玫瑰图像的红、绿、蓝分量。 ![[IM Output]](../static/img/images/rose.gif)
玫瑰 | | ![[IM Output]](../static/img/color_basics/separate_RGB_0.gif)
红 | ![[IM Output]](../static/img/color_basics/separate_RGB_1.gif)
绿 | ![[IM Output]](../static/img/color_basics/separate_RGB_2.gif)
蓝
---|---|---|---|---
注意“红”图像要比另外两个颜色分量亮得多,才能显示出玫瑰。但三幅图像对靠近底部的白色斑块都很亮。 RGB 是加色 现在,红、绿、蓝颜色被称为“加色”。也就是说,这些颜色相加在一起形成最终的彩色图像。这是因为它们是我们眼睛所看到的主导颜色,把它们组合起来,我们几乎可以有效生成眼睛能看到的所有颜色。它们之所以是加色,是因为从黑色(比如一块空白的显示器)开始,你接着加入红、绿、蓝光来生成我们所看到图像的相应颜色。其关键在于你从黑色(即没有光)开始,然后加入适量的红、绿、蓝。在黑暗的房间里,用三支手电筒、末端各贴上红、绿、蓝玻璃纸照射,你也能得到同样的效果。当这三种颜色照在同一处(比如白墙上)时,我们看到的是白色。正是因为我们的眼睛实际看到这些“原色”的方式,彩色图像通常用 RGB 值来表示,这些值也被称为“颜色通道”。
CMY 色彩空间
当你印刷时,你面对的是一个不同的问题。一张纸无法产生光,只能反射光。因此你需要从一个能将照射其上的所有光向各个方向反射的表面开始。这正是白色表面。但愿它所反射的光本身是纯白光,要么来自照进窗户的阳光,要么来自我们人工照明房间里的灯光。现在,要在那张纸上创建一幅图像,你需要在那个表面上涂上墨水,而墨水实际上会去除特定波长的光。由于我们“感知”红、绿、蓝颜色,这些正是我们想从那张白纸所反射的光中有选择地去除的颜色。因此,我们用青色墨水去除红光,用品红色墨水去除绿光,用黄色墨水去除蓝光。生成某种特定颜色所需的青、品红、黄墨水量,构成了所谓的 CMY 色彩空间。这里我生成了仅用青、品红、黄墨水(假定墨水是“线性”的)来生成玫瑰图像所需的墨水掩模 ![[IM Output]](../static/img/images/rose.gif)
玫瑰 | | ![[IM Output]](../static/img/color_basics/separate_CMY_0.gif)
青 | ![[IM Output]](../static/img/color_basics/separate_CMY_1.gif)
品红 | ![[IM Output]](../static/img/color_basics/separate_CMY_2.gif)
黄
---|---|---|---|---
也就是说,青色掩模的值越亮,就需要越多的青色墨水来去除越多的红色。换句话说,青色掩模正好是我们希望纸张反射的红光量的负片。事实上,上面三幅通道图像都正好是为 RGB 色彩空间所生成图像的负片。所以,要把一幅 RGB 图像转换为 CMK 图像,你真正需要做的只是对图像取反,然后声明该图像处于 CMY 色彩空间。由于我们是在有选择地去除波长,青、品红、黄被称为“减色”。
CMYK 色彩空间
有选择地去除波长存在一个主要问题:仅靠涂上青、品红、黄三种墨水来去除所有红、绿、蓝光,实际上并不能去除所反射的全部光线。结果你得到的不是黑色,而是一种难看的浑浊棕色。墨水(或滤光片)并不完美,正如我们自己的眼睛也不完美一样。正如我之前提到的,我们每种颜色感受器看到的并不只是一种波长的光,而是一段我们解读为“红”“绿”或“蓝”(或这些颜色的混合)的波长范围。以至于我们的“蓝”光感受器实际上能看到(尽管不太好)一点紫外线。旁注:“黑光灯”的滤光片故意做得不完美,这样我们就能“勉强看到”这种灯发出的光,从而知道它是否开着。正是由于 CMY 墨水的这种颜色“泄漏”,加上我们自己不完美的眼睛,我们还在混合中加入了纯黑墨水,用它来抹去纸张可能反射的全部光线。为了避免与蓝色(blue)混淆,黑色墨水或通道被赋予字母 K。因此印刷时我们使用四种彩色墨水:青色(Cyan)、品红色(Magenta)、黄色(Yellow)和黑色(blacK);并用这些墨水来定义图像,构成 CMYK 色彩空间。例如,下面是从这幅图像中分离出来的相应 CMYK 分量。 ![[IM Output]](../static/img/images/rose.gif)
玫瑰 | | ![[IM Output]](../static/img/color_basics/separate_CMYK_0.gif)
青 | ![[IM Output]](../static/img/color_basics/separate_CMYK_1.gif)
品红 | ![[IM Output]](../static/img/color_basics/separate_CMYK_2.gif)
黄 | ![[IM Output]](../static/img/color_basics/separate_CMYK_3.gif)
黑
---|---|---|---|---|---
注意青、品红、黄的量已经减少,现在比 CMY 色彩空间中更暗了,因为它们的作用被适量的黑色所取代。也就是说,当某个像素同时存在这三种墨水时,就改用黑色代替。因此,要打印纯黑,你只需用纯黑墨水,而不用其他墨水。记住,上面的“黑(blacK)”指的是要涂在纸上的黑色墨水量,所以灰度通道图像越亮,就应使用越多的黑色墨水。因此它也是一幅负片样的图像,正如其他三幅图像一样。当然,在彩色打印机中加入纯黑会让打印黑色文字简单得多,因为你不再需要把三种不同墨水完美叠印在同一处来生成纯黑的线条、字母和形状。这意味着墨水用量大大减少,纸张不那么“湿”,也不太容易渗开或弄脏,这对打印机尤其有利。关于 RGB 和 CMYK 颜色如何工作的另一个类似讨论,请参见以下页面的介绍部分。XaraXone Workbook, Defining Color。
其他色彩空间
其他色彩空间只是表示这些相同颜色,或表示我们不完美的眼睛也能辨别的、严格 RGB 之外的某些颜色的另一些方式。然而这类色彩空间对于用显示器显示这些颜色或对于印刷影响甚微。它们基本上代表了处理和/或加工图像颜色的其他方式,以便增强或突出某些特定方面,例如……
- 对暗色更好的非线性处理(sRGB)
- 彩虹色与色相(HSB,HSL,HSI,OTHA 色彩空间——强度不保留)
- 标准化定义的颜色(XYZ)
- 精确或感知的颜色差异(LAB 与 LUV 色彩空间,及其 LCHab 和 LCHuv 循环色相等价形式)
- 扩展的高动态范围(用于 HDRI 图像)(scRGB)
- 对颜色值更好的压缩(例如 YIQ 和 YUV)
- 电视传输(YCbCr、YPbPr,其中 Y = 黑白信号)
我还没有提到的最后一种色彩空间是“GrayScale(灰度)”,但那只是一个简单的单一像素值数组。如何解读这些值是可变的,因为它们可以表示许多不同的东西。通常这样的图像被视为线性灰度,类似于线性 RGB(与非线性 sRGB 相对)。IM 第 6 版实际上没有这样的灰度色彩空间,只是用线性 RGB 色彩空间伪造它,把所有 RGB 设置为同一个值。如果这三个值不相同,图像就不再是灰度的了。IM 第 7 版的灰度是单通道图像(内存占用小得多)。 | _上述对图像“色彩空间”的更改只是对图像颜色在内存中的一种粗略排列。它也提供了不同色彩空间之间非常基础(简化)的颜色转换。
要进行精确的颜色指定和颜色转换,应改用颜色配置文件(Color Profiles),但仅在使用能处理颜色配置文件的图像文件格式时才有效。
_
---|---
伽马校正与 sRGB 色彩空间
人类颜色感知
在上面我们看到,你可以用许多不同的方式表示图像。我们上面看到的所有色彩空间都被称为“线性”色彩空间,这意味着所用的实际值代表了图像中颜色的实际“强度”值。 然而现实生活从来没有这么简单。从来没有!例如,让我们生成并保存一幅具有简单线性灰度值序列的图像…… |
magick -size 100x100 gradient:'gray(100%)-gray(0)' \
-set colorspace sRGB gradient.gif
- 使用 "
gradient:'gray(100%)-gray(0)'" 确保 IM 生成的是线性 RGB 数据的渐变,它将处于线性 RGB 色彩空间。 - "-set colorspace sRGB" 告诉 IM 这个“线性”渐变实际上处于 "sRGB" 中,因此在保存为只能存储 sRGB 色彩空间值的 GIF 图像文件格式时不需要“校正”。
现在这幅图像中所用的实际颜色值是一个线性渐变,应当从顶部的白色平滑过渡到底部的黑色,中间是数学上精确完美的 50% 灰。然而如果你观察这幅图像,会发现图像实际上似乎包含的暗色(接近黑色)比亮色(接近白色)多得多。为什么?嗯,人类视觉在给定一个仅为其最大范围一半(“白色”)的光强时,看到的并不是颜色值所指示的纯中间调灰,而是一个暗得多的颜色。结果上面这个线性渐变看起来并不像从白到黑的均匀线性分布,而是暗色远多于应有的量。实际图像值到感知值大致是一个如下形式的“幂函数”……
**_perceived_grey_ = _value_ 2.2**
值 '2.2' 是平均伽马函数值,对大多数人而言都是典型的。
伽马校正
伽马校正是一种调整实际保存的颜色值的方法,使得最终图像在颜色分布上看起来更加均匀。基本上,由于人类视觉用 2.2 的幂因子使光线看起来更暗,为了让线性图像“看起来”线性,我们需要用 1/2.2 的值来反转那个幂函数。也就是说,要让图像看起来线性,我们需要用以下公式对它进行校正……
**_gamma_corrected_value_ = _value_ 1/2.2**
IM 通过Level 操作符的 Gamma 参数,或更具体地使用 Gamma 操作符 来提供伽马校正。不过你也可以直接使用 Evaluate POW 函数 来修改图像值。
那么让我们应用它,看看“伽马校正后图像”的结果…… |
magick -size 100x100 gradient:'gray(100%)-gray(0)' -gamma 2.2 \
-set colorspace sRGB gradient_gamma.gif
![[IM Output]](../static/img/color_basics/gradient_gamma.gif)
注意现在图像中的明暗颜色量要均等得多了。然而图像中的实际值不再是“线性”的,这在以后处理这幅图像时可能引发问题。伽马校正只是一种粗略的“快速”方法,用来调整颜色使图像“看起来”正确。它并不是为人类响应校正图像的常用方法,甚至不是最佳方法。关于为图像处理进行伽马校正的更具体示例,请参见带伽马校正的缩放 关于伽马校正的更多信息,请参见
你可能还想看看 "[-auto-gamma](https://imagemagick.org/command-line-options/#auto-gamma)" 操作符,它尝试调整伽马以产生一幅明暗量均等(在线性空间中)的线性 RGB 图像。
显示器的伽马
从显示器后退几米(码),观察左侧的图像。如果你的显示器(和网页浏览器)正确显示了这幅 sRGB 图像,那么中央“井字”图案与周围 sRGB 渐变亮度大致相等的那个点,应当位于正中间。大多数电脑显示器都通不过这个测试!不过 HDMI 电视应该表现完美。这幅图像是用以下命令创建的…… |
magick -size 45x256 gradient: -size 10x256 pattern:gray50 \
-duplicate 1,0 +append -set colorspace sRGB -colorspace RGB \
monitor_sRGB.png
![[IM Output]](../static/img/color_basics/monitor_sRGB.png)
下面是一些具有不同“伽马”级别的类似图像,让你看看你的显示器与适合人类感知的正确 '2.2' 伽马显示有多接近。
for gamma in 1.6 1.8 2.0 2.2 2.4
do
magick -size 45x256 gradient: -size 10x256 pattern:gray50 \
-duplicate 1,0 +append -gamma $gamma monitor_g$gamma.png
done
![[IM Output]](../static/img/color_basics/monitor_g1.6.png)
伽马 1.6 | ![[IM Output]](../static/img/color_basics/monitor_g1.8.png)
伽马 1.8 | ![[IM Output]](../static/img/color_basics/monitor_g2.0.png)
伽马 2.0 | ![[IM Output]](../static/img/color_basics/monitor_g2.0.png)
伽马 2.2 | ![[IM Output]](../static/img/color_basics/monitor_g2.4.png)
伽马 2.4
---|---|---|---|---
(当你后退时)等亮度点大约在 50% 标记处的那幅图像,告诉你显示器的大致伽马级别。如果调校得当,你的显示器应当具有 2.2 的伽马级别,这与 sRGB 色彩空间非常吻合。我写这段时,我那台旧屏幕(单位提供的)极差。它的伽马设置约为 1.8,而且显示器顶部(更暗)与底部(更亮)的伽马竟然不同。这给我在屏幕不同位置比较图像时带来过麻烦,因为同一幅图像在垂直方向不同位置时看起来不一样!另一方面,我的个人笔记本(当时)显示非常均匀,按上面的标准伽马设置约为 2.0。
sRGB 色彩空间校正
用 sRGB 色彩空间保存图像与对图像进行伽马校正非常相似,但稍微复杂一些,以便更好地重现人眼的实际响应,特别是对非常暗的颜色阴影。 那么让我们把线性渐变保存为 sRGB 校正后的色彩空间。 |
magick -size 100x100 gradient:'gray(100%)-gray(0)' \
-set colorspace RGB -colorspace sRGB gradient_sRGB.gif
magick -size 100x100 gradient:white-black gradient_sRGB.gif
_这是因为线性渐变总是会在线性(RGB)色彩空间中生成(这是该操作符工作的唯一合理方式)。
然而由于请求的是 sRGB 颜色 'white-black',线性数据渐变会被自动转换为 sRGB 色彩空间,产生非线性的数据值和一个感知上线性的渐变。
| _在 IM 6.7.5 版之前,上述命令会失败,因为 IM 把 'sRGB' 和 'RGB' 色彩空间的含义弄反了。因此在较旧版本的 IM 上,这两个色彩空间名称需要互换。例如…… |
magick -size 100x100 gradient: -set colorspace sRGB \
-colorspace RGB gradient_sRGB.gif
_这种色彩空间处理上的怪异长期以来被视为一个 IMv7 bug,虽然本打算只在 IMv7 中修复,但它被回移植到了 IMv7。
注意上述命令(或任何其他渐变)并不完美,因为完美根本不可能——每个人都以自己的方式、带着细微差别去看待事物。简单地说:_你所看到的,永远不会与别人看到的完全一样(这其实很有禅意)。sRGB 只不过是根据众多调查,以及大量印刷/油漆/颜色专家的意见,对大多数人而言一个非常好的近似。关于精确 sRGB 公式的细节,请参见 Wikipedia, sRGB Colorspace。一个更完整、更精确的“人类亮度响应”已被开发出来,可以在论文 Human Vision, Just Noticeable Difference 中在线看到。它包含了在重大光照变化情况下的自适应响应。万维网已经标准化使用 sRGB 作为推荐的(且仍然相当简单的)默认色彩空间,因此应当用于所有不包含任何色彩空间配置文件信息的图像。也就是说,用于诸如 GIF、PNG、JPEG 和 TIFF 之类的图像。所有这些格式(GIF 除外)都允许使用颜色配置文件(Color Profiles)来明确指定图像的色彩空间。然而诸如 PbmPlus 之类的图像文件格式通常不被视为处于 sRGB 色彩空间。因此在处理这类文件格式时,使用 "-set colorspace ..." 来确保色彩空间符合你的预期,通常是个好主意。下面把三幅图像放在一起,以便你比较它们。 ![[IM Output]](../static/img/color_basics/gradient.gif)
线性 | ![[IM Output]](../static/img/color_basics/gradient_gamma.gif)
伽马 | ![[IM Output]](../static/img/color_basics/gradient_sRGB.gif)
sRGB
---|---|---
正如你所见,伽马校正和 sRGB 校正后的图像几乎相同,画成图时差异实际上极其微小。因此,虽然使用 sRGB 是更正确的方法,但使用伽马校正应用起来大概更容易。sRGB 与伽马图像之间最大的差异出现在极暗的图像中。对于 8 位灰度值 1,sRGB 比等效的伽马亮 60 倍。值为 8 时亮 5 倍。这在大多数情况下不会造成任何明显差异,但在处理非常暗的图像时则可能造成差异。
处理真实图像
大多数图像处理操作符并不关心图像使用的是什么色彩空间,它只是把操作应用于通道数据,而不管其色彩空间。不过有些操作符必须为处理“黑色(Black)”的额外通道数据作出特殊处理,正如你稍后会看到的还有“Alpha”(即“Alpha”透明度)。然而图像的色彩空间会极大地影响许多操作的最终结果。因此在不同的色彩空间中进行图像处理可以产生更好的结果。这个示例更清楚地说明了为什么在 sRGB 中进行处理不是个好主意。来自 IM 用户论坛上关于颜色模糊(Color Blurs)和“损坏的颜色(Broken Colors)”的一场讨论。 我们取两种使用不同颜色通道的颜色,把它们模糊在一起,使得在通道内颜色模糊趋向于零(一个低颜色值)。先用默认的 sRGB 输入通道来做。 |
magick -size 40x80 xc:red xc:lime +append \
-blur 0x20 blur_sRGB.png
![[IM Output]](../static/img/color_basics/blur_sRGB.png)
如果你观察结果,会发现颜色看起来像是从红色经由黑色再到绿色地模糊过去。这是因为在 sRGB 色彩空间中,这些值在我们眼中显得比实际应有的更暗。 这里我再次模糊同一幅图像,但使用线性 RGB 色彩空间。 |
magick -size 40x80 xc:red xc:lime +append \
-colorspace RGB -blur 0x20 -colorspace sRGB blur_RGB.png
![[IM Output]](../static/img/color_basics/blur_RGB.png)
正如你所见,这次我们得到了更合理得多的结果,红色和绿色经由橙色模糊过渡。使用其他线性色彩空间(如 LAB 或 LUV)你也会得到类似结果,我们将在下面更详细地讨论它们。基本上,当处理涉及颜色混合的图像时,例如在颜色量化(颜色削减)之类的操作中,以及在图像缩放和更普遍的图像扭曲中,你都应该在线性色彩空间中处理图像以获得更准确的结果,尽管实际上很少有人这么做。 | _Helmut Dersch(以桶形畸变与镜头校正著称)建议你应考虑使用线性 'LAB' 色彩空间来处理图像,尤其是缩放和图像扭曲。
我只建议在对图像进行绘制、合成、缩放或扭曲时,从“输入”sRGB 色彩空间转移到其他某种“线性”色彩空间。无论是线性 RGB、LAB 还是 LUV,应该都关系不大。
_
---|---
例如,下面是在 3 种主要线性色彩空间中的红蓝模糊。我选择这些颜色,是因为它们在生成的中间颜色上似乎显示出最大差异。
for colorspace in RGB LUV LAB
do
magick -size 80x40 xc:red xc:blue -append \
-colorspace $colorspace -blur 0x30 -colorspace sRGB \
colorspace_$colorspace.png
done
关于按色彩空间处理图像的更多示例,请参见带色彩空间校正的缩放。另外请参见关于颜色名称以及在线性色彩空间中绘制的警告,见带伽马与色彩空间校正的绘制
颜色指定
IM 中的颜色可以用许多方式来指定。关于这方面最好的指南在 IM 官方网站上 Color Names。
按名称指定颜色
许多颜色都被赋予了特定名称,这使得它们更易于使用。例如 "RoyalBlue" 是一种非常漂亮的明亮偏蓝色。
右侧是一幅图像,包含 ImageMagick 中可用的所有命名颜色,包括带数字的那些。这些颜色首先被分为 3 组:偏白色、中间调和暗色,然后绘制在三个独立的 HSL 色相环上,每个具有不同的垂直偏移。纯白和纯黑颜色作为各自独立的点出现在图表的最顶端和最底端,构成垂直范围的两个极端。生成它的脚本是 "[hsl_named_colors](../static/img/scripts/hsl_named_colors)",它遵循了在分层图像的程序化定位中讨论的一种技术。 | _从技术上讲,由于我把 HSL 颜色绘制成三维的“双锥”形而非“圆柱”形,每个颜色点的半径被设为等于该颜色的“Chroma(彩度)”(“饱和度”/“明度”),而不只是其“饱和度”。参见Wikipeadia: HSL and HSV。
要更正确的话,还应使用六角锥体而非圆锥,不过那计算起来要难得多,收获却很少。
_
---|---
正如你所见,红到黄之间有大量颜色名称,而在青到绿色相之间有一个较小的组。在偏白的黄色和青色中也有类似的集群。但偏绿颜色的命名几乎没有。本质上,HSL 色彩空间中有些区域的命名颜色非常少。要找到一个可用的特定命名颜色可能很困难。但是通过把右侧图像加载到 IM 的 "[display](basics.html#display)" 程序中,你可以用鼠标中键查看所绘制的特定颜色的 ImageMagick 颜色名称。
特殊颜色名称
有几个特殊颜色,在 ImageMagick 中用于特殊用途。'None' 或 'Transparent' 是一种完全透明的黑色,通常用于指定背景透明度,例如在创建纯色画布,或使用图像层时。'Opaque' 只是 'Black' 的别名,因此很少使用。它通常只在你想表示任意不透明颜色时使用,比如在进行 alpha 通道处理时。
颜色名称冲突
颜色名称可以来自三个不同的来源:SVG、X11 和 XPM,而大多数名称无论定义来源如何都产生相同的颜色。但有少数颜色名称会根据所用的颜色规范产生不同的颜色。最大的问题是 SVG 颜色 'Green'(半亮绿色),它与 X11/XPM 颜色 'Green'(纯 RGB 绿色)不同。如果你想要纯绿色,最好使用 SVG 颜色名称 'Lime',它没有冲突。维基百科有一篇关于颜色名称冲突的优秀文章,还有一张实际颜色名称的好表格,见 X11 color names。你可能还想看看文章 Web Colors,它提供了一组排列工整的、涵盖某些颜色范围的表格。最值得注意的冲突在于四种特定颜色。下面是已知颜色名称冲突的表格。记住,SVG 颜色是 IM 默认会使用的。 冲突
颜色名称 | SVG 结果
(IM 默认) | X11 结果
对应名称 | X11 等价
名称 | 替代
颜色名称
---|---|---|---|---
Green | | #008000 | | #00FF00 | | | Lime
Maroon | | #800000 | | #B03060 | | FireBrick |
Purple | | #FF00FF | | #A020F0 | | Magenta |
Gray | | #7E7E7E | | #BEBEBE | | | Grey
关于上述内容的说明……
- X11 的 '
Grey' 是一种视觉上的中灰色。它也非常接近(但不完全相同于)X11 颜色 'Gray74' 和 SVG 颜色 'Silver'('gray(192)')。 - 默认(SVG)的 '
Gray' 非常接近一个完美的数学灰,后者用颜色名称 'Gray50' 或 'gray(128)'(用于 8 位)来指定会更好。 - 由于所有命名颜色都用 8 位(0-255)值指定,它们都无法生成完美的 16 位纯灰色!
- 当需要灰色用于数学处理时,例如 FFT DC 相位、边缘检测、Shade 图像、合成光照效果和相对位移图,你最好使用颜色公式 '
gray(50%)',它在任何颜色位深下都能生成完美的数学中间调灰。
颜色与色彩空间
虽然许多颜色有名称,但图像中遇到的大多数颜色并没有,它们只是一组值,通常是 3 个,用来指定一种特定颜色。然而仅凭三个值本身并不能完全定义一种颜色,你还需要指定这些值所属的“色彩空间”或“颜色系统”。上面所有的“命名”颜色都处于 sRGB 色彩空间中,那是它们被定义时所在的色彩空间。但有时你想在不同的色彩空间中定义颜色。例如在 HSL、CYMK,甚至作为 XYZ 颜色。Imagemagick 可以做到这一点,你可以在 ImageMagick Color Names 中看到这些规范的细节。未来:使用其他色彩空间的示例(仍在开发中) | _虽然 ImageMagick 中的 RGB 表示线性 RGB 色彩空间,但一种公认的做法是,颜色名称 'rgb(value,value,value)' 实际上定义的是 sRGB 颜色。
要真正定义线性 RGB 颜色而非 sRGB 颜色,请使用颜色公式 'icc-color(RGB,value,value,value)'(见下文)。
---|---
自 IM v6.7.8-3 起,你可以使用函数 'icc-color(colorspace,color...)' 来定义颜色,或重新定义某个特定颜色的色彩空间。_未来:使用示例
半透明颜色
你只能用两种不同方式直接指定半透明颜色。设置半透明颜色最常见的方法是使用十六进制值。例如,下面是一些展示不同颜色透明度级别的颜色规范。我把生成的颜色图像显示在背景图案上,以便你能透过图像的透明度看到该图案。
magick -size 50x50 xc:'#00FF00FF' color_hex_1.png
magick -size 50x50 xc:'#00FF00C0' color_hex_2.png
magick -size 50x50 xc:'#00FF0090' color_hex_3.png
magick -size 50x50 xc:'#00FF0060' color_hex_4.png
magick -size 50x50 xc:'#00FF0030' color_hex_5.png
magick -size 50x50 xc:'#00FF0000' color_hex_6.png
| 在 IM v6.3.0 之前,最后一组十六进制数字以“蒙版(matte)”或“不透明度(opacity)”值的形式包含颜色的透明度。也就是说,最后的十六进制 '00' 代表“不透明(opaque)”,而 'FF' 是透明。
然而在 IM v6.3.0 之后,这个值被反转,以表示“alpha”透明度值,使 IM 与 SVG 标准及其他图形软件保持一致。换句话说,'FF' 现在代表完全不透明,'00' 是完全透明。
---|---
你也可以使用特殊的 'rgba()' 颜色函数来指定颜色。其中 RGB 值从 0 到 255,alpha 通道指定为介于 0.0(透明)到 1.0(不透明)之间的小数。
magick -size 50x50 xc:'rgba(255,0,0, 1.0)' color_rgba_1.png
magick -size 50x50 xc:'rgba(255,0,0, 0.8)' color_rgba_2.png
magick -size 50x50 xc:'rgba(255,0,0, 0.6)' color_rgba_3.png
magick -size 50x50 xc:'rgba(255,0,0, 0.4)' color_rgba_4.png
magick -size 50x50 xc:'rgba(255,0,0, 0.2)' color_rgba_5.png
magick -size 50x50 xc:'rgba(255,0,0, 0.0)' color_rgba_6.png
| 在 IM 6.2.7 版之前,'rgba()' 同样对 alpha 通道值使用蒙版(matte)值。也就是说,0 表示完全不透明,255 表示完全透明。根据“W3C CSS3 Color Module 关于指定颜色的建议”,这一点被更改了,这是 IM 变得更符合其他图像标准(尤其是用于 WWW 和 SVG)的一部分。
---|---
目前无法通过名称直接指定带额外 alpha 值设置的半透明颜色。不过你可以通过先生成该命名颜色,再修改图像的透明度来变通实现。你还有一个附加的复杂之处:在你真正能设置颜色透明度之前,你必须设置 alpha 通道。
magick -size 50x50 xc:RoyalBlue color_name_1.png
magick -size 50x50 xc:RoyalBlue -alpha set \
-channel A -evaluate set 80% color_name_2.png
magick -size 50x50 xc:RoyalBlue -alpha set \
-channel A -evaluate set 60% color_name_3.png
magick -size 50x50 xc:RoyalBlue -alpha set \
-channel A -evaluate set 40% color_name_4.png
magick -size 50x50 xc:RoyalBlue -alpha set \
-channel A -evaluate set 20% color_name_5.png
magick -size 50x50 xc:RoyalBlue -alpha set \
-channel A -evaluate set 0 color_name_6.png
是的,这很麻烦,要是能在颜色名称规范中设置透明度就好了。如果你愿意看到这一点,请在 IM 开发者论坛上提出请求。也可以使用 MVG 绘制设置来绘制一个命名的填充颜色,不过你需要一块透明的起始画布才能让它正确工作。例如…… |
magick -size 50x50 xc:none \
-draw "fill Tomato fill-opacity 0.5 rectangle 0,0 49,49" \
color_name_draw.png
| ![[IM Output]](../static/img/color_basics/color_name_draw.png)
| 注意,一个完全透明的颜色虽然完全不可见,仍然具有颜色。然而大多数 IM 操作符都认为任何完全透明的颜色,与任何其他完全透明的颜色相同。正因如此,以及内部数学运算的方式,许多操作符常会用完全透明的黑色(也就是特殊颜色 'none')来替换完全透明的颜色。
---|---
颜色通道
图像的实际颜色数据存储为一组组值的数组,称为通道。通常一幅图像至少有 3 个通道,表示红、绿、蓝颜色值。但正如你上面看到的,所存储的值也可以表示其他色彩空间。
色彩空间与通道命名
"[-colorspace](https://imagemagick.org/command-line-options/#colorspace)" 操作符的主要用途是改变 IM 在内存中存储图像颜色的方式。通常每幅图像有 3(或 4)个图像数据通道。图像当前的“色彩空间”决定了每个通道的数据所代表的含义。现在通常这些通道被命名为 'Red'、'Green'、'Blue',因为那通常是存储在这些通道中的图像数据类型。然而情况并非总是如此。不要把 'R' 或 'Red' 通道想成是红色,而要把它想成是“通道 1”,根据图像的色彩空间,它可能包含 'red'、'hue'、'cyan' 或其他东西的数据。'Red' 只是一个标签,通常用于“红色”或第一个通道。第二常用的色彩空间是 'CMYK',它定义了应涂多少颜色“墨水”来使一张“白”纸变暗(一种减色色彩空间)。注意 K 是 "blacK" 的缩写,它是图像取反后的强度值。由于这很常见,'RGB' 通道也有另一套命名 'Cyan'、'Magenta' 和 'Yellow',或简称字母 'C'、'M' 和 'Y',尽管实际上它们指的是与 'RGB' 图像所用的同一组通道。还会额外添加一个特殊的第四颜色通道,用于 'Black' 或 'K' 颜色通道。这基本上意味着 "Green" 的颜色通道实际上指的与 "Magenta" 所用的完全是同一个颜色通道。数据本身是 '绿色' 还是 '品红色',并不取决于通道的名称,而取决于内存中图像的“色彩空间”。其他色彩空间也是如此。例如使用 'LAB' 色彩空间意味着 'Red' 通道包含 'Lightness(明度)' 值,而 'Green' 通道保存 'A'(即红-绿)值,'Blue' 通道保存 'B'(即蓝-黄)值。
类似地,通道名称 'Alpha'('A')、'Opacity'('O')和 'Matte',都是 "[-channel](https://imagemagick.org/command-line-options/#channel)" 设置中指代图像透明度信息的别名。'alpha' 通道是 'matte' 通道的反相并不重要,它仍然指代同一个通道,并产生同样的结果,即图像的内部 matte 通道。操作符是把内部 alpha 通道数据当作 'alpha' 还是值来处理,取决于该操作符。诸如 "[-threshold](https://imagemagick.org/command-line-options/#threshold)" 之类的低级通道操作符在内存中作用于通道的原始 'matte' 数据。然而大多数高级操作符,如 "[-fx](https://imagemagick.org/command-line-options/#fx)" 和 "[-composite](https://imagemagick.org/command-line-options/#composite)",出于操作目的会把那数据当作表示 'alpha' 数据。还有另一种控制所存储图像数据色彩空间的方法。"[-set](https://imagemagick.org/command-line-options/#set) colorspace"(IM v6.4.3-7 添加)将只改变内存中的“色彩空间”设置。也就是说,它可以把一幅 RGB 图像转换为 HSL 图像,但不改变或修改图像所使用的实际像素数据。它最典型的用途是当你手动合并通道数据时,用来设置合并后图像的最终色彩空间。
那么让我们看看如何操作颜色通道。记住每个通道只是一个值数组。所有通道随后组合在一起,表示图像中每个像素的实际颜色。
分离通道图像
分离各个颜色通道最简单的方法是使用 "[-separate](https://imagemagick.org/command-line-options/#separate)" 操作符,把每个通道的当前内容提取为一幅灰度图像。
magick rose: -channel R -separate separate_red.gif
magick rose: -channel G -separate separate_green.gif
magick rose: -channel B -separate separate_blue.gif
| 注意红色玫瑰在红色通道图像中很突出,而在蓝色和绿色通道中相当暗。另一方面,绿色叶子在绿色通道中突出,而在其他通道中则不然。图像底部附近的白色在所有通道中都很亮。 | 在 IM v5 及之前,"-channel" 不仅是后续图像操作的一个设置,有时还是一个“图像操作符”,把指定通道转换为一幅灰度图像。非常令人困惑! IM v6 创建了 "-separate",用以“分离”这两个截然不同的任务。"-channel" 选项只是一个供后续图像操作使用的设置,而 "-separate" 会把指定通道提取为独立的、完全不透明的灰度图像。 |
|---|---|
自 IM v6.2.9-3 起,"-separate" 操作符允许你根据 "-channel" 设置分离多个颜色通道。"-channel" 设置中项目的数量决定了所创建图像的数量(按 RGBA 顺序)。例如,由于默认的 "-channel" 设置是 'RGB',默认动作是创建三幅图像,我把它们输出在下面。 |
magick rose: -separate separate_RGB_%d.gif
这里我们使用 "-colorspace" 操作符把 IM 存储图像颜色数据的方式转换为 CMYK 颜色表示。然后我们提取所涉及的四个颜色通道。
magick rose: -colorspace CMYK -separate separate_CMYK_%d.gif
最后一幅图像('Black' 或 'K' 通道)特别有趣,因为它看上去像是原图的一幅取反灰度图像。实际上它代表 CMYK 打印机应在纸上沉积的“墨水”量,减少其他颜色通道所需的颜色量。注意默认情况下 "-channel" 设置不包含图像的特殊 Matte 透明度通道。如果你想总是生成所有存在的通道,可以使用 "-channel ALL" 通道设置,或使用 'RGBA' 或 'CMYKA' "-channel" 设置。
从色彩空间表示得到灰度通道
你可以为特殊用途从色彩空间中提取特定的通道值。例如,这里我们用若干不同的表示方式,从玫瑰图像中提取图像的灰度亮度或强度。
magick rose: -colorspace Gray channel_gray.gif
magick rose: -grayscale Rec709Luma channel_luma709.gif
magick rose: -grayscale Rec601Luma channel_luma601.gif
magick rose: -colorspace HSI -channel B -separate channel_average.gif
magick rose: -colorspace HSL -channel B -separate channel_lightness.gif
magick rose: -colorspace HSB -channel B -separate channel_brilliance.gif
magick rose: -colorspace CMYK -channel K -negate -separate channel_black.gif
magick rose: -colorspace LAB -channel R -separate channel_lab_light.gif
![[IM Output]](../static/img/color_basics/channel_gray.gif)
Gray
Gray | ![[IM Output]](../static/img/color_basics/channel_luma709.gif)
Rec709Luma
| ![[IM Output]](../static/img/color_basics/channel_luma601.gif)
Rec601Luma (Y)
YUV/YIQ | ![[IM Output]](../static/img/color_basics/channel_average.gif)
Average (I)
HSI/OHTA | ![[IM Output]](../static/img/color_basics/channel_lightness.gif)
Lightness
HSL | ![[IM Output]](../static/img/color_basics/channel_brilliance.gif)
Brightness
HSB | ![[IM Output]](../static/img/color_basics/channel_black.gif)
Neg Black
CMYK | ![[IM Output]](../static/img/color_basics/channel_luma709.gif)
Luminance*
LAB / LUV
---|---|---|---|---|---|---|---
关于实际公式,请参见 "[-colorspace](https://imagemagick.org/command-line-options/#colorspace)" 选项的官方参考。注意,自 IM v6.7.7 起,灰度图像在内存中以及保存时都不带伽马或 sRGB 修改地存储。因此它们往往比此版本之前更暗。注意 'Gray'(也称为 'Intensity' 或更确切地说 'Luminance')与 YUV 色彩空间的 'Luma' 是等价的。类似地,HSB 色彩空间的 'Brightness' 与 CMYK 色彩空间取反后的 'blacK' 通道是等价的(且对于灰度用途通常过亮)。注意 LAB(以及 LUV)色彩空间的 'Lightness' 通道(不要与 HSL 的 'Lightness' 混淆)被认为最接近人类视觉感知,尽管它并不常用于生成灰度图像。注意,若给定一幅灰度图像,所有色彩空间灰度图像都会产生与输入灰度图像完全相同的图像,唯一例外是 LAB / LUV 色彩空间的 'Lightness'('R')通道图像。
其他通道分离方法
一种方法是把某一个通道复制到所有其他通道,以生成一幅灰度图像,正如Separate 操作符所生成的那样。一个简单但慢的方法是使用 FX 自制操作符。
magick rose: -fx R channel_red.gif
magick rose: -fx G channel_green.gif
magick rose: -fx B channel_blue.gif
这常被视为最“简单”、最易理解的方案,已在其他 IM 教程中使用。其他方法涉及使用多种技术来“清零”不想要的通道。这些方法列在下面的清零颜色通道中,且通常比使用 "[-fx](https://imagemagick.org/command-line-options/#fx)" 快得多。
合并 RGB 通道图像
一旦你分离出所有图像颜色通道并对它们进行了处理,你还需要能够把这些图像重新组合在一起。这可以使用特殊的列表操作符 "[-combine](https://imagemagick.org/command-line-options/#combine)" 来完成,它基本上正是 "-separate" 的逆操作。
magick separate_red.gif separate_green.gif separate_blue.gif \
-combine -set colorspace sRGB rose_combined.gif
这些随后 "[-combine](https://imagemagick.org/command-line-options/#combine)" 创建出一幅被声明为 sRGB 色彩空间的图像。一位用户想要能够交换图像的红、蓝通道,这做起来很简单:分离通道、交换、再重新合并。 |
magick rose: -separate -swap 0,2 -combine rose_rb_swap.gif
![[IM Output]](../static/img/color_basics/rose_rb_swap.gif)
记住,默认的 "[-channel](https://imagemagick.org/command-line-options/#channel)" 设置是 'RGB',它定义了哪些图像作为通道图像被组合在一起。如果不是所有被组合在一起的通道都已定义,其他通道会用当前 "-background" 设置中的颜色值来设置。不过你应该注意,"[-combine](https://imagemagick.org/command-line-options/#combine)" 和 "-separate" 都会忽略 "[-channel](https://imagemagick.org/command-line-options/#channel)" 定义通道的顺序。对于 "[-channel](https://imagemagick.org/command-line-options/#channel)" 设置中设定的每个通道集,通道总是按标准的 'Red,Green,Blue,Matte' 通道顺序被处理和生成。因此,即使你使用 "-channel BR" 设置或仅 "blue,red","-combine" 操作符仍然会期望这两幅图像先是红色再是蓝色。绿色和 alpha 值(如果图像有透明度)将根据当前 "-background" 设置值来设定。例如……
magick separate_red.gif separate_blue.gif -background black \
-channel blue,red -combine rose_red_blue.gif
合并非 RGB 通道图像
自 IM v6.4.3-7 起,你也可以 "[-combine](https://imagemagick.org/command-line-options/#combine)" 表示其他色彩空间的通道图像,但你需要告诉 IM 结果图像应当处于什么色彩空间。这通过使用特殊的 "[-set](https://imagemagick.org/command-line-options/#set) colorspace" 操作符来完成。它基本上会改变内存中图像的色彩空间,但不映射图像的像素数据,使其保持原样。一旦图像在正确的色彩空间中被合并,你就可以使用普通的 "[-colorspace](https://imagemagick.org/command-line-options/#colorspace)" 操作符把像素数据映射回正常的 RGB 数据。 |
magick separate_HSB_?.gif -set colorspace HSB -combine \
-colorspace sRGB rose_HSB_combined.gif
![[IM Output]](../static/img/color_basics/rose_HSB_combined.gif)
此方法对 CMYK 图像也适用,由于需要第四个颜色通道,CMYK 图像通常很难处理。 |
magick separate_CMYK_?.gif -set colorspace CMYK -combine \
-colorspace sRGB rose_CMYK_combined.gif
![[IM Output]](../static/img/color_basics/rose_CMYK_combined.gif)
一种替代的变通方法(用于较旧版本的 IM)是加载一幅图像(红色通道)并改变它,使其处于正确的色彩空间中。之后,每个单独的通道图像都可以被加载并通道复制到那幅预先准备好的图像中。 |
magick separate_HSB_0.gif -colorspace HSB \
separate_HSB_0.gif -compose CopyRed -composite \
separate_HSB_1.gif -compose CopyGreen -composite \
separate_HSB_2.gif -compose CopyBlue -composite \
-colorspace sRGB rose_HSB_combined_alt.gif
![[IM Output]](../static/img/color_basics/rose_HSB_combined_alt.gif)
当然,如果你使用 "[-set](https://imagemagick.org/command-line-options/#set) colorspace" 操作,第一个通道的数据将已经就位,因为这并不会改变实际的像素数据,只改变数据被解读的方式。 | 最后一个示例对 'CMYK' 图像不起作用,因为 'Black' 通道图像实际上并不包含一个黑色通道!因此 "-compose CopyBlack" 将找不到有效数据可复制。我视其为一个 bug,但目前不太可能被修复。
---|---
使用其他色彩空间可能很有用。例如,这里我取内置的玫瑰图像,想在 'Lab' 色彩空间中对图像的亮度通道取反。完成后我重新合并以再次构建一幅 sRGB 图像。 |
magick rose: -colorspace Lab -separate \
\( -clone 0 -negate \) -swap 0 +delete \
-combine -set colorspace Lab \
-colorspace sRGB rose_light_neg.gif
![[IM Output]](../static/img/color_basics/rose_light_neg.gif)
| _此前这个示例使用的是 'HSL' 色彩空间,但那是一个线性色彩空间,而我们想在 'Lab' 所提供的“感知色彩空间”中取反。
_
---|---
注意图像仍具有相同的颜色,但颜色的亮度(明度)被反转了,产生一种怪异的效果。你可以把 "-negate" 替换成你自己的一组操作来调整图像的亮度级别。然而由于 "-negate" 本身就是一个受通道控制的操作符,我们不必为了取反而分离出亮度通道。 |
magick rose: -colorspace Lab \
-channel R -negate +channel \
-colorspace sRGB rose_light_neg2.gif
![[IM Output]](../static/img/color_basics/rose_light_neg2.gif)
正如你所见,这简化了操作,但对于你想要达成的效果,它未必总是实用。
清零颜色通道
有时你有一幅图像(RGB 或某种其他色彩空间),你只想清除或“清零”其中一两个颜色通道,而把所有其他通道保持原样。例如,要在不使用 RGB 灰度化技术的情况下生成一幅灰度图像,你可以在 HSL 色彩空间中“清零”饱和度通道('G'),以制作一幅灰度图像。当饱和度为零时,'Hue(色相)' 值没有意义,于是你就得到一幅灰度图像。最直接的技术,往往是使用 Evaluate 操作符把不想要的通道中所有值清零…… |
magick rose: -colorspace HSL \
-channel G -evaluate set 0 +channel \
-colorspace sRGB rose_grey.gif
# Evaluate (fast and direct)
-channel G -evaluate set 0 +channel
# FX zeroing (direct simple, but slow)
-channel G -fx 0 +channel
# Separate the channels you want to keep,
# then combine using a background color to set the other channels
-channel RB -separate -background black -combine +channel
# Gamma which is a miss-use of the operator, but works VERY well!
# ( 1 = leave alone; 0 = zero channel; -1 = maximize channel )
# This is short, simple , needs no channel setting, but very obtuse!
-gamma 1,0,1
# Threshold channels to zero
-channel G -threshold 101% +channel
# Threshold to maximum value then negate to zero
-channel G -threshold -1 -negate +channel
# Multiply with an appropriate primary/secondary color
# The color specifies the channels to preserve! 'magenta' = 'red'+'blue'
\( +clone +level-colors magenta \) -compose multiply -composite
# Colorize specific channels to black
# (0 = leave alone; 100% set from fill (black) )
-fill black -colorize 0,100%,0
你能想到上面没有列出的另一些清零(或最大化)颜色通道的方法吗?——给我发邮件
色彩空间
到目前为止,我们一直集中于 'sRGB'、'RGB' 和 'CMYK' 色彩空间。这是因为它们是通常用于显示、印刷以及图像在文件中传统存储的色彩空间。但虽然这些色彩空间很实用,它们并不代表我们人类实际观察世界的方式。我们的眼睛或许以红、绿、蓝波长看东西,但我们的大脑把它们解读为:颜色色相(是什么颜色)、灰度(有多鲜艳)和强度(多亮/多暗)。正因如此,许多色彩空间和颜色系统被开发出来,往往出于完全独立的需求。例如画家发展出一套颜色系统(基于诸如青金石之类的颜色源)、色度和着色。后来使用 RGB 的计算机系统,需要更好的方式让用户选择或修改颜色,而又不至于计算量太大。
基于色相的色彩空间
也许最著名的替代方案之一是基于循环色相的系统,它是作为 RGB 颜色的颜色选择界面而开发的。基本上,RGB 颜色立方体在三维中被旋转,使得立方体的黑-灰-白对角轴成为该色彩空间的一个轴。它指定了颜色有多暗或多亮。这一变化的关键特征在于,从 RGB 值出发的一种简单转换,把原色围绕这个轴等距分布,从而形成一个从红经绿、再经蓝、又回到红的循环色相。颜色离该轴有多远(径向)被称为饱和度或彩度。
例如,让我们把内置的 'rose:' 图像变换为 'HSB'(色相 Hue、饱和度 Saturation、亮度 Brilliance,也称为 HSV,其中 V 代表 Value)色彩空间后,分离它的各通道。
magick rose: -colorspace HSB -separate separate_HSB_%d.gif
或者类似但不完全相同的 'HSL'(色相 Hue、饱和度 Saturation、明度 Lightness)。
magick rose: -colorspace HSL -separate separate_HSL_%d.gif
注意两种色彩空间中的“Hue(色相)”通道图像都是几乎纯黑与纯白颜色的同样斑驳图样。这是因为色相实际上是循环的。也就是说,上面通道图像中的黑色和白色实际上都是“红”色相的表示,而轻微的变化会使色相从红色的一侧(产生白色)翻转到另一侧(产生黑色)。如果这是个问题,你可以使用 Modulate 操作符旋转色相设置,使红色由某个其他色相值来表示。'HSL' 与 'HSB' 之间真正的区别在于原色被定义得有多亮。但要看清这一点,我们最好观察该色彩空间更实用的表示——使用色相环。如果你观察上面分离中最后那些“亮度/明度”图像,你会看到 'HSB' 把一个强(接近原色)的“红”色当作几乎白色处理,而 'HSL' 把它当作更像中间调灰强度来处理。
生成 HSL 色相环
上面对图像颜色的原始分离仍然很难理解。为了更好地理解色彩空间,我们需要试着把它可视化。色彩空间更常被表示为一个圆形极坐标渐变,展示该色彩空间的某一部分。你可以生成各个分离的通道值图像,并合并它们,以生成用其他方式很难生成的特定类型图像。例如,这里我们生成一个完美的 'HSL' 色相环。
magick -size 100x300 gradient: -rotate 90 \
-distort Arc '360 -90.1 50' +repage \
-gravity center -crop 100x100+0+0 +repage angular.png
magick -size 100x100 xc:white solid.png
magick -size 100x100 radial-gradient: -negate radial.png
magick angular.png solid.png radial.png \
-combine -set colorspace HSL \
-colorspace sRGB colorwheel_HSL.png
![[IM Output]](../static/img/color_basics/angular.png)
Hue | ![[IM Output]](../static/img/color_basics/solid.png)
Saturation | ![[IM Output]](../static/img/color_basics/radial.png)
Luminance | | ![[IM Output]](../static/img/color_basics/colorwheel_HSL.png)
HSL 色相环
---|---|---|---|---
| _这些灰度图像是用 sRGB 值生成的线性渐变。因此这些渐变往往看起来比应有的更暗。然而这里重要的是输入图像中的值,而非观看时的色彩空间。
另一方面,所得图像虽在线性 RGB 色彩空间中生成,却被保存为 sRGB 色彩空间,以确保浏览器和其他图像显示程序以视觉上效果良好的方式显示该渐变。_
---|---
还要注意,色相是一个“模数”值,它在红色处(色相值 = 0)回绕。这在做图像处理时可能令人头疼,因为你有两种视觉上完全相同的红色,但在数值上却相距最大的色相距离。处理颜色差异时,这不是一个适合使用的色彩空间。实际上,HSB 和 HSL 色彩空间的明度/亮度通道并不太有用,因为各种色相并未被同等对待。基本上,它“均衡了”原色的强度。例如,把“黄”色相旋转成“蓝”色相会使非常亮的颜色变得非常暗,反之亦然。更多细节请参见 HSL Disadvantages。建议谨慎。
还有许多色彩空间也使用这种基于“六角锥”的色相系统。HSB、HCL 和 HCLp(感知 HCL)。这里是所有这四种“六角锥”色彩空间的色相环。
magick angular.png solid.png radial.png \
-combine -set colorspace HSL \
-colorspace sRGB colorwheel_HSL.png
magick angular.png solid.png radial.png \
-combine -set colorspace HSB \
-colorspace sRGB colorwheel_HSB.png
magick angular.png solid.png radial.png \
-combine -set colorspace HCL \
-colorspace sRGB colorwheel_HCL.png
magick angular.png solid.png radial.png \
-combine -set colorspace HCLp \
-colorspace sRGB colorwheel_HCLp.png
![[IM Output]](../static/img/color_basics/colorwheel_HSL.png)
HSL | ![[IM Output]](../static/img/color_basics/colorwheel_HSB.png)
HSB | ![[IM Output]](../static/img/color_basics/colorwheel_HCL.png)
HCL | ![[IM Output]](../static/img/color_basics/colorwheel_HCLp.png)
HCLp
---|---|---|---
记住,上面显示的所有颜色都是在最大颜色饱和度下生成的。然而 'HSB' 色彩空间会在最大明度下产生原色(HSL 则在半强度下生成这些颜色)。因此只有当饱和度为零时才能生成白色。结果是,边缘周围不是一圈白色区域,而是得到完全饱和的颜色。'HCL' 色彩空间使用同样的“六角锥”色相计算,但它调整“明度”通道,以使用颜色强度,而非直接的线性 RGB 值。结果是,当使用 'HCL' 时,原色位于不同的强度级别,蓝色更靠近中央的黑色,而红色则亮得多、更靠外。'HCL' 色彩空间的 50% 强度区域不会产生浓烈的颜色,而是生成更自然的粉彩色。例如,这里比较了 HSL 和 HCL 色彩空间在 50% 强度下饱和色相之间的差异。
magick -size 100x100 xc:black \
-fill white -draw 'circle 49.5,49.5 40,4' \
-fill black -draw 'circle 49.5,49.5 40,30' \
-alpha copy -channel A -morphology dilate diamond anulus.png
magick hue_angular.png -size 100x100 xc:white xc:gray50 \
-combine -set colorspace HSL -colorspace RGB \
anulus.png -alpha off -compose Multiply -composite \
anulus.png -alpha on -compose DstIn -composite \
-colorspace sRGB hues_HSL.png
magick hue_angular.png -size 100x100 xc:white xc:gray50 \
-combine -set colorspace HCL -colorspace RGB \
anulus.png -alpha off -compose Multiply -composite \
anulus.png -alpha on -compose DstIn -composite \
-colorspace sRGB hues_HCL.png
这并不是说 'HCL' 不含纯色,只是它们不像在 'HSL' 色彩空间中那样被“强行”压入一个共同平面。特别要注意,HCL 中所有色度都具有相同的 50% 强度(如所请求的),不像 HSL 色彩空间色相的结果那样。绿色大概是所有主要颜色中最接近 50% 强度的,因此在 50% 色相中响应良好。建议你使用这个色彩空间进行色相旋转,以保持图像中所有颜色的总体亮度。参见在 HCL 色彩空间中 Modulate 中的示例。HWB 色彩空间 ???
感知色彩空间
'Lab' 和 'Luv' 色彩空间的设计目的,是使它们完全把灰度强度与图像的颜色分量分离开来。这与 'RGB' 和 'sRGB' 色彩空间不同。一旦你掌握了窍门,这使得该色彩空间总体上更易于处理和修改。更具体地说,'Luv' 被设计为“感知线性”的。也就是说,色彩空间中某一部分颜色的小变化,看起来与另一部分色彩空间中类似的变化大致相同。这使得 Luv 色彩空间更适合用于图像差异比较。这两个色彩空间非常相似,处理图像时通常产生相似的结果。这里我们分离 'Lab' 和 'Luv' 色彩空间的通道,只是为了展示这两个色彩空间实际上有多么相似。
magick rose: \( -clone 0 -colorspace LAB -separate +append \) \
\( -clone 0 -colorspace LUV -separate +append \) \
-delete 0 -append -set colorspace sRGB separate_lab_luv.png
Luv
---|---|---|---
'Lab' 和 'Luv' 色彩空间更好的其他示例,可以通过其圆柱形的 'LCHab' 'LCHvu' 变体看到,见下面的 LCH 色相环。关于使用这些色彩空间的实际示例,请参见在 Lab 色彩空间中缩放。
基于 Lab 和 Luv 的色彩空间
'HCL' 色彩空间基于 'LCHuv' 色彩空间,后者是 'Luv' 色彩空间的圆柱形表示,不过明度通道采用了更简单的公式,以便在最大明度处生成纯白。为完整起见,这里是 'Lab' 和 'Luv' 色彩空间的圆柱形表示,分别称为 'LCHab' 和 'LCHuv'。但请注意,通道的顺序与上面所示的等价 'HCL' 色彩空间相反。
magick radial.png solid.png angular.png \
-combine -set colorspace LCHab \
-colorspace sRGB colorwheel_LCHab.png
magick radial.png solid.png angular.png \
-combine -set colorspace LCHuv \
-colorspace sRGB colorwheel_LCHuv.png
![[IM Output]](../static/img/color_basics/radial.png)
Lightness* | ![[IM Output]](../static/img/color_basics/solid.png)
Chroma | ![[IM Output]](../static/img/color_basics/angular.png)
Hue | | ![[IM Output]](../static/img/color_basics/colorwheel_LCHab.png)
LCHab | ![[IM Output]](../static/img/color_basics/colorwheel_LCHuv.png)
LCHuv
---|---|---|---|---|---
注意 'LCH' 色彩空间是 'LCHab' 的别名。在上图中你可以看到 'LCHuv' 有一处不连续,那里通过色相环过程设置了不真实的颜色。图像的正常转换不会生成这些颜色。
scRGB 高动态范围色彩空间
Wikiepedia: http://en.wikipedia.org/wiki/ScRGB
This is essentially a method of storing a High dynamic range color
(with negatives and up to 10 times linear RGB range) in a 16 bit integer,
with only 1/2 the color resolution of a normal 16-bit sRGB image.
As it is using 16bit integers it can be stored in image files formats that can
save such images (PNG, PPM, MIFF), though a color profile, or some other
method should be used to mark those images as holding scRGB colorspace data.
You would have to be very careful, with many image processing operators in
this colorspace as it has an 'offset' to allow it to handle negative numbers.
And while some operators like resize and distort can be used directly on this
colorspace, it is probably a better idea to use a HDRI version of ImageMagick,
and magick to linear RGB (with negatives), for more general image processing.
_Examples and more information on using this colorspace would be good_
替换图像中的颜色
ImageMagick 自然提供了若干选项,用另一种颜色替换某种特定颜色及与之相近的颜色。在处理图标和包含极少颜色的“位图”类图像时,这非常好用,但在处理包含颜色色度或带抗锯齿边缘像素的图像时往往会失败。基本上,你需要记住颜色是用单一色度替换的。所以如果你替换一组或一片邻近的颜色,所有这些颜色都会被一种特定的单一颜色替换,而不是被一个匹配的颜色范围替换。这并不是说做带色度的颜色替换不可能,只是目前若不下大功夫就做不到简单实现。即便如此,GIF 图像不允许使用半透明,所以以这种方式替换颜色是控制 GIF 背景透明度的好方法(示例参见 背景图案上的 GIF)另一方面是,虽然你可以使用预定义颜色映射把所有“相近颜色”映射到给定的颜色映射,但没有操作符能把一大组颜色直接一对一映射到另一组完全不同的颜色。这是一个不足,可能在未来版本的 IM 中改变。在记住这个告诫的前提下,让我们看看 IM 确实提供的、用另一种颜色直接替换某一特定颜色的方式。
替换特定颜色
"[-opaque](https://imagemagick.org/command-line-options/#opaque)" 和 "[-transparent](https://imagemagick.org/command-line-options/#transparent)" 操作符旨在用另一种颜色替换图像中的某种颜色。例如,要把 'blue' 颜色替换成比如 'white',你会使用这样的命令…… |
magick balloon.gif -fill white -opaque blue balloon_white.gif
![[IM Output]](../static/img/color_basics/balloon_white.gif)
基本上,任何是 'blue' 的颜色都被替换成了当前的 "[-fill](https://imagemagick.org/command-line-options/#fill)" 颜色。然而自 IM v6.2.7 起,此操作符受 "[-channel](https://imagemagick.org/command-line-options/#channel)" 设置限制。因此,要把一种颜色(比如蓝色)转换为透明,你需要指定一个包含 alpha 通道的 "[-channel](https://imagemagick.org/command-line-options/#channel)" 以使颜色透明。你还需要确保图像已启用 'matte' 或 alpha 通道,以保存透明度信息。 |
magick balloon.gif -alpha set -channel RGBA \
-fill none -opaque blue balloon_none.gif
![[IM Output]](../static/img/color_basics/balloon_none.gif)
由于用透明替换某种颜色是一个如此常见的操作,上述操作有其专属的“替换为透明”操作符 "[-transparent](https://imagemagick.org/command-line-options/#transparent)"。 |
magick balloon.gif -transparent blue balloon_trans.gif
![[IM Output]](../static/img/color_basics/balloon_trans.gif)
自 IM 6.3.7-10 版起,这些操作符的“加号”版本会反转颜色选择。也就是说,与给定颜色不匹配的颜色将被替换。例如,这里我把任何不是纯黑的颜色替换成白色,只留下图像的纯黑边框。 |
magick balloon.gif -fill white +opaque black balloon_borders.gif
![[IM Output]](../static/img/color_basics/balloon_borders.gif)
这看起来可能没什么了不起,但当你把它与 Fuzz 因子(见下文)结合时,它就成了一个非常强大的工具。 | 在 IM v6.3.7-10 之前,反向操作需要使用图像蒙版的一些小技巧。基本上,你把想要保留的颜色替换为透明,然后把所有其他颜色 "[-colorize](https://imagemagick.org/command-line-options/#colorize)" 成想要的颜色,以创建一个叠加蒙版。然后把它叠加到原图上,以“遮蔽掉”不匹配的颜色! | |
magick balloon.gif \
\( +clone -alpha set -transparent black \
-fill white -colorize 100% \) \
-composite balloon_mask_non-black.gif
![[IM Output]](../static/img/color_basics/balloon_mask_non-black.gif)
正如你所见,该操作符的“加号”形式极大地简化了“非此颜色”的替换操作。
关于更高级的替换技术,我建议你看看背景去除。 | _请注意,由于所有匹配的颜色(尤其是“模糊匹配的颜色”,见下文)都被替换为单一统一的颜色,你将不会得到任何彩色区域边缘的抗锯齿。而且你会失去可能存在的任何阴影或其他着色效果。这会对任何非简单、非卡通式图像的外观产生严重的不良影响。
这类颜色替换并不是为实际真实世界图像设计的,而更多用于图像遮罩效果。建议谨慎。_
---|---
"[-opaque](https://imagemagick.org/command-line-options/#opaque)" 颜色替换无法用平铺图案替换颜色。它只会用另一种单一的特定颜色替换颜色。然而 "[-draw](https://imagemagick.org/command-line-options/#draw)" 和 "[-floodfill](https://imagemagick.org/command-line-options/#floodfill)" 这两种颜色替换方法都可以(见下文)。
用图像中的某种颜色替换
你还可以使用绘制颜色替换,根据图像本身中存在的颜色而非某种特定颜色,来给图像重新上色。 |
magick present.gif -fill red -draw 'color 0,0 replace' present_blue.gif
![[IM Output]](../static/img/color_basics/present_blue.gif)
注意我从未指定要替换的颜色,只指定了要替换颜色的位置。正是该位置上的颜色被用于“匹配”要填充哪些区域,无论那是什么颜色。你可以在上面的示例中看到颜色替换的问题:那种特定颜色可能出现在你预期之外的其他地方,导致上面的 'present' 图像中出现了一行红色像素。透明也不构成问题,尽管图像的某些内部部分也变成了透明,正如它们在上面变成红色那样…… |
magick present.gif -alpha set -fill none \
-draw 'color 0,0 replace' present_none.gif
![[IM Output]](../static/img/color_basics/present_none.gif)
但请注意,与 "[-opaque](https://imagemagick.org/command-line-options/#opaque)" 和 "[-transparent](https://imagemagick.org/command-line-options/#transparent)" 不同,绘制颜色替换不允许你反转要替换的“匹配颜色”。绘制还有一种特殊的 Matte 替换,其中只替换填充颜色的透明度。也就是说,你可以让所有匹配的颜色变得透明或半透明,而实际上不改变像素本身的颜色。当然要用合适的文件格式。 |
magick present.gif -alpha set -fill '#00000080' \
-draw 'matte 0,0 replace' present_semi.png
![[IM Output]](../static/img/color_basics/present_semi.png)
当同时指定了 Fuzz 因子 时,这会变得更有用。使用 "[-draw](https://imagemagick.org/command-line-options/#draw)" 最大的优势在于你还可以用平铺图案替换颜色。例如…… |
magick present.gif -tile pattern:right30 \
-draw 'color 0,0 replace' present_tile.gif
![[IM Output]](../static/img/color_basics/present_tile.gif)
关于更高级的替换技术,我建议你看看背景去除。
Floodfill 绘制
绘制颜色方法还为你提供了一种通过“漫水填充(floodfilling)”替换颜色的简单方法。也就是说,与其替换图像内所有匹配的颜色,你可以只选取那些与图像中指定点“相连”或“连接”的颜色。指定的点不仅会指定起始点(种子点),还会指定你试图替换的颜色。 |
magick present.gif -fill red -draw 'color 0,0 floodfill' present_fill.gif
![[IM Output]](../static/img/color_basics/present_fill.gif)
注意那些没有“连接”到 0,0 像素的红色区域没有被替换。对于背景替换来说这可能是个问题,但解决办法同样简单。把图像稍微扩大一些,使漫水填充能从各个方向“渗入”图像,完成后再去除那些额外的空间。 |
magick present.gif -bordercolor white -border 1x1 \
-fill red -draw 'color 0,0 floodfill' \
-shave 1x1 present_bgnd.gif
![[IM Output]](../static/img/color_basics/present_bgnd.gif)
当然,你可以使用下面的 Fuzz 因子控制设置来调整哪些颜色被“匹配”,这对于 JPEG 图像尤为重要。
Floodfill 操作符
添加 "[-floodfill](https://imagemagick.org/command-line-options/#floodfill)" 操作符是为了让漫水填充稍微容易一些,尤其当你想精确指定你具体想要替换的颜色时。在使用 Fuzz 因子颜色匹配时,这可能尤其重要。然而请注意,如果那个种子点不在你所寻找颜色的 Fuzz 因子匹配范围内,那么 "[-floodfill](https://imagemagick.org/command-line-options/#floodfill)" 什么也不做。这既可视为该操作符的特性,也可视为其祸根。
漫水填充时推荐使用小的 Fuzz 因子。
或确保种子点与所寻找的颜色精确匹配。
例如,添加一个已知颜色的边框,以便从边缘漫水填充…… |
magick present.gif -bordercolor white -border 1x1 \
-fill red -floodfill +0+0 white \
-shave 1x1 present_floodfill.gif
![[IM Output]](../static/img/color_basics/present_floodfill.gif)
这会把任何直接属于种子像素周围区域、从 +0+0 开始、且为 'white' 的颜色替换为 'red',由于添加了边框,该处保证为 'white'。你也可以用平铺图案漫水填充。 |
magick present.gif -bordercolor white -border 1x1 \
-tile pattern:left30 -floodfill +0+0 white \
-shave 1x1 present_pattern.gif
![[IM Output]](../static/img/color_basics/present_pattern.gif)
'color ' 参数有时会很麻烦,因为它必须匹配种子点的颜色,否则不会发生任何动作。但这也可能有用,因为它能确保漫水填充确实做你想要的,而非意料之外的事。例如,这里我试图用各种颜色填充白色圆盘…… |
magick disks.gif \
-fill Red -floodfill +30+50 white \
-fill Green -floodfill +60+60 white \
-fill Blue -floodfill +10+40 white \
floodfill_hit_miss.gif
![[IM Output]](../static/img/color_basics/floodfill_hit_miss.gif)
在这种情况下,只有 'Green' 和 'Blue' 漫水填充操作“击中了一个圆盘”(并填充了它),而 'Red' 漫水填充没有匹配到圆盘,所以没有圆盘被填充,也没有意外填充图像的背景。这也意味着,如果你已经填充了某个特定区域,当两个点都击中该区域时,后续的填充不会“重新填充”同一区域。那能节省大量时间。你可能还想看看条件膨胀,它代表一种从图像中多个“种子”点出发的、较低级的漫水填充操作。
Fuzz 因子——匹配相似/多个颜色
正如前面示例所示,仅选择单一颜色进行替换的总体结果通常不太好看。由于抗锯齿(更多信息参见 抗锯齿),纯色区域的边缘或区域通常在边缘处混有多种颜色。因此你应尽可能避免直接颜色替换。例如,这里我取一头看似简单的黑白“牛”,并试图把它变成一头红牛。
magick cow.gif -fill red -opaque black cow_replace_red.gif
正如你所见,只有“黑色”区域的中心部分实际变成了红色。这是因为,尽管图像看起来是黑白的,它实际上是一幅灰度图像,几乎所有边缘都是各种深浅的灰色。也就是说,它们的颜色并非精确的纯黑。Fuzz 因子("[-fuzz](https://imagemagick.org/command-line-options/#fuzz)")代表颜色之间在多维球面距离上的一种“相似性”匹配,使用图像所使用的任何色彩空间。好吧,让我们用大白话来讲。你有一种特定颜色。另一种颜色将被视为与所寻找的颜色_相同_,如果这两种颜色之间的差异小于 fuzz 因子设置。'fuzz 因子' 越大,越多的“相近”颜色将匹配并被替换。那么让我们在牛图像上试试,把不仅是纯黑、还有接近黑色的颜色都转换为红色。
magick cow.gif -fuzz 40% -fill red -opaque black cow_replace_fuzz.gif
正如你所见,我们现在把图像中所有“暗”像素都替换成了红色。但结果仍然很糟,边缘带有灰蒙蒙的色调和强烈的锯齿效应。对这幅图像而言,直接颜色替换不是一个好的解决方案,尽管你可以用一个大的 'fuzz 因子' 让它生效。关于这幅图像的理想解决方案,请参见按颜色的色阶调整中的示例。对于你试图用透明替换背景颜色的图像,这个问题更加严重。你基本上会在该背景颜色上的对象周围得到一圈“光晕”。这非常难以解决,类似的问题在背景去除中有详细讨论。哪些操作使用 fuzz 因子 "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 操作符会影响几乎任何比较图像内特定颜色的操作符。这包括:"[-opaque](https://imagemagick.org/command-line-options/#opaque)"、"[-transparent](https://imagemagick.org/command-line-options/#transparent)"、"[-floodfill](https://imagemagick.org/command-line-options/#floodfill)"、"[-trim](https://imagemagick.org/command-line-options/#trim)"、"[-deconstruct](https://imagemagick.org/command-line-options/#deconstruct)"、"[-draw](https://imagemagick.org/command-line-options/#draw) 'color'"、"[-draw](https://imagemagick.org/command-line-options/#draw) 'matte'",可能还有其他。它也影响 GIF "[-layers](https://imagemagick.org/command-line-options/#layers) [OptimizeTransparency](anim_opt.html#opt_trans)" 和 "[-compose](https://imagemagick.org/command-line-options/#compose) [ChangeMask](compose.html#changemask)" 的处理。它还影响 "magick compare" 的结果,特别是 "[-metric](https://imagemagick.org/command-line-options/#metric) AE" 即绝对误差像素计数。
Fuzz 因子距离
"[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 设置实际上是一种颜色“距离”设置。任何处于所寻找颜色给定距离之内的颜色,都会匹配该颜色,即使它并非精确匹配。值 '200' 表示在所用 IM 的当前颜色深度下 200 个颜色单位的距离。对于 IM Q16(颜色存储用16 位质量)而言这相当小,对于 IM Q8 则非常大,会导致大量颜色彼此匹配。 例如,这里我把处于 'blue' 30,000 颜色单位(对 IM Q16)以内的所有颜色改为白色。在我的 Q16 ImageMagick 程序中,这大致代表从 'blue' 到 'navy'(半暗蓝色)的距离, |
magick colorwheel.png \
-fuzz 30000 -fill white -opaque blue \
opaque_blue.jpg
![[IM Output]](../static/img/color_basics/opaque_blue.jpg)
为了更易理解,这里我反转匹配的颜色,把未匹配的颜色变为白色。 |
magick colorwheel.png \
-fuzz 30000 -fill white +opaque blue \
opaque_blue_not.png
![[IM Output]](../static/img/color_basics/opaque_blue_not.png)
如果你的 IM 早于添加 "[-opaque](https://imagemagick.org/command-line-options/#opaque)" 操作符“加号”形式的 6.3.7-10 版,你可以使用这种遮罩方法来反转颜色匹配的结果…… |
magick colorwheel.png \
\( +clone -fuzz 30000 -transparent blue \
-channel RGB +level-colors white +channel \) \
-composite opaque_blue_inv.png
![[IM Output]](../static/img/color_basics/opaque_blue_inv.png)
或者使用这种方法,把所有修改都限制在“alpha 通道”上,使所有原始颜色保持原样。也就是说,你从颜色选择中创建一个取反的蒙版,使所有未被选中的颜色完全透明。它们仍然存在,只是透明了! |
magick colorwheel.png -fuzz 30000 -transparent blue \
-channel A -negate +channel opaque_blue_inv_alpha.png
![[IM Output]](../static/img/color_basics/opaque_blue_inv_alpha.png)
这些替代方法的一个优势是,你可以把它们扩展为生成一种“非多种颜色”的技术。你只需在取反蒙版之前,向被设为透明的列表中加入更多颜色,并可能移除取反后的透明度。 |
magick colorwheel.png \
-fuzz 25000 -transparent blue -transparent red -transparent lime \
-channel A -negate +channel \
-background white -alpha remove opaque_multi_inv.png
| _有意思的是,在采用 Q8 编译设置的 IM 中,256(28)的 "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 因子会使 'black' 和 'blue' 颜色等价。对于采用 Q16 设置的 IM,这个数字是 65536(216)。
要使 'blue' 和 'red' 颜色匹配,这个数字必须乘以 2 的平方根,即 IM Q8 为 362,IM Q16 为 92682。
要使所有颜色都匹配(例如 'black' 和 'white' 颜色),你需要乘以 3 的平方根。换句话说,IM Q8 的 fuzz 因子设置为 444,IM Q16 为 113512。
---|---
| _很可能使用“感知”色彩空间(如 'LAB' 或 'LUV')能定义出更好、更真实的颜色距离。只需在执行模糊颜色匹配之前把图像转换到那个色彩空间即可。这会使诸如纯蓝与黑色之类的颜色比它们在 'sRGB' 或线性 'RGB' 色彩空间中更接近,黄色与白色也更接近。
---|---
正如你从上面的公式中所见,直接的颜色距离绝对不是设置所用 fuzz 因子的好方法,因为它还取决于所用的具体编译期质量设置。把 "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 因子设置为百分比,会使其使用简单得多。在这种情况下,'100%' 代表一个足够大、能覆盖所有颜色的 fuzz 因子。也就是说,它代表从 'black' 到 'white' 的颜色距离,跨越 RGB 颜色立方体的三维对角线。 这里我们把处于从白到黑距离 90% 以内的任何颜色替换为白色。这应当导致图像上只剩下接近 'black' 的最后 10% 颜色,因为黑色位于 RGB 颜色立方体的对侧。 |
magick colorwheel.png -fuzz 90% -fill white -opaque white opaque_w90.jpg
![[IM Output]](../static/img/color_basics/opaque_w90.jpg)
注意这个 90% 代表 RGB 颜色立方体中围绕 'white' 的一个颜色球体。然而这与替换那些不在 'black' 的 10% 球体内的颜色并不相同。 |
magick colorwheel.png -fuzz 10% -fill white +opaque black opaque_k10.jpg
正如你所见,黑色附近 10% 的颜色球体比围绕白色选取 90% 的颜色球体要均匀得多。想想一个以立方体白色角为中心的大球体如何填充那个立方体。然后想想一个以黑色角为中心的小球体,你就能理解这两幅图像之间的区别了。 ![[IM Output]](../static/img/color_basics/opaque_k10.jpg)
| _100% 的 "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 因子,等于从 'black' 到 'white' 的 RGB 颜色立方体距离。由此我们可以算出,约 57.7% 的百分比是 'black' 与 'blue' 之间的距离,而 81.6% 是从 'blue' 到 'red' 或从这两种颜色之一到 'white' 的距离。
总之,任何大于约 25%(略低于从 'blue' 到 'navy blue' 的 RGB 距离)的值,都代表一个非常大的颜色变化。_
---|---
为了更多地演示颜色距离,让我们围绕蓝色使用逐渐增大的 fuzz 因子百分比……
magick colorwheel.png -fuzz 10% -fill white -opaque blue opaque_b10.jpg
magick colorwheel.png -fuzz 25% -fill white -opaque blue opaque_b25.jpg
magick colorwheel.png -fuzz 57% -fill white -opaque blue opaque_b57.jpg
magick colorwheel.png -fuzz 81% -fill white -opaque blue opaque_b81.jpg
magick colorwheel.png -fuzz 95% -fill white -opaque blue opaque_b95.jpg
由此你可以清楚地看到,离 'blue' 最远的颜色不是 'black' 或 'white',而实际上是 'yellow' 在 RGB 色彩空间中离它最远。还要注意,81% 的颜色差异将刚好错过匹配纯 'red' 颜色,然而虽然纯红不匹配其他红色,但(不含橙红色的)红色确实会匹配。这同样是由于颜色匹配的“球形”本质。其教训是,比起单一的大值,你大概最好使用多个小 "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 因子匹配,或一个较小的“反向匹配”。这里我们把图像中的颜色与另一种颜色——“近乎完美的灰色”——比较,随着 'fuzz 因子' 增大,把相似的颜色改为那同一种灰色。
magick colorwheel.png -fuzz 25% -fill gray50 -opaque gray50 opaque_g25.jpg
magick colorwheel.png -fuzz 30% -fill gray50 -opaque gray50 opaque_g30.jpg
magick colorwheel.png -fuzz 35% -fill gray50 -opaque gray50 opaque_g35.jpg
magick colorwheel.png -fuzz 45% -fill gray50 -opaque gray50 opaque_g45.jpg
magick colorwheel.png -fuzz 51% -fill gray50 -opaque gray50 opaque_g51.jpg
正如你所见,色相环图像中的颜色仅在略低于 30% 的 fuzz 因子处才开始匹配,并缓慢增加,直到 45% 时除了最极端的颜色外都已消失。到 51% 时,图像中所有颜色都已匹配那个近乎完美的灰色。你所看到的,是 RGB 颜色在三维空间中排列成立方体的方式所导致的结果。然而“色相环”图像只包含“完全饱和的颜色”,这基本上意味着所有位于 RGB 颜色立方体外表面上的极端颜色。而完美灰色位于立方体的中心,离所有“饱和颜色”都相当遥远。因此,直到达到 28% 这一较大的 fuzz 因子时,立方体各面中央的颜色才开始匹配。随着 fuzz 因子越来越大,越来越多的颜色会匹配,直到只剩下颜色立方体最极端角落处的颜色。在约 50% 处,角落颜色也将开始匹配,于是到 51% 时每一种不透明的 RGB 颜色都将匹配。
Fuzz 因子与透明颜色
当匹配涉及透明和半透明颜色时,使用 "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" 因子会变得更复杂。例如,这里我跨整幅图像创建一个黑白之间的渐变,但随后在垂直方向上添加一个透明渐变。然后我对完美灰色(即 50% 灰)进行模糊颜色匹配。在后面的图像中,我把被匹配的颜色变得越来越透明,直至完全透明,然而 Fuzz 因子保持恒定的 20%。
magick -size 100x100 gradient: \( +clone -rotate 90 \) +swap \
-compose CopyOpacity -composite trans_gradient.png
magick trans_gradient.png -channel RGBA \
-fuzz 20% -fill Gray50 -opaque 'GrayA(50%,1.0)' fuzz_trans_100.png
magick trans_gradient.png -channel RGBA \
-fuzz 20% -fill Gray50 -opaque 'GrayA(50%,.75)' fuzz_trans_75.png
magick trans_gradient.png -channel RGBA \
-fuzz 20% -fill Gray50 -opaque 'GrayA(50%,.40)' fuzz_trans_40.png
magick trans_gradient.png -channel RGBA \
-fuzz 20% -fill Gray50 -opaque 'GrayA(50%,0.0)' fuzz_trans_00.png
注意上面使用 "-channel RGBA" 并非为了颜色匹配,而是为了指定要被“填充”的颜色通道。也就是说,没有它,上述操作仍会匹配相同的颜色,但灰色“填充”将保持半透明,而不会被设为不透明的灰色。如果你想匹配所有颜色而不管其透明度,那么你需要关闭图像的透明通道,至少暂时关闭。之后你可以再把它打开,不过你的填充颜色将再次具有与原始颜色相同的透明度。在第一幅图像中,与完全不透明的灰色(alpha='1.0')匹配时,你会得到所有接近不透明灰色的非常球形的匹配。然而随着被匹配颜色变得更半透明,匹配的半透明颜色数量似乎会变得更大,直到一个完全透明的灰色将匹配任何接近透明的颜色。所发生的情况是,随着透明度增加,半透明颜色之间的距离减小。两种颜色越透明,与它们不透明的对应颜色相比,它们就越接近。当两种颜色都完全透明时,这两种颜色将被视为完美匹配,即“0”距离匹配。另一件要注意的事是(自 IM v6.6.6-4 起),到一个完全透明颜色(无论灰色与否)的距离,纯粹是该颜色透明度(alpha 值)的函数。上面最后一幅图像匹配了所有处于完全透明 20% 以内的像素,而不管实际颜色如何。 这也意味着,一个大的 Fuzz 因子配合一个完全透明的颜色(如 'none'),可用于匹配所有或几乎所有半透明颜色。例如…… |
magick trans_gradient.png -channel RGBA \
-fuzz 95% -fill Gray50 -opaque None \
-alpha off fuzz_trans.jpg
![[IM Output]](../static/img/color_basics/fuzz_trans.jpg)
注意上面只有顶部 5% 接近不透明的颜色没有匹配,而所有其他半透明颜色都被变成了灰色。最后的 "[-alpha](https://imagemagick.org/command-line-options/#alpha) off" 从图像中去除了最后一点半透明。正因如此,"[-channel](https://imagemagick.org/command-line-options/#channel) RGBA" 设置实际上并不需要,但为完整起见仍推荐使用。这个示例本质上等价于对 alpha 通道做阈值处理,然后在下方添加一个灰色衬底(以使透明颜色变灰) | 在 IM v6.6.6-4 之前,模糊颜色匹配并不把完全透明与不透明颜色同等匹配。事实上,黑色比白色匹配得近得多。因此最后那个示例将失败。详情参见 Fuzz 距离与透明颜色 Bug。
---|---
| 更糟的是,在 IM v6.2.6-2 之前,模糊颜色匹配并不把所有完全透明的颜色视为同一种颜色。也就是说,完全透明的黑色(也称为 'None')与完全透明的白色(或颜色 '#FFF0')不同,尽管它们都是完全透明的。
---|---
正在建设中
Color maths (get the average of two or more colors)....
Example Averaging two colors... Say '#000000' and '#DDDDDD'
Generally the colors are added to images, and the result output as a
single pixel 'txt:-' image, which which the color can be extracted.
* use -resize to merge the colors
magick -size 2x1 xc:'#000000' -fill '#DDDDDD' \
-draw 'point 0,0' -resize 1x1 txt:-
* Use -evaluate-sequence mean on them!
magick -size 1x1 xc:'#000000' xc:'#DDDDDD' \
-evaluate-sequence mean txt:-
Or for a lot of colors you can use the 'Box' resize filter
magick rose: -filter Box -resize 1x1\! txt:
# ImageMagick pixel enumeration: 1,1,255,RGB
0,0: (145, 89, 80) #915950
* Use -fx to apply whatever formula you want
magick -size 1x1 xc:'#000000' xc:'#DDDDDD' \
-fx '(u+v)/2' txt:-
With an ImageMagick API the results can be more directly retrieved from the
image.
![[IM Output]](../static/img/color_basics/colorspace_RGB.png)
![[IM Output]](../static/img/color_basics/colorspace_LUV.png)
![[IM Output]](../static/img/color_basics/colorspace_LAB.png)
![[IM Output]](../static/img/color_basics/color_hex_1.png)
![[IM Output]](../static/img/color_basics/color_hex_2.png)
![[IM Output]](../static/img/color_basics/color_hex_3.png)
![[IM Output]](../static/img/color_basics/color_hex_4.png)
![[IM Output]](../static/img/color_basics/color_hex_5.png)
![[IM Output]](../static/img/color_basics/color_hex_6.png)
![[IM Output]](../static/img/color_basics/color_rgba_1.png)
![[IM Output]](../static/img/color_basics/color_rgba_2.png)
![[IM Output]](../static/img/color_basics/color_rgba_3.png)
![[IM Output]](../static/img/color_basics/color_rgba_4.png)
![[IM Output]](../static/img/color_basics/color_rgba_5.png)
![[IM Output]](../static/img/color_basics/color_rgba_6.png)
![[IM Output]](../static/img/color_basics/color_name_1.png)
![[IM Output]](../static/img/color_basics/color_name_2.png)
![[IM Output]](../static/img/color_basics/color_name_3.png)
![[IM Output]](../static/img/color_basics/color_name_4.png)
![[IM Output]](../static/img/color_basics/color_name_5.png)
![[IM Output]](../static/img/color_basics/color_name_6.png)
![[IM Output]](../static/img/color_basics/separate_red.gif)
![[IM Output]](../static/img/color_basics/separate_green.gif)
![[IM Output]](../static/img/color_basics/separate_blue.gif)
![[IM Output]](../static/img/color_basics/channel_red.gif)
![[IM Output]](../static/img/color_basics/channel_green.gif)
![[IM Output]](../static/img/color_basics/channel_blue.gif)
![[IM Output]](../static/img/color_basics/rose_combined.gif)
![[IM Output]](../static/img/color_basics/rose_red_blue.gif)
![[IM Output]](../static/img/color_basics/rose_grey.gif)
![[IM Output]](../static/img/color_basics/separate_HSB_0.gif)
![[IM Output]](../static/img/color_basics/separate_HSB_1.gif)
![[IM Output]](../static/img/color_basics/separate_HSB_2.gif)
![[IM Output]](../static/img/color_basics/separate_HSL_0.gif)
![[IM Output]](../static/img/color_basics/separate_HSL_1.gif)
![[IM Output]](../static/img/color_basics/separate_HSL_2.gif)
![[IM Output]](../static/img/color_basics/hues_HSL.png)
![[IM Output]](../static/img/color_basics/hues_HCL.png)
![[IM Output]](../static/img/color_basics/separate_lab_luv.png)
![[IM Output]](../static/img/images/cow.gif)
![[IM Output]](../static/img/color_basics/cow_replace_red.gif)
![[IM Output]](../static/img/color_basics/cow_replace_fuzz.gif)
![[IM Output]](../static/img/color_basics/opaque_multi_inv.png)
![[IM Output]](../static/img/color_basics/opaque_b10.jpg)
![[IM Output]](../static/img/color_basics/opaque_b25.jpg)
![[IM Output]](../static/img/color_basics/opaque_b57.jpg)
![[IM Output]](../static/img/color_basics/opaque_b81.jpg)
![[IM Output]](../static/img/color_basics/opaque_b95.jpg)
![[IM Output]](../static/img/color_basics/opaque_g25.jpg)
![[IM Output]](../static/img/color_basics/opaque_g30.jpg)
![[IM Output]](../static/img/color_basics/opaque_g35.jpg)
![[IM Output]](../static/img/color_basics/opaque_g45.jpg)
![[IM Output]](../static/img/color_basics/opaque_g51.jpg)
![[IM Output]](../static/img/color_basics/trans_gradient.png)
![[IM Output]](../static/img/color_basics/fuzz_trans_100.png)
![[IM Output]](../static/img/color_basics/fuzz_trans_75.png)
![[IM Output]](../static/img/color_basics/fuzz_trans_40.png)
![[IM Output]](../static/img/color_basics/fuzz_trans_00.png)