图像的灰度化及用python实现

一、灰度化

灰度化定义

在R、G、B图像模型中,当R=G=B(三种颜色分量值相同时),则此时彩色表示一种灰度颜色,其中R=G=B的值叫做灰度值,在灰度图像中,灰度值也可以称为亮度值。灰度值范围0-255

灰度化的方法

对于一副彩色图像来说,灰度化一般有四种常用方法,分别为分量法 最大值法 平均值法 加权平均法

1.分量法

该方法最为简单,即在R、G、B三种颜色分量中,任意选取一种颜色作为灰度值

2.最大值法

该方法是先找出每个像素R、G、B三种颜色分量的值,然后找到值最大的那个颜色,然后以此最大值作为灰度值
f ( x , y ) = M a x { R ( x , y ) , G ( x , y ) , B ( x , y ) } f(x,y)=Max\left \{ R(x,y),G(x,y),B(x,y)\right \}

3.平均值法

该方法是先找到像素的R、G、B三种颜色的分量值,最后置灰度值为三个分量值的平均值即可。
f ( x , y ) = R ( x , y ) + G ( x , y ) + B ( x , y ) 3 f(x,y)=\frac{R(x,y)+G(x,y)+B(x,y)}{3}

4.加权平均法

因为人眼对每种颜色的敏感度不同,其中人眼对绿色敏感度最高,蓝色敏感度最低,所以我们可以使用加权平均的方法来求灰度值,公式如下

f ( x , y ) = a i R ( i , j ) + b i G ( i , j ) + c i B ( i , j ) f(x,y)=a_iR(i,j)+b_iG(i,j)+c_iB(i,j)

灰度化应用场景
  1. 计算机通过图像识别物体的时候,最关键的因素是图像的梯度,有了梯度我们才可以找到物体边缘,才能对物体进行定位。然而梯度计算必须要用到灰度图像,彩色图像非常容易受到光照等因素的影响,同类的物体颜色也有很多变化,所以彩色图像是很难提供一些关键信息的
  2. 图像进行灰度化之后,矩阵的维数降低,所以运算速度会大幅度提高,而且梯度信息都得以保留。

二、基于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]

最终运行结果

原图

在这里插入图片描述

加权平均法在这里插入图片描述
发布了2 篇原创文章 · 获赞 0 · 访问量 79

猜你喜欢

转载自blog.csdn.net/qq_43409114/article/details/104558032