OpenCV彩色图与灰度图互相转换

OpenCV彩色图与灰度图互相转换

256256 OpenCV可以将彩色图转换成灰度图,这不难理解。但是OpenCV能将灰度图转换成彩色图,这也太厉害了吧。想象一下,将图1中的灰度图输入进去,出来的竟然是图2这种的彩色图,也太不可思议了,可事实是我想多了。

图1 lena_gray
图2 lena_rgb

首先看看彩色图是怎么转换成灰度图的,先读入照片

import cv2
import numpy as np
img_rgb = cv2.imread(r'..\image\lena_rgb.jpg')

这里采用了三种方式将RGB图像装换成灰度图。第一种是根据公式GRAY=0.3*R+0.59*G+0.11*B:

#第一种 GRAY=0.3*R+0.59*G+0.11*B
img_gray = img_rgb[:,:,0] * 0.11 + img_rgb[:,:,1] * 0.59 + img_rgb[:,:,2] * 0.3
img_gray = img_gray.astype(np.uint8)
#只有当数组类型为uint8时,opencv才会认为这是图片

效果如下:

第二种是对每个通道求均值:

#第二种  GRAY=(R+G+B)/3
img_gray2 = (img_rgb[:,:,0] + img_rgb[:,:,1]  + img_rgb[:,:,2]) / 3
img_gray2 = img_gray2.astype(np.uint8)

效果如下:

可见效果并不好

第二种是取每个通道上的最大值:

#第三种 max(R,G,B)
img_gray3 = np.zeros((256,256))
for i in range(0,256):
    for j in range(0,256):
        img_gray3[i][j] = np.max((img_rgb[:,:,0][i][j], img_rgb[:,:,1][i][j], img_rgb[:,:,2][i][j]))
img_gray3 = img_gray3.astype(np.uint8)

效果如下:

可以看出,图片有点偏亮了,毕竟是选取的最大值

再来看看OpenCV是怎么转换的:

img_gray4 = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

效果如下:

看起来跟第一种GRAY=0.3*R+0.59*G+0.11*B的结果挺像的,来看看是不是这样实现的:

#两者相减,看值是否为0
sub = img_gray4 - img_gray
count, count1 = 0, 0
for i in range(sub.shape[0]):
    for j in range(sub.shape[1]):
        if(sub[i][j] == 0):
            count += 1
        elif(sub[i][j] == 1):
            count1 += 1

图片的尺寸为256*256,因此sub也为256*256,共有65536个点,sub中的零值共38599个,值为1的共有26937个,加起来刚好是65536,也验证了OpenCV使用的这种转换方式,可能在计算精度上有点区别。

接下来就看看OpenCV是怎么讲灰度图转换成彩色图的,首先读入一张灰度图(就是刚刚保存的),注意应设置flags为0,代表输入的是灰度图。

img_gray = cv2.imread(r'..\image\gray4.jpg', flags = 0)

然后将其转化成彩色图:

img2 = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)

img2显示如下:

是的,你没有看错,这就是转化后的彩色图,果然事实跟想象还是有差异的。接下来就分析下为什么是这个样子。先打印img2的shape看看,确保这是彩色图

print(img2.shape)

输出(256, 256, 3),可以确定这就是彩色图了。那它是如何转化的呢,我一开始的想法是:这应该是一个查表的操作,灰度图中的0-255每一个值都对应三个(R,G,B)的值,对应关系可以由某个公式计算出来。事实比这个还简单。我将每一个通道的值都跟原始灰度图做差,来看看结果如何。

sub1 = img2[:, :, 0] - img_gray
sub2 = img2[:, :, 1] - img_gray
sub3 = img2[:, :, 2] - img_gray
#判断sub中的每个值是不是都等于0
print((sub1 == 0).all())
print((sub2 == 0).all())
print((sub3 == 0).all())

输出的是True True True。很明显OpenCV就是把灰度图复制了三遍,分别赋值R,G,B三个通道。

那应该怎么理解呢,其实R,G,B三个通道上的值相等时,所呈现的颜色就是灰色(很容易验证),只有亮跟暗的区别,值越大就越亮,越小就越暗。也就是从灰度图中的亮度变成了彩色图中的灰色了。所以使用这个函数将灰度图转换成彩色图时,如果出现的还是黑白图,不要觉得是程序出错了。

(占个坑)将灰度图转换成五颜六色的彩色图可能需要深度学习来实现了,有机会再写。

编辑于 2019-07-11 22:16