目录
一、什么是图像的灰度化?
二、灰度化的几种方法(最大值法、平均值法、加权均值法、gamma校正)
1、直接调用函数:cv2.cvtColor() 图像颜色空间转换
2、最大值法
(1)概念
(2)代码
(3)结果
3、平均值法
(1)概念
(2)“RuntimeWarning: overflow encountered in ubyte_scalars”问题的解决
(3)代码
(4)结果
4、加权均值法
(1)概念
(2)代码
(3)结果
5、gamma校正
(1)概念
(2)代码
(3)结果
三、不同方法之间的比较
四、疑问:怎么利用Python创建一个空的初始化图像?(np.unit8的应用)
1、关键代码
2、图像展示
3、得到灰度图像矩阵对比
4、利用opencv创建图像参考代码(彩色和灰色均有)
首先我们知道一张图片的所有颜色都可以通过RGB值调节进行表示,如果是一张彩色图片则RBG值不一定相同,将彩色图片灰度化就是指的是将彩色图片变成黑白的,这时候的RBG三个通道的值是相同的,就是将一幅色彩图像转化为灰度图像的过程。
彩色图像分为R,G,B三个分量,分别显示出红绿蓝等各种颜色,灰度化就是使彩色的R,G,B分量相等的过程。灰度值大的像素点比较亮(像素值最大为255,为白色),反之比较暗(像素最下为0,为黑色)这个过程就是指灰度化,具体可见:《百度百科》
对图像灰度化便于后续对图像的特征进行提取,以及得到图像的灰度曲线图
这里以上述经典图片为例进行灰度化处理
img2 = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #灰度化:彩色图像转为灰度图像
img3 = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB) #彩色化:灰度图像转为彩色图像
# cv2.COLOR_X2Y,其中X,Y = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS
opencv自带的一个函数可以将彩色转化为灰色,通过颜色空间的转换来得到灰度化后的图片
import cv2
def gray_cvt(inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_cvt_image = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)#灰度化
cv2.namedWindow(windowname) # 这行没啥用 控制显示图片窗口的名字
cv2.imshow(windowname, gray_cvt_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_cvt_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
inputimagepath="colorful_lena.jpg"
windowname='gray_cvt'
outimagepath="gray_cvt.jpg"
gray_cvt(inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
返回的是一个(200,200)的图像,是一个二维数组,这里的元素值就是B=G=R值
直接调用函数cv2.cvt灰度化后的R,G,B得值等于转化前3个值中最大的一个,即:
R=G=B=max(R,G,B)
import cv2
def gray_max_rgb(inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)#读取图像,返回的是一个装有每一个像素点的bgr值的三维矩阵
gray_max_rgb_image = img.copy()#复制图像,用于后面保存灰度化后的图像bgr值矩阵
img_shape = img.shape#返回一位数组(高,宽,3)获得原始图像的长宽以及颜色通道数,一般彩色的颜色通道为3,黑白为1
for i in range(img_shape[0]):#按行读取图片的像素bgr
for j in range(img_shape[1]):#对每一行按照列进行每一个像素格子进行读取
gray_max_rgb_image[i,j] = max(img[i,j][0],img[i,j][1],img[i,j][2])#求灰度值
print(gray_max_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_max_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_max_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
inputimagepath = "colorful_lena.jpg"
windowname = "gray_max_rgb"
outimagepath = "gray_max_rgb.jpg"
gray_max_rgb(inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
返回的是一个三维矩阵,只是第三维比较特殊,三个元素都是一样的,即R=B=G
print(gray_max_rgb_image)#取最后一维的第一组数据作为参考
最大值法
灰度化后R,G,B的值为转化前R,G,B的平均值。即:
R=G=B=(R+G+B)/3
这个表明像素值在进行加减操作后出现了像素值的溢出现象,即像素值的值为0-255,如果小于0或者大于255就会出现这种错误,这种情况也可以得到一个转换后的图像但是图片却失真了
RuntimeWarning: overflow encountered in ubyte_scalars gray_mean_rgb_image[i,j] = (img[i,j][0]+img[i,j][1]+img[i,j][2])/3
解决这种方法就是在进行像素的加减操作前将像素进行强制取整操作即可
gray_mean_rgb_image[i,j] = (int(img[i,j][0])+int(img[i,j][1])+int(img[i,j][2]))/3
#平均值法进行图像灰度化
import cv2
def gray_mean_rgb(inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_mean_rgb_image = img.copy()
img_shape = img.shape
for i in range(img_shape[0]):
for j in range(img_shape[1]):
gray_mean_rgb_image[i,j] = (int(img[i,j][0])+int(img[i,j][1])+int(img[i,j][2]))/3
print(gray_mean_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_mean_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_mean_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
inputimagepath = "colorful_lena.jpg"
windowname = "gray_mean_rgb"
outimagepath = "gray_mean_rgb.jpg"
gray_mean_rgb(inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
print(gray_mean_rgb_image)#取最后一维的第一组数据作为参考
平均值法
灰度化后按照一定权值,对R,G,B的值加权平均,即:
分别为R,G,B的权值,取不同的值形成不同的灰度图像。由于人眼对绿色最为敏感,红色次之,对蓝色的敏感性最低,因此使将得到较易识别的灰度图像。一般时,得到的灰度图像效果最好
注:一般权重有两套值供选择
Gray= 0.072169B+ 0.715160G+ 0.212671R
Gray= 0.11B+ 0.59G+ 0.3R
前一种是OpenCV开放库所采用的灰度权值,后一种为从人体生理学角度所提出的一种权值(人眼对绿色的敏感最高,对蓝色敏感最低)
#加权均值法进行图像灰度化
import cv2
def gray_weightmean_rgb(wr,wg,wb,inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_weightmean_rgb_image = img.copy()
img_shape = img.shape
for i in range(img_shape[0]):
for j in range(img_shape[1]):
gray_weightmean_rgb_image[i,j] = (int(wr*img[i,j][2])+int(wg*img[i,j][1])+int(wb*img[i,j][0]))/3
print(gray_weightmean_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_weightmean_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_weightmean_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
wr = 0.299
wg = 0.587
wb = 0.114
inputimagepath = "colorful_lena.jpg"
windowname = "gray_weightmean_rgb"
outimagepath = "gray_weightmean_rgb.jpg"
gray_weightmean_rgb(wr,wg,wb,inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
print(gray_weightmean_rgb_image)#取最后一维的第一组数据作为参考
加权均值法
#gamma校正加权均值进行图像灰度化
import cv2
def gray_gamma_weightmean_rgb(wr,wg,wb,gamma,inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_gamma_weightmean_rgb_image = img.copy()
img_shape = img.shape
for i in range(img_shape[0]):
for j in range(img_shape[1]):
fenzi = int((wr*img[i,j][2])**gamma)+int((wg*img[i,j][1])**gamma)+int((wb*img[i,j][0])**gamma)
fenmu = wr**gamma + wg**gamma + wb**gamma
gray_gamma_weightmean_rgb_image[i,j] = int((fenzi/fenmu)**(1/gamma))
print(gray_gamma_weightmean_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_gamma_weightmean_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_gamma_weightmean_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
wr = 1
wg = 1.5
wb = 0.6
gamma = 2.2
inputimagepath = "colorful_lena.jpg"
windowname = "gray_gamma_weightmean_rgb"
outimagepath = "gray_gamma_weightmean_rgb.jpg"
gray_gamma_weightmean_rgb(wr,wg,wb,gamma,inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
print(gray_gamma_weightmean_rgb_image)#取最后一维的第一组数据作为参考
gamma修正法
由上图进行各个灰度化结果比较可以清晰的看出:
1、最大值法灰度化后图像过于亮,丢失的图像细节较多,常用于对原本色调较暗的图像进行处理
2、加权平均值法灰度化后过于暗,不易于进行目标对象与背景区域的区分,常用于对原本色调较亮的图像进行处理
3、直接调用函数进行灰度化颜色依旧偏暗
4、gamma修正灰度化的效果很好,但是gamma修正法的系数太多,而且设计到了指数以及开方运算,运算时间长,对于大量图片的处理更是不适用,对设备的要求非常高
5、均值的效果跟gamma修正法差不多,可能不及gamma修正法,但是其方法计算便捷,且结果较佳
因此一般使用均值法进行图片的灰度处理
《如何利用numpy创建全0,全1,随机矩阵》
在上述的灰度化中,灰度化后得到的图像矩阵均为三维的矩阵,只是最后一维的3个元素是相同的,但是实际上灰色图片的像素值矩阵只需要两个维度就可以进行完全地表达,即只需要装一个灰度值就可以了,这时候就可以通过numpy先创建一个合适尺寸的数组,然后将灰度化后的值去覆盖定义的数组即可,注意一点:通过numpy创建数组后,必须要将生成数组的格式转换为uint8(无符号8位整形)格式,否则应用cv2.imshow时图像不能显示,通过np.uint8来指定创建数组的元素的数据类型
gray_max_rgb_image = np.zeros((img_shape[0], img_shape[1]), np.uint8)
这里以最大值法为例:
# gray_max_rgb_image = img.copy()#复制图像,用于后面保存灰度化后的图像bgr值矩阵
img_shape = img.shape#返回一位数组(高,宽,3)获得原始图像的长宽以及颜色通道数,一般彩色的颜色通道为3,黑白为1
gray_max_rgb_image = np.zeros((img_shape[0], img_shape[1]), np.uint8)#创建一个与原始图像大小一致的图像,初始值为0,即为黑色
cv2.imshow('',gray_max_rgb_image)#这里得到的是一个与原始图像一样大小的黑色初始图像
for i in range(img_shape[0]):#按行读取图片的像素bgr
for j in range(img_shape[1]):#对每一行按照列进行每一个像素格子进行读取
gray_max_rgb_image[i,j] = max(img[i,j][0],img[i,j][1],img[i,j][2])#求灰度值
cv2.imshow('',gray_max_rgb_image)#这里得到的是灰度化后的图像
创建的图像:
创建的图像灰度化后的图像:
最大值法利用原始图像的矩阵shape进行的灰度化的图像矩阵,shape为(200,200,3),且可以看到最后一维三个数值是一样的,即RGB值均相等。
利用创建的数组进行灰度化的图像矩阵,shape为(200,200),这里只保留了一个灰度值
import cv2 as cv
import numpy as np
def creat_image():
'''
#创建RGB图像
image = np.zeros([400,400,3],np.uint8) #初始图片黑色
#修改第一个通道的值
image[:,:,0] = np.ones([400,400])*255 #输出蓝色的图 第一通道是blue
# 修改第二个通道的值
image[:, :, 1] = np.ones([400, 400]) * 255
cv.imshow("new_image",image)
'''
#创建单通道图像 灰度图像
image = np.zeros([400, 400,1], np.uint8)
image[:,:,0] = np.ones([400,400])*127
cv.imshow("new_image", image)
import cv2 as cv
t1 = cv.getTickCount() #获取时间
creat_image()
t2 = cv.getTickCount()
time = (t2-t1)/cv.getTickCount()
print("time:%s ms"%(time*1000)) #花了多长时间 mS
cv.waitKey(0)
#释放窗口
cv.destroyAllWindows()