赞
踩
目录
空间域:指图像平面本身,这类图像处理方法直接操作图像中的像素。
空间域处理主要分为灰度变换和空间滤波两类。灰度变换对图像的单个像素进行操作,主要以对比度和阈值处理为目的。空间滤波涉及改善性能的操作,如通过图像中每个像素的邻域处理来锐化图像。
本章讨论的空间域处理可由下式表示:
g(x,y)=T[f(x,y)]
其中,f(x,y)是输入图像,g(x,y)是处理后图像,T为点(x,y)的邻域上定义的关于f的一种算子。算子可应用于单幅图像或图像集合。
上图显示了公式在单幅图像上的基本实现。所示点(x,y)是图像中的一个任意位置,包含该点的小区域是点(x,y)的邻域。邻域通常是中心在(x,y)的矩形,其尺寸要比图像小得多。
该图给出的处理由以下几步组成:邻域原点从一个像素应用算子T,并在该位置产生输出。这样,对于任意指定的位置(x,y),输出图像g在这些坐标处的值,等于对f中以(x,y)为原点的邻域应用算子T的结果。这个过程称为空间滤波,其中邻域与预定义的操作一起称为空间滤波器。
最小邻域的大小为1x1。在这种情况下,g仅取决于点(x,y)处的f值,而T则成为一个如下式的灰度变换函数:
s=T(r)
其中r,s表示变量,即g和f在任意点(x,y)处的灰度。
上图所示反转变换,可得到灰度级范围为[0,L-1]的一幅图像的反转图像,该反转图像由下式给出:
s=L-1-r
对数变换通用形式为:
s=clog(1+r)
式中c是常数,并假设r≥0。对数曲线形状表明,该变换将输入中范围较窄的低灰度值映射为输出中范围较宽的灰度值,或将输入中范围较宽的高灰度值映射为输出中范围较窄的灰度值。
基本形式为:
式中c和γ为正常数。与对数变换的情况类似,部分γ值的幂率曲线将较窄范围的暗色输入值映射为较宽范围的输出值,或将较宽范围的高灰度级输入值映射为较窄范围的输出值。
然而,与对数函数不同的是,我们注意到,随着γ值的变化,我们将简单地得到一族可能的变换曲线。如下图所示:
当γ>1的值所生成的曲线和γ<1的值所生成的曲线的效果完全相反。上式在c=γ=1时简化成了恒等变换。
分段线性函数主要优点是,其形式可以任意复杂。缺点在于其技术说明要求用户输入。
分段线性函数:对比度拉伸、灰度级分层、比特平面分层
首先是图像反转。使用代码获取图片中的每个像素的原灰度值,再读取图片灰度值中的最大值作为“L”,通过减法运算后再将其输出即可实现反色变换。
- import numpy as np
- from PIL import Image
- import matplotlib.pyplot as plt
- #读者在使用反色变换前请安装numpy库和pillow库
- def image_inverse(x):#定义反色变换函数
- value_max = np.max(x)
- y = value_max - x
- return y
- if __name__ == '__main__':
- gray_img = np.asarray(Image.open(r'G:\test photo\1.jpg').convert('L'))
- #Image.open是打开图片,变量为其地址,
- inv_img = image_inverse(gray_img) #将原图形作为矩阵传入函数中,进行反色变换
- fig = plt.figure()#绘图
- ax1 = fig.add_subplot(121)#第一个1是一行,2是是两列,第二个1是第一个图
- ax1.set_title('Orignal')
- ax1.imshow(gray_img, cmap='gray', vmin=0, vmax=255)
- ax2 = fig.add_subplot(122)
- ax2.set_title('Transform')
- ax2.imshow(inv_img, cmap='gray', vmin=0, vmax=255)
- plt.show()
下图为效果图:
然后是对数变换。对数变换公式中加1是为了防止像素灰度为0,从而导致其结果为负无穷。
接下来通过代码进行简单地实验。首先定义一个两行两列矩阵,设其值为[[10, 150], [250, 25500]](其灰度范围为0-25500)。
那么,将其量化到0-255的范围内,
10对应1,
150对应2,
250对应3,
25500对应255。
差距很小,肉眼很难进行分辨。此时通过对数变换进行处理,可以使图像对比度大大增强。
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- def set_chinese():#该函数主要实现对图片名称的汉化
- import matplotlib
- matplotlib.rcParams['font.sans-serif'] = ['SimHei']
- matplotlib.rcParams['axes.unicode_minus'] = False
-
-
- def image_log(cnt):#对数变化运算
- return np.log(1 + cnt)
-
-
- if __name__ == "__main__":
- set_chinese()
-
- x = np.array([[10, 150],
- [250, 25500]])#先将原矩阵的数值写给变量x
-
- xx = image_log(x)#获取对数变换后的数值
-
- fig = plt.figure()
- ax1 = fig.add_subplot(121)
- ax1.set_title('对数变换前', fontsize=12)
- ax1.imshow(x, cmap='gray', vmin=0, vmax=25500)
-
- ax2 = fig.add_subplot(122)
- ax2.set_title('对数变换后', fontsize=12)
- ax2.imshow(xx, cmap='gray')
-
- plt.show()
-
-
-
-
效果图:
灰度级范围为[0,L-1]的数字图像的直方图是离散函数h(rk)=nk,其中rk是第k级灰度值,nk是图像中灰度为rk的像素个数。在实践中,经常用乘积MN表示的图像总像素除每个分量来归一化直方图,通常M和N是图像的行数和列数。因此,归一化后的直方图由p(rk)=nk/MN给出,其中k=0,1...,L-1。简单地说,p(rk)是灰度级rk在图像中出现的概率的估计。归一化直方图的所有分量之和应等于1。
在暗图像中,直方图的分量集中在灰度级的低(暗)段。类似地,亮图像直方图的分量则倾向于灰度级的高端。
低对比度图像具有较窄的直方图,且集中于灰度级的中部。对于单色图像,这意味着暗淡,好像灰度被冲淡了一样。
高对比度图像中直方图的分量覆盖了很宽的灰度级范围,而且像素的分布没有太不均匀,只有少量垂线比其他高许多。
可得出以下结论:若一幅图像的像素倾向于占据整个可能的灰度级并且分布均匀,则该图像会有高对比度的外观并展示灰色调的较大变化。
考虑连续灰度值,并用变量r表示待处理图像的灰度。通常,我们假设r的取值区间为[0,L-1],且r=0表示黑色,r=L-1表示白色。在r满足这些条件的情况下,我们将注意力集中在变换形式
s=T(r),0≤r≤L-1
上(灰度映射),对于输入图像中每个具有r值的像素产生一个输出灰度值s。我们假设函数满足以下条件:
(a)T(r)在区间0≤r≤L-1上位单调递增函数。
(b)当0≤r≤L-1时,0≤T(r)≤L-1
条件(a)中要求T(r)为单调递增函数是为了保证输出灰度值不少于相应的输入值,防止灰度反变换时产生人为缺陷。条件(b)保证输出灰度的范围与输入灰度的范围相同。最后,条件(a’)保证从s到r的反映射是一对一的,防止出现二义性。
一幅图像的灰度级可视为区间[0,L-1]内的随机变量。随机变量的基本描绘子是其概率密度函数(PDF)。令pr(r)和ps(s)分别表示随机变量r和s的概率密度函数,其中p的下标用于指示pr和ps是不同函数。由基本概率论得到的一个基本结果是,如果pr(r)和T(r)已知,且在感兴趣的值域上T(r)是连续且可微的,则变换(映射)后的变量s的PDF可由下面的简单公式得到:
这样,输出灰度变量s的PDF就由输入灰度的PDF和所用变换函数决定[回忆可知r和s由T(r)关联起来]。
在图像处理中,特别重要的变换函数由如下形式:
由莱布尼茨准则推导得:
对于离散值,我们处理其概率(直方图值)与求和来替代处理概率密度函数与积分。如前所述,一幅数字图像中灰度级rk出现的概率近似为
式中MN是图像的总像素,nk是灰度为rk的像素个数,L是图像中可能灰度级的数量。
变换函数的离散形式为
以下为代码复现及效果图(前者为处理前,后者为均衡化后)
- import cv2
- import matplotlib.pyplot as plt
- import numpy as np
-
- # 定义matshow方法
- def matshow(title='image', image=None, gray=False):
- if isinstance(image, np.ndarray):
- if len(image.shape) == 2:
- pass
- elif gray:
- # 转换成GRAY格式
- image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
- else:
- # 图片默认BGR通道,将突破转换成RGB
- image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
- # 使用这种方式显示图片可能会导致图片显示畸形
- # cv2.imshow('image', image)
- plt.figure()
-
- # 载入图像
- plt.imshow(image, cmap="gray")
-
- # 设置标题
- plt.title(title)
-
- plt.show()
-
-
- if __name__ == '__main__':
- im = cv2.imread(r'G:\test photo\1.jpg', 0)
- matshow('im', im)
-
- # 绘制直方图
- plt.hist(im.ravel(), 256, [0, 256])
- plt.show()
-
- # 均衡化处理
- im_equ1 = cv2.equalizeHist(im)
- matshow('im_equ1', im_equ1)
-
- # 绘制均衡化处理的直方图
- plt.hist(im_equ1.ravel(), 256, [0, 256])
- plt.show()
-
直方图均衡能自动地确定变换函数,该函数寻求产生有均匀直方图的输出图像。需要自动增强时,这是一种好方法,因为由这种技术得到的结果可以预知,并且这种方法实现起来也很简单。
对于某些应用,采用均匀直方图的基本增强并不是最好的方法。特别地,又是我们希望处理后的图像具有规定的直方图形状可能更有用。这种用于产生处理后又特殊直方图的方法称为直方图匹配或直方图规定化。
直方图的固定化在大多数时候都是试凑过程,一般来说,并没有固定直方图的规则,对于任何给定的增强人物都必须借助于实例分析。
在某种意义上,像素被基于整幅图像的灰度分布的变化函数修改。这种全局的方法适用于整个图像的增强,但存在增强图像中小区域的细节的需要。在这些区域中,一些像素的影响在全局变换的计算中可能被忽略,因为全局变换没有必要保证期望的局部增强。解决方法是以图像中每个像素的邻域中的灰度分布为基础设计变换函数。
前面描述的直方图处理技术很容易用于局部增强。过程是定义一个邻域,并把该区域的中心从一个像素移至另一个像素。在每个位置,计算邻域中的点的直方图,并且得到的不是直方图均衡化,就是规定化变换函数。这个函数最终用于映射邻域中心像素的灰度。然后,邻域的中心被移至一个相邻像素位置,并重复该过程。
令r表示在区间[0,L-1]上代表灰度值的一个离散随机变量,并令p(ri)表示对应于ri值的归一化直方图变量。
式中,m是r的均值(平均灰度,即图像中像素的平均灰度):
二阶矩阵:
将该表达式称为灰度方差,通常用表示。均值是平均灰度的度量,方差是图像对比度的度量。
在仅处理均值和方差时,实际上通常直接从取样值来估计它们,而不必计算直方图。近似地,这些估计称为取样均值和取样方差。
和
令(x,y)表示给定图像中任意像素的坐标,Sxy表示规定大小的以(x,y)为中心的邻域(子图像)。该领域中像素的均值由下式给出:
类似地,邻域中像素的方差由下式给出:
空间滤波器由
(1)一个邻域(通常是一个较小的矩形)
(2)对该邻域所包围图像像素执行的预定义操作组成。
滤波产生一个新像素,新像素的坐标等于邻域中心的坐标,像素的值是滤波操作的结果。滤波器的中心访问输入图像中的每个像素后,就产生了处理(滤波)后的图像。如果在图像像素上执行的是线性操作,则该滤波器称为线性空间滤波器。否则,滤波器就称为非线性空间滤波器。
滤波器的相应g(x,y)是滤波器系数与由该滤波器所包围的图像像素的乘积之和。
一般来说,使用大小为mxn的滤波器对大小为MxN的图像进行线性空间滤波,可由下式表示:
式中,x和y是可变的,以便w中的每个像素可访问f中的每个像素。
相关:滤波器模板移过图像并计算每个位置乘积之和的处理。 卷积:机理相似,但滤波器首先要旋转180°。 对于大小为mxn的滤波器,我们在图像的顶部和底部至少填充m-1行0,在左侧和右侧填充n-1列0。如果滤波器模板是对称的,显然,相关和卷积将得到相同的结果。
大小为mxn的滤波器w(x,y)与一幅图像f(x,y)做相关操作,可表示为w(x,y)☆f(x,y),它由上一节末尾列出的公式给出
类似地,w(x,y)和f(x,y)的卷积表示为w(x,y)★f(x,y),它由下式给出:
当兴趣在于相关或卷积的模板的相应特性R时,有时写成乘积的求和方式是方便的:
式中w项是大小为mxn的滤波器的系数,z是由滤波器覆盖的相应图像的灰度值。
对于带有标号的普通3x3模板。在这种情况下:
式中w是由模板的系数形成的9维向量,z是由模板包含的图像灰度形成的9维向量。
生成一个大小为mxn的线性空间滤波器要求指定mn个模板系数,这些系数是根据该滤波器支持什么样的操作来选择的,记住,线性滤波的作用实现成绩求和操作。 例如,假设想要将图像中这些像素替换为以这些像素为中心的3x3邻域的平均灰度。图像中任意位置(x,y)的灰度平均值是以(x,y)为中心的3x3邻域中的9个灰度值之和除以9.令zi,i=1,2,...,9表示这些灰度,则平均灰度为
但该式与系数值为wi=1/9的式相同。换句话说,使用系数为1/9的3x3模板进行线性滤波操作可实现所希望的平均。
在某些应用中,我们有一个具有两个变量的连续函数,目的是基于该函数得到一个空间滤波模板。例如,有两个变量的一个高斯函数有如下基本形式:
- import cv2
- # 读取图片
- image = cv2.imread(r"G:\test photo\1.jpg")
- # 高斯滤波
- gauss = cv2.GaussianBlur(image, (5, 5), 0)
- # 显示
- cv2.waitKey()
- cv2.namedWindow('gauss', 0)
- cv2.imshow("gauss", gauss)
- cv2.waitKey( )
- cv2.destroyAllWindows()
平滑滤波器用于模糊处理和降低噪声。模糊处理经常用于预处理任务中,例如在(大)目标提取之前取出图像中的一些琐碎细节,以及连接支线或曲线的缝隙。通过线性滤波和非线性滤波模糊处理,可以降低噪声。
平滑线性空间滤波器的输出(相应)是包含在滤波器模板邻域内的像素的简单平均值。这些滤波器有时也称为均值滤波器。
平滑滤波器的基本概念非常直观。它使用滤波器模板确定的邻域内像素的品滚灰度值来代替图像中每个像素的值,这种处理的结果降低了图像灰度的“尖锐”变化。由于典型的随机噪声由灰度级的急剧变化组成,因此,常见的平滑处理应用就是降低噪声。
上图模板产生所谓的加权平均,是指不同的系数乘以像素,即一些像素的重要性(权重)要比另一些像素的重要性大。
一幅MxN图像经过一个mxn(m和n是奇数)的加权均值滤波器滤波的过程可由下式给出:
统计排序滤波器是一种非线性空间滤波器,这种滤波器的响应以滤波器包围的图像区域中所包含的像素排序(排队)为基础,然后使用统计排序结果决定的值代替中心像素的值。
中值滤波器:用像素邻域内灰度的中值(在中值计算中包括原像素值)代替该像素的值。它提供了一种优秀的去噪能力,并且比相同尺寸的线性平滑滤波器的模糊程度明显要低。中值滤波器对处理脉冲噪声非常有效,这种噪声也称为椒盐噪声。
最大值滤波器:使用像素邻域内灰度的最大值来代替该像素的值,在搜寻一幅图像的最亮的时非常有用。
最小值滤波器:使用像素邻域内灰度的最小值来代替像素的值,可用于相反的目的。
- import cv2
- import matplotlib.pyplot as plt
- import numpy as np
-
- img = cv2.imread(r"G:\jy.png")
- blur = cv2.medianBlur(img, 3)
- cv2.waitKey()
- cv2.imshow("org", img)
- cv2.imshow("result", blur)
- cv2.waitKey()
- cv2.destroyAllWindows()
可以看出中值滤波(非线性滤波)处理椒盐噪声效果良好
锐化处理的主要目的是突出灰度的过渡部分。锐化处理可由空间微分来实现。
一维函数f(x)的一阶微分的基本定义是差值
二阶微分定义为如下差分:
一阶微分处理主要应用于提取边缘;二阶微分主要用于增强细节,是一个适合锐化图像的立项特征。
各向同性滤波器:响应与滤波器作用的图像的突变方向无关。也就是说,各向同性滤波器是旋转不变的,即将原图像旋转后进行滤波处理给出的结果,与先对图像滤波然后再旋转的结果相同。
最简单的各向同性微分算子是拉普拉斯算子。一个二维图像函数f(x,y)的拉普拉斯算子定义为:
因为任意阶微分都是先行操作,所以拉普拉斯变换也是一个线性算子。两个变量的拉普拉斯算子:
由于拉普拉斯是一种微分算子,因此其应用着重于图像中的灰度突变区域,而非灰度级缓慢变化的区域。这将产生暗色背景中叠加有浅灰色边线和突变点的图像。将原图像和拉普拉斯图像叠加在一起的简单方法,可以复原背景特效并保持拉普拉斯锐化处理的效果。
使用拉普拉斯增强图像的基本方法:
f(x,y)和g(x,y)是输入图像和锐化后的图像。若定义的中心系数是负的,则c=-1,反之,c=1。
- import cv2
- import numpy as np
- def Laplace_suanzi(img):
- r, c = img.shape
- new_image = np.zeros((r, c))
- L_sunnzi = np.array([[0, -1, 0], [-1, 4, -1], [0, -1, 0]])
- # L_sunnzi = np.array([[1,1,1],[1,-8,1],[1,1,1]])
- for i in range(r - 2):
- for j in range(c - 2):
- new_image[i + 1, j + 1] = abs(np.sum(img[i:i + 3, j:j + 3] * L_sunnzi))
- return np.uint8(new_image)
-
-
- img = cv2.imread(r"G:\3.png", cv2.IMREAD_GRAYSCALE)
- cv2.imshow("image", img)
- cv2.waitKey()
- cv2.destroyAllWindows()
印刷和出版业已用多年的图像锐化处理过程是从原图像中减去一幅费瑞华(平滑)的版本。这个称为非锐化掩蔽的处理过程由下列步骤组成:
1.模糊原图像。 2.从原图像中减去模糊图像(产生的差值图像称为模板)。 3.将模板加到原图像上。
然后,在原图像上加上该模板的一个权重部分:
k为权重系数(k≥0)。当k等于1时,我们得到上面定义的非锐化掩蔽。当k>1时,该处理称为高提升滤波。选择k<1则不强调非锐化模板的贡献。当k足够大时,会产生不好的结果。
图像处理中的一阶微分是用梯度幅值来实现的。对于函数f(x,y),f在坐标(x,y)处的剃度定义为二维列向量
向量▽f的幅值(长度)表示为M(x,y),即
M(x,y)是与原图像大小相同的图像,它是888当x和y允许在f中的所有像素位置变化时产生的。在实践中,该图像通常称为梯度图像。
因为梯度向量的分量是微分,所以它们是线性算子。但该向量的幅度不是线性算子,因为求幅度是做平方和平方根操作。另一方面,上式中偏微分不是旋转不变的(各向同性),而梯度向量的幅度是旋转不变的。在某些实现中,用绝对值来近似平方和平方根操作更适合于计算:
Roberts提出的其他两个定义使用交叉差分:
Sobel算子:
- #roberts算子
- import cv2
- #roberts算子[[-1,-1],[1,]]
- def robert(img):
- h,w=img.shape[:2]
- r=[[-1,-1],[1,1]]
- for i in range(h):
- for j in range(w):
- if (j+2<w) and (i+2<=h):
- process_img=img[i:i+2,j:j+2]
- list_robert=r*process_img
- img[i,j]=abs(list_robert.sum())
-
- return img
-
- img=cv2.imread(r'G:\3.png',cv2.IMREAD_GRAYSCALE)
- cv2.imshow('orl_img',img)
- img=robert(img)
- cv2.imshow('robert',img)
- cv2.waitKey(0)
- #sobel算子
- import cv2
- import numpy as np
-
-
- def sobel(img):
- h,w=img.shape
- new_img=np.zeros([h,w])
- x_img=np.zeros(img.shape)
- y_img=np.zeros(img.shape)
- sobel_x=np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
- sobel_y=np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
- for i in range(h-2):
- for j in range(w-2):
- x_img[i+1,j+1]=abs(np.sum(img[i:i+3,j:j+3]*sobel_x))
- y_img[i+1,j+1]=abs(np.sum(img[i:i+3,j:j+3]*sobel_y))
- new_img[i+1,j+1]=np.sqrt(np.square(x_img[i+1,j+1])+np.square(y_img[i+1,j+1]))
-
- return np.uint8(new_img)
-
- img=cv2.imread(r'G:\3.png',cv2.IMREAD_GRAYSCALE)
- cv2.imshow('orl_img',img)
- img=sobel(img)
- cv2.imshow('sobel',img)
- cv2.waitKey(0)
-
可以看出边缘检测效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。