图像处理

Wolfram 语言对编程式的和交互式图像处理都提供内置的支持,和 Wolfram 语言强大的数学和算法功能完全地结合在一起. 你能创建和导入图像,用内置函数对它们进行操作,应用线性的和非线性的滤波器,以及用几种不同的方式来显现它们.
图像创建和表示
图像可以通过数值数组,通过对 Wolfram 语言图形剪贴的方法,以及通过用 Import 从外部来源来创建.
Image[data]
像素值由 data 给出的光栅图像
Import["file"]
从一个文件导入的数据
CurrentImage[]
从摄像头或者其他设备捕捉图像
图像创建函数.
创建一个图像对象的最简单的方法是用 Image 封装一个从0到1的实数矩阵.
这里是一个由一个数字矩阵创建的单通道的图像:
另一个方法是从某些其它的应用程序中复制和粘贴或拖放一个图像. 你可以用 Import 从一个当地文件系统中或任何可进入的远程文件中获得一个图像.
这里从 Wolfram 语言的文件目录 ExampleData 中输入一个图像:
通过调用如下的函数可获得图像的有用属性.
ImageDimensions[image]
给出和 image 相联系的光栅的像素尺寸
ImageAspectRatio[image]
给出 image 高宽比例
ImageChannels[image]
给出在 image 数据中存在的通道的数目
ImageColorSpace[image]
给出与 image 相关的色彩空间
ImageType[image]
给出 image 中的每一个像素元素所用的数值类型
ImageQ[image]
如果 image 是一个有效的 Image 对象的形式, 那么给出 True (真),否则,给出 False(假)
Options[symbol]
给出赋予一个符号的默认选项的一个列表
ImageData[image]
image 中像素值阵列
图像属性.
返回图像尺寸:
ImageData (图像数据)函数可以很容易地提取图像的像素值数组. 默认情况下,这个函数返回实数值,但是你可通过可供选择的类型自变量来得到一个特定的类型.
这里作为一个按比率缩放到0和1的实数矩阵,返回图像的一部分:
这里是作为一个范围从0到255的整数矩阵返回同样的图像部分:
在多通道图像的情况下,原始的像素数据是用一个三维数组来表示的,它按照由 Interleaving 选项决定的两种可能方法之一来排列.
输入一个彩色图像:
在默认的 Interleaving->True 设置下,数据被组织成一个颜色值列表的二维数组,颜色值列表在 RGB 颜色空间图像的普通情况下由三个数组成.
这显示了默认的数据组织形式:
Interleaving->False 这个选项设置能用来把原始数据作为矩阵的列表来存储和提取,每一个矩阵对应一个颜色通道.
这是上例中的图像部分,它被排列成一个通道矩阵的列表:
一个多通道的图像能够被分解成单通道图像的一个列表,反过来,一个多通道的图像能由任何数目的单通道图像来创建.
这里把上例中的 RGB 颜色的图像分解成三个灰度图像:
坐标系
有几种图像处理命令要求或返回图像域的位置. 要指定像素位置,坐标系是必需的. 请注意,使用的坐标系多于一个. 本教程将分别介绍索引坐标和图像坐标.

索引坐标

图像是由像素数据组成的数组. 这些数组的行和列具有下标作为固有的坐标. 因此,Wolfram 语言的部分规范自然地由离散坐标系扩展至图像.
定义一个黑白数据的数组:
这里从数组中提取前10行中的第9至15列:
相应的具有相同行列规范的图像指令:
由行、列的下标给出的部分规范具有明确的定义. 然而,一个数组的空间嵌入是不明确的.
Graphics 的基元 Raster 将数组各行从上到下显示:
Image 对数组各行从上到下进行渲染:
列与行坐标的方向取决于空间嵌入. 对行进行枚举的第一个坐标垂直运行,在 Raster 的情况下由下向上,在 Image 的情况下由上向下. 对列进行枚举的第二个坐标沿水平方向由左到右运行.
一个宽度为 、高度为 Raster 的索引坐标:

3.gif

一个宽度为 、高度为 Image 的索引坐标:

6.gif

同时作用于图像和数据阵列的 Wolfram 语言命令遵循索引坐标系. 这些命令首先列出指向垂直行坐标的参数,然后列出指向水平列坐标的参数.
方向上沿行坐标的一阶高斯导数:
方向上沿列坐标的一阶高斯导数:

图像坐标

第二个坐标系对数据而言不是内在的,但附加于嵌入空间中. 连续图像坐标系,与图形坐标系类似,原点位于图像的左下角, 坐标从左至右延伸, 坐标由下至上》 图像域覆盖二维区间 ×.
一个宽度为 、高度为 Image 的标准图像坐标:

15.gif

图像的像素是由连续整数坐标值之间的区间覆盖. 因此,非整数坐标明确指向单个像素. 然而,位于像素边界的整数坐标,通过选择所有相邻的像素,或取它们的平均颜色值,将所有直接相邻的像素考虑在内.
一个标准图像坐标上的通道值:

16.gif

在像素之间的标准图像坐标上的平均通道值:

17.gif

贯穿坐标 {5,5}{16,16} 及其相邻像素的剪切图像:

18.gif

适用于任意阵列的图像处理命令,将在标准图像坐标中对结果进行渲染. 这些标准图像坐标可以很容易地在 Graphics 的基元中使用.
ImageLines 返回标准图像坐标中的线条:
对于高度为 的图像,索引坐标 与标准图像坐标 之间的转换关系如下:
,
或者
.
标准图像坐标系的一个稍作修改的版本的是归一化图像坐标系. 在该坐标系中,图像宽度 被缩放为1.
一个宽度为 、高度为 Image 的归一化图像坐标:

29.gif

在有些时候,使用归一化坐标指定与图像尺寸无关的操作更为方便.
将图像移动 个图像宽度:
以像素为单位进行相同的移动:
标准图像坐标系的另一种修改后的版本是像素对齐的坐标系. 该坐标系的原点相对于标准图像坐标系向左和向下偏移 ,以对齐像素中心的整数坐标.
一个宽度为 、高度为 Image 的像素对齐图像坐标:

34.gif

PixelValue[image,{x,y}]
给出图像在位置 {x,y} 处的像素值
PixelValuePositions[image,val]
返回 image 中与值 val 匹配的像素位置列表
ReplacePixelValue[image,{xp,yp}->val]
image 中位置 {xp,yp} 处的像素值变更为 val
使用像素对齐图像坐标的命令.
基本图像操作
考虑通过剪切或填充来改变图像尺寸的图像操作. 这些操作有各种不同的用处. 剪切允许你从一个大的图像中选择一部分来创建出一个新的图像,而在图像处理中,填充通常是用来在边沿上延伸图像以确保边沿像素的均匀处理.
ImageTake[image,n]
给出一个由 image 的前 n 行组成的图像
ImageCrop[image]
通过去除颜色均匀的边沿来剪切 image
ImageTrim[image,{{x1,y1},}]
image 进行裁剪以囊括指定的 {xi,yi} 像素
ImagePad[image,m]
m 个背景像素来填充 image 的所有边沿
图像的剪切和填充操作.
这选取了例图中的前50行:
ImageCrop (图像剪切)方便地补充了 ImageTake. 它不是指定要被提取的确切的行数和列数,相反的,它允许你定义新产生的图像的理想尺寸,也就是,要保留的行数和列数. 默认下,剪切操作是中心进行的,即从图像的边缘上删除相同数量的行和列.
这里从例图的中心提取了一个100×100的像素区域:
ImageCrop 主要是用来减小源图像的尺寸,人们也常常希望填充一个图像使得它的尺寸增加. 这里支持所有最普遍的填充方法.
这里显示了应用到例图右边缘的四种不同的填充方法:
经常有必要通过重新抽样或以某种方式改变它的位置来改变一个图像的尺寸. 我们有执行这些基本的几何任务的函数可供使用.
ImageResize[image,w]
给出一个 w 像素宽,重新改变了尺寸的 image 版本
Thumbnail[image]
给出 image 的一个缩略图
ImageRotate[image]
逆时针旋转 image 90°
ImageReflect[image]
用上下镜面反射翻转 image
空间操作.
这里, ImageResize 用来增加和缩减原始图像的大小:
ImageRotate 是另一个常用的空间操作. 它产生的图像,其所有像素都相对于图像中心的支点有一个逆时针旋转.
这里将例图旋转了30度:
有一些有用的图像处理任务只要求在两个图像或一个图像和一个常数之间进行简单的算术运算. 例如,你能通过将一个图像和一个常数因子相乘或往(从)一个图像中加(减)一个常数来改变明度. 更有趣的是,两个图像之间的差别能够用来发现变化,两个图像之间的乘积能用来隐藏或突出一个图像的某些区域,这个过程叫做掩模(masking). 对于这个用途,有三个基本的算术函数可用.
ImageAdd[image,x]
image 中的每一个通道值加上一个量 x
ImageSubtract[image,x]
image 中的每一个通道值中减去一个常数量 x
ImageMultiply[image,x]
image 中的每一个通道值和一个因子 x 相乘
算术运算.
这里是一个通过相加和相乘来混合图像的例子:
用点操作来处理图像
点操作构成一个简单但重要的一类图像处理操作. 这些操作改变一个图像的明视度的数值因而改变一个图像的显示外观. 这个术语起源于这样一个事实,那就是点操作取单个的像素作为输入. 可以这样表达
    
这里 是一个灰度变换,它指定了一个在输入图像 和结果 之间的映射, 表示像素的行和列的指标. 点操作是一个根据某个定义 T 变换的函数在原始的(输入)和修改了的(输出)图像之间的一对一的映射.

对比度修改

在图像处理中经常遇到的对比度修改的点操作包括求反(灰度的或彩色的),gamma(伽玛) 校正(一个幂律变换),以及线性和非线性的对比度伸展.
Lighter[image,
]
给出 image 的一个亮一点版本
Darker[image,
]
给出 image 的一个暗一点版本
ColorNegate[image]
给出 image 的负本,在其中所有的颜色都被求反了
ImageAdjust[image]
调整 image 中的级别,使它们按比例调节到0到1的范围里
ImageApply[f,image]
f 应用于 image 中每一像素的通道值列表
摘选的点算符.
最简单的点变换的例子之一是求反. 对一个灰度图像 f,这个变换被定义为
    .
它被用于源图像的每一个像素. 在多通道图像的情况下,同样的变换被用于每一像素的每一颜色值.
这里显示了原来的例图和它的数字负片:
ImageAdjust 函数能用于执行绝大多数普遍需要的对比度伸展和幂律变换,而 ImageApply 使你能够实现任何你想要的点变换.
这里用线性比例调节增加对比度:
作为一个非线性对比度伸展操作的例子,考虑以下叫做 sigma 缩放的变换. 假设默认的范围是从0到1,这个变换定义为
    .
下面定义这个变换:
这里是方差参数值不同的几个变换的图形:
这里显示了这个变换对例图的效果:
图像二值化是一个把多级的图象转换成一个二值图像的操作. 在一个二元图像中,每一个像素的数值由一个单一的二进制数字代表. 在它最简单的形式下,二值化,也叫做阈值化,是一个基于点的操作,它根据和某一个总体的阈值 t 相比较来给一个图像的每一个像素赋予一个0或1的值.
    
阈值化是一个引人注目的早期处理步骤,因为它导致数据存储量上极大的减小并且产生更易于分析的二值图像. 二值图像允许使用强大的形态运算符来对图像内容进行基于形状和结构的分析. 二值化也是图像分割的一种形式,因为它把一个图像分割成不同的区域.
Binarize[image]
image 创建一个二值图像
ColorQuantize[image,n]
给出仅用 n 个不同颜色的近似 image
量化函数.
彩色图像在阈值化之前先被转化成灰度图像. 如果阈值没有明显地给出,那么通过几个众所周知的方法之一来计算一个最优数值.
这里是一个基于 Otsu 的最优阈值选择方法的默认的二值化:
这里 ImageApply 用来返回一个彩色图像,在其中每一个单独的通道都被二值化了,导致最多8个不同的颜色:

颜色转换

支持的颜色空间包括:RGB(红、绿、蓝)、CMYK(青绿、品红、黄、黑)、HSB(色相、饱和度、明度)、灰度和独立于设备的空间,例如,Lab.
在实际使用中,RGB (红色、绿色、蓝色)颜色配合是最常用的颜色表达方式. 这三个所谓的主色彩用不同的比例合并在一起(加在一起)来产生一个复合的,全色彩的图像. RGB 颜色模式在彩色监视器,录像机和照相机里普遍使用. 而且,人的视觉系统也是通过把颜色调节成这些主色彩的不同组合来感知的. 相同数量的主色彩加在一起产生光的次要色彩:青绿色 (C),品红色(M),和黄色(Y). 这是用于印刷业中的主要色素颜色,所以显示出 CMY 颜色模式的重要性. 对图像处理的应用,把颜色信息从明视度上分开出来经常是有用的. HSB(色相、饱和度、明度)模式有这个特性. 色相代表观察者所看见的主要颜色,饱和度指的是用白光对颜色的稀释量,明度定义平均的亮度. 亮度这一成分,因此,可以独立于图像颜色信息来处理.
ColorConvert[expr, colspace]
expr 里的颜色指定转换成由 colspace 代表的颜色空间
颜色转换函数.
这里显示了从一个 RGB 源转换到其它受支持的颜色空间的结果:
注意到 RGB->Grayscale (RGB -> 灰度)这个变换使用了美国广播电视(NTSC)推荐的并后来加入到 CCIR 601 数字录像标准的加权系数.

图像直方图

普遍地对于很多图像增强操作的一个重要概念是直方图,它只是一个对图像中灰色级别的一个计数(或相对频率,如果是归一化的). 对直方图的分析给出关于图像对比的有用信息. 图像直方图在图像处理的很多领域中都很重要,最显著的是压缩、分割和阈值.
ImageLevels[image]
image 中的每一个频道给出一列像素数值和计数
ImageHistogram[image]
image 中的每一个频道画出一个像素级别的直方图
图像直方图函数.
这里显示了两种不同的直方图的显现方法:
区域操作的图像处理
大多数有用的图像处理算符都是基于区域的. 基于区域的操作根据在一个局部的,通常小的邻近区域中的数值来计算一个新的像素数值. 这一般是通过用一个有限大小的算符(比如,一个滤波器)进行的线性或非线性的滤波操作来履行的. 不失去一般性,考虑一个位于 ,数值为 的图像像素中心的一个对称的 3×3 的邻近区域. 一个普遍的基于区域的变换能被表示为
    
这里 是由把 变换应用到输入图像 中所有像素位于中心的 3×3 邻域而产生的输出图像. 应该注意到邻域的空间尺寸和几何形状一般是由应用的需要而决定的. 基于区域的图像处理操作的例子包括降低噪声,边缘检测,边缘锐化,图像增强和分割.

线性和非线性滤波

使用卷积的线性图像滤波是处理图像的最通用的方法之一. 为了达到一个理想的结果,你必须指定一个合适的滤波器. 例如平滑,锐化,边缘检测,以及变焦这样的任务都是典型的基于卷积来实施的图像处理任务的例子. 其它的任务,例如噪声去除,最好是用非线性的处理技术来完成.
ImageFilter[f,image,r]
f 应用于 image 的每一个通道中的每一个像素的 r 范围
ImageConvolve[image,ker]
给出 image 和内核 ker 的卷积
一般的滤波函数.
这里是使用一个平滑滤波器的一个典型的模糊操作:
更普遍的(但速度上会慢一些的)ImageFilter 函数能在传统的线性滤波不能用,并且理想的操作不能由任何固定的滤波函数来履行的情况下使用.
计算每一个像素的一个小的邻区内最大的数值范围:
大量的线性和非线性的算符可作为固定函数使用. 这里是一部分列单.
Blur[image]
给出一个模糊的 image 版本
Sharpen[image]
给出一个锐化的 image 版本
MeanFilter[image,r]
对每一个数值用它的范围 r 的平均值替换
GaussianFilter[image,r]
同一个像素半径为 r 的 Gaussian 内核卷积
MedianFilter[image,r]
对每一个数值用它的范围 r 的中位数替换
MinFilter[image,r]
对每一个数值用它的范围 r 的最小值替换
CommonestFilter[image,r]
对每一个像素用它的范围 r 中最普遍的像素值替换
普遍的线性和非线性的滤波算符.
在图像处理中更普遍的线性滤波的应用之一是对离散导数的近似计算,因而边缘检测. 众所周知的 Prewitt、Sobel 和Canny 的方法本质上都是基于对图像中每一点的两个正交的导数和梯度大小的计算上的.
这里是两个 Sobel 滤波器:
这里用 Sobel 滤波器返回一个灰度图像的边缘:
作为第二个例子,考虑从一个图像中去除脉冲噪声的任务,由于它的外观这叫做椒盐噪声. 这是一个经典的例子,对比由线性移动平均和非线性移动中位数的计算所产生的不同结果.
创建一个有脉冲噪声的小图像:
这里是一个并排的比较:
显然地,中值滤波器返回更好的结果.

形态处理

数学形态提供了一个处理基于景色中物体的空间结构的数字图像的方法. 在二值形态中,和目前为止讨论的线性和非线性算符不一样,形态算符改变像素群的形状而不是它们的振幅. 但是,和这些算符类似,二值形态算符可以用卷积一样的算法来履行,把基本的加法和乘法运算用逻辑的 OR(或)和 AND(与)来替换.
Dilation[image,r]
关于一个范围 r 平方的膨胀
Erosion[image,r]
关于一个范围 r 平方的腐蚀
基本的形态算符.
这里显示了用一个5x5均匀结构元素得到的一个二值图像(中间)的膨胀(左边)和腐蚀(右边):
二值形态的定义自然地延伸到灰度图像的领域,当 Boolean(布尔)AND(与)和 OR(或)成为逐点的最小和最大的算符时. 对于一个均匀的,零值的结构元素,一个图像 的膨胀简化成以下简单的形式:
    
这里显示了用一个5x5均匀结构元素得到的彩色图像例子(中间)的膨胀(左边)和腐蚀(右边):
通过使用一个单一的结构元素或者一列那样的元素,这些算符能够组合在一起使用,用来执行很多有用的图像处理的任务. 一个部分的列表包括变细,变粗,边缘和边角检测,以及背景归一化.
这里用膨胀和腐蚀来检测一个灰度图像中的边缘:
GeodesicDilation[marker,mask]
给出受图像 mask 约束的图像 marker 的短程膨胀的一个固定点
GeodesicErosion[marker,mask]
给出受图像 mask 约束的图像 marker 的短程腐蚀的一个固定点
DistanceTransform[image]
给出 image 的距离变换,在其中每一个像素的数值都被它到最近的一个背景像素的距离替代
MorphologicalComponents[image]
给出一个数组,在其中 image 的每一个像素都被代表那个像素所在的相联系的前景图像成分的整数指标所替代
摘选的形态函数.
一个重要的形态算法的种类,称为形态重新构造,是基于对一个标记图像反复地使用膨胀(或腐蚀),每一步的结果都受第二个图像,掩模的束缚. 这个过程在达到一个固定点时结束. 有趣的是,很多的图像处理的任务在重新构造方面都有一个自然的公式. 峰和谷的检测,洞的填充, 区域充斥,以及滞后阈值只是几个例子. 后者,也称为一个双阈值,是一个广泛被使用的 Canny 边缘检测器的不可缺少的一部分. 在低端阈值之下的像素被拒绝,在高端阈值之上的像素被接受,而在中间范围的像素只有在它们是和高阈值的像素连接时才会被接受. 连接可以用不同的算法来建立,但重新构造给出了一个有效而且非常简单的解决办法.
这里分别是低的、高的、和双阈值的图像:
清除所有符号: