一、灰度化
灰度化定义
在R、G、B图像模型中,当R=G=B(三种颜色分量值相同时),则此时彩色表示一种灰度颜色,其中R=G=B的值叫做灰度值,在灰度图像中,灰度值也可以称为亮度值。灰度值范围0-255
灰度化的方法
对于一副彩色图像来说,灰度化一般有四种常用方法,分别为分量法
最大值法
平均值法
加权平均法
。
1.分量法
该方法最为简单,即在R、G、B三种颜色分量中,任意选取一种颜色作为灰度值
2.最大值法
该方法是先找出每个像素R、G、B三种颜色分量的值,然后找到值最大的那个颜色,然后以此最大值作为灰度值
3.平均值法
该方法是先找到像素的R、G、B三种颜色的分量值,最后置灰度值为三个分量值的平均值即可。
4.加权平均法
因为人眼对每种颜色的敏感度不同,其中人眼对绿色敏感度最高,蓝色敏感度最低,所以我们可以使用加权平均的方法来求灰度值,公式如下
灰度化应用场景
- 计算机通过图像识别物体的时候,最关键的因素是图像的梯度,有了梯度我们才可以找到物体边缘,才能对物体进行定位。然而梯度计算必须要用到灰度图像,彩色图像非常容易受到光照等因素的影响,同类的物体颜色也有很多变化,所以彩色图像是很难提供一些关键信息的
- 图像进行灰度化之后,矩阵的维数降低,所以运算速度会大幅度提高,而且梯度信息都得以保留。
二、基于python的算法实现
因为在图像灰度化的过程都是要对图像进行扫描,至于值的确定,我们可以单独用一个函数来得到,所以把扫描过程独立起来,值的获取独立起来。我们单独使用一个Values()
方法来得到我们所需要的灰度值,参数就是一个含R、G、B值的列表
方法整体很简单,就几行代码。只要把各种计算灰度值的公式用上就行了。剩下的全交给扫描函数就行了
下面就是一个用来处理BMP图像文件的类,将前一节文章里的代码集成起来,可以用来读取8位伪彩色图、24位真彩色图
class BmpManager:
def __init__(self,fileName):
self.f_size=None
self.f_width=None
self.f_height=None
self.f_ofset=None
self.f_bitcount=None
self.colorTab=None
self.Img=None
def Parse(self,fileName):
f=open(fileName,'rb')
file_type=str(f.read(2),encoding='utf-8')
assert file_type=='BM',"文件类型错误"
file_size_byte = f.read(4) # 这个可以用来读取文件的大小 需要读取4个字节
f.seek(f.tell() + 4) # 跳过中间无用的四个字节
file_ofset_byte = f.read(4) # 读取位图数据的偏移量
f.seek(f.tell() + 4) # 跳过无用的两个字节
file_wide_byte = f.read(4) # 读取宽度字节
file_height_byte = f.read(4) # 读取高度字节
f.seek(f.tell() + 2) ## 跳过中间无用的两个字节
file_bitcount_byte = f.read(4) # 得到每个像素占位大小
#下面就是将读取的字节转换成指定的类型
self.f_size,=struct.unpack('l',file_size_byte)
self.f_ofset,=struct.unpack('l',file_ofset_byte)
self.f_width,=struct.unpack('l',file_wide_byte)
self.f_height,=struct.unpack('l',file_height_byte)
self.f_bitcount,=struct.unpack('i',file_bitcount_byte)
# 判断是否有颜色表
if self.f_ofset==1078:
self.__256Image__(fileName)#处理伪彩色图像
else:
self.__24BImage(fileName) #处理真彩色图像
def __256Image__(self,f_name):
'然后来读取颜色表'
f=open(f_name,'rb')
self.colorTab = np.array([],dtype=int)
f.seek(54) # 跳过文件信息头和位图信息头
for i in range(0, 256):
b = struct.unpack('B', f.read(1))[0]
g = struct.unpack('B', f.read(1))[0]
r = struct.unpack('B', f.read(1))[0]
alpha = struct.unpack('B', f.read(1))[0]
self.colorTab=np.append(self.colorTab,np.array([r,g,b,255]))
self.colorTab=self.colorTab.reshape(256,4)
'下面部分用来读取BMP位图数据区域,将数据存入numpy数组'
# 首先对文件指针进行偏移
f.seek(self.f_ofset)
# 因为图像是8位伪彩色图像,所以一个像素点占一个字节,即8位
img = np.empty(shape=[self.f_height, self.f_width, 4], dtype=int)
cout = 0
for y in range(0, self.f_height):
for x in range(0, self.f_width):
cout = cout + 1
index = struct.unpack('B', f.read(1))[0]
img[self.f_height - y - 1, x] = self.colorTab[index]
while cout % 4 != 0:
f.read(1)
cout = cout + 1
self.Img=img
def __24BImage(self,f_name):
f=open(f_name,'rb')
f.seek(self.f_ofset)
img=np.empty(shape=[self.f_height,self.f_width,3],dtype=int)
cout=0
for y in range(0,self.f_height):
for x in range(0,self.f_width):
BYTES=f.read(3)
x1,x2,x3=struct.unpack('BBB',BYTES)
cout=cout+3
img[self.f_height - y - 1, x]=np.array([x3,x2,x1])
while cout%4!=0:
cout=cout+1
f.read(1)
self.Img=img
def getHeight(self):
return self.f_height
def getWidth(self):
return self.f_width
def getImage(self):
return self.Img
def getSize(self):
return self.f_size
def grayScale(self,method='AVG'):
#下面对图像进行扫描
for y in range(0,self.f_height):
for x in range(0,self.f_width):
value=self.Values(method,self.Img[y][x])
self.Img[y][x]=np.array([value,value,value])
def Values(self,methods,v):
if methods=='AVG':
return np.average(v)
if methods=='R':
return v[0]
if methods=='G':
return v[1]
if methods=='B':
return v[2]
if methods=='Max':
return np.max(v)
if methods=='WAvg':
return 0.3*v[0]+0.59*v[1]+0.11*v[2]