对这个工具,你一定很熟悉吧,Photoshop里有,很多简单的图像处理软件里面也会有
那这个工具到底是什么意思呢,它和我们要讲到的灰度变换有很大的关系
在图像处理中,像图像度变换和直方图均衡都属于点运算范畴。
处理时作用域是单个像素
有表达式:
g(x,y) = T[ f(x,y) ] T为映射关系
在点运算中,映射关系是关键,它描述了输入灰度级和输出灰度级之间的关系。
灰度变换是图像增强的一种重要手段,用于改善图像的显示效果,属于空域处理方法
最开始我们讲的反转就属于灰度变换的一种
其变换关系为
g(x,y) = 255 - f(x,y)
我们来讲讲常用的灰度变换
(1)灰度线性变换
1.图像反转
2.线性灰度变换
表达式关系为
3.分段线性灰度变换
表达式关系为
我们来写程序来实现这些功能:
import cv
def Hist(image,color
=
cv.RGB(
102
,
204
,
204
)):
a = [0]
*
256
w = image.width
h = image.height
iHist = cv.CreateImage((
256
,
256
),
8
,
3
)
for i
in
range(h):
for j
in
range(w):
iGray = int(image[i,j])
a[iGray] = a[iGray]
+
1
S = max(a)
for k
in
range(
256
):
a[k] = a[k]
*
255
/
S
x = (k,
255
)
y = (k,
255
-
a[k])
cv.Line(iHist,x,y,color)
return iHist
def GrayTr(image,array):
w = image.width
h = image.height
size = (w,h)
iGrayTr = cv.CreateImage(size,image.depth,
1
)
for i
in
range(h):
for j
in
range(w):
idex = int(image[i,j])
iGrayTr[i,j] = array[idex]
return iGrayTr
def Invert():
aInvert = [0]
*
256
for i
in
range(
256
):
aInvert[i] =
255
-
i
return aInvert
def Linear():
aLinear = [0]
*
256
for i
in
range(
256
):
if i
<
60
:
aLinear[i] =
30
elif i
<
200
:
aLinear[i] = int((
220.0
-
30.0
)
/
(
200
-
60
)
*
(i
-
60
)
+
30
)
else :
aLinear[i] =
220
return aLinear
def SubLinear():
aSubLinear = [0]
*
256
for i
in
range(
256
):
if i
<
60
:
aSubLinear[i] = int(
30.0
/
60
*
i)
elif i
<
200
:
aSubLinear[i] = int((
220.0
-
30.0
)
/
(
200
-
60
)
*
(i
-
60
)
+
30
)
else :
aSubLinear[i] = int((
255.0
-
220.0
)
/
(
255
-
200
)
*
(i
-
200
)
+
220
)
return aSubLinear
image = cv.LoadImage(
'
lena.jpg
'
,0)
iInvert = GrayTr(image,Invert())
iLinear = GrayTr(image,Linear())
iSubLinear = GrayTr(image,SubLinear())
cv.ShowImage( ' image
'
,image)
cv.ShowImage( ' iInvert
'
,iInvert)
cv.ShowImage( ' iLinear
'
,iLinear)
cv.ShowImage( ' iSubLinear
'
,iSubLinear)
cv.ShowImage( ' iHist
'
,Hist(image))
cv.ShowImage( ' iIHist
'
,Hist(iInvert))
cv.ShowImage( ' iLHist
'
,Hist(iLinear))
cv.ShowImage( ' iSubHist
'
,Hist(iSubLinear))
cv.WaitKey(0)
运行效果如下:
我们看到第三幅图的直方图和其他的有很大差别
主要是在我们把原图中灰度值在60以下的点全部映射到灰度值30
使得灰度值为30的点特别多,导致其它的灰度值的点显得很少,相应的画出来也就特别短
但明显的,我们看到没有点映射到30一下和220以上,在灰度值上产生了截断效果
另外我们来看看灰度窗和灰度级分层:
灰度窗是左边映射关系:增强特定灰度值的对比度,其它的全部置0
灰度级分层:把在特定灰度级和其他灰度级的区域分开
编写程序:
import cv
def GrayTr(image,array):
w = image.width
h = image.height
size = (w,h)
iGrayTr = cv.CreateImage(size,image.depth, 1
)
for i in
range(h):
for j in
range(w):
idex = int(image[i,j])
iGrayTr[i,j] = array[idex]
return iGrayTr
def Window():
aWindow = [0] *
256
for i in
range(
60
,
121
):
aWindow[i] = int( 255.0
/
(
120
-
60
)
*
(i
-
60
))
return aWindow
def Slice():
aSlice = [0] *
256
for i in
range(
256
):
if i >
59
and
i
<
121
:
aSlice[i] = 200
else :
aSlice[i] = 30
return aSlice
image = cv.LoadImage( '
lena.jpg
'
,0)
iWindow = GrayTr(image,Window())
iSlice = GrayTr(image,Slice())
cv.ShowImage( ' image '
,image)
cv.ShowImage( ' iWindow '
,iWindow)
cv.ShowImage( ' iSlice '
,iSlice)
cv.WaitKey(0)
效果如下:
(2)灰度非线性变换
左边为对数变换,右边为指数变换(当然,上面的图不是很标准)
重点是生成对应的映射对
程序如下:
import cv
import math
def GrayTr(image,array):
w = image.width
h = image.height
size = (w,h)
iGrayTr = cv.CreateImage(size,image.depth, 1 )
for i in range(h):
for j in range(w):
idex = int(image[i,j])
iGrayTr[i,j] = array[idex]
return iGrayTr
def Log():
aLog = [0] * 256
for i in range(
1
,
256
):
aLog[i] = int( 32 *
math.log(i,
2
))
return aLog
def Exp():
aExp = [0] * 256
NUM = 1.01
k = math.pow(NUM, 255 )
for i in range(
1
,
256
):
aExp[i] = int( 255 *
math.pow(NUM,i)
/
k)
return aExp
image = cv.LoadImage( ' lena.jpg
'
,0)
iLog = GrayTr(image,Log())
iExp = GrayTr(image,Exp())
cv.ShowImage( ' image ' ,image)
cv.ShowImage( ' iLog ' ,iLog)
cv.ShowImage( ' iExp ' ,iExp)
cv.WaitKey(0)
效果如下
好啦。灰度变换就讲到这里啦!!