在OpenCV(Python)中,为什么从灰度图像获取到的是3通道图像?

61

我正在使用Ubuntu 12.04上的Python (2.7)和OpenCV 2.4.6绑定。

我加载了一张图片。

    image = cv2.imread('image.jpg')

我随后检查图像数组的形状。

    print image.shape

我得到的是 (480, 640, 3) 的数据,这符合一张 640x480 的彩色图像的预期。然后我将图像转换成灰度图像并再次检查其形状。

    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    print gray_image.shape

我得到了(480,640,1)的结果,这正是我期望的640x480 灰度图像。然后我保存了该图像:

    cv2.imwrite('gray.jpg', gray_image)

我在使用Linux系统,尝试使用gThumb查看该图像,以显示所有颜色通道。然后将灰度图像导入OpenCV后,该图像再次具有三个通道。

我知道可以使用一个标志来读取图像:

    CV_LOAD_IMAGE_GRAYSCALE - If set, always convert image to the grayscale one

但是这听起来好像会将图像作为彩色图像导入,然后再进行转换。我正在将这个项目移植到树莓派上,所以不希望发生不必要的操作。

编辑:我进行了一些时间检查,发现使用CV_LOAD_IMAGE_GRAYSCALE标志设置加载图像可以使图像加载速度快两倍,不论输入的图像如何。

     Using a 3072 x 4608 x 3 image
     0.196774959564 seconds with default loading
     0.0931899547577 seconds with CV_LOAD_IMAGE_GRAYSCALE

问题似乎是OpenCV会创建一个三通道的JPG输出,而不管我是否有灰度图像矩阵!

有哪些其他应用程序可以确保我获取单个8位通道的JPG图像?(也许gThumb错误地报告了通道)。

如果图像不是单通道的,为什么OpenCV要将我的灰度图像保存为一个三通道图像在磁盘写入时?

4个回答

82

你的代码是正确的,似乎 cv2.imread 加载的图像有三个通道,除非设置了CV_LOAD_IMAGE_GRAYSCALE

>>> import cv2
>>> image = cv2.imread('foo.jpg')
>>> print image.shape
 (184, 300, 3)
>>> gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
>>> print gray_image.shape 
 (184, 300)
>>> cv2.imwrite('gray.jpg', gray_image)

现在,如果您加载图像:

>>> image = cv2.imread('gray.jpg')
>>> print image.shape
 (184, 300, 3)

看起来你已经将图像保存为BGR格式,但实际上并非如此,这只是OpenCV默认以3通道读取图像,在灰度图像的情况下,它会将其图层复制三次。如果你用Scipy重新加载该图像,则可以看到该图像确实是灰度图像:

>>> from scipy.ndimage import imread
>>> image2 = imread('gray.jpg')
>>> print image2.shape
 (184, 300)

如果您想加载灰度图像,则需要设置CV_LOAD_IMAGE_GRAYSCALE标志:

>>> image = cv2.imread('gray.jpg', cv2.CV_LOAD_IMAGE_GRAYSCALE)
>>> print image.shape
 (184, 300)

谢谢,看起来gThumb也会复制图层。 - Steve
2
说了这么多,那么如果我们需要将图像保存为单通道格式,有什么解决方案呢? - Saman
38
现在看来,cv2.IMREAD_GRAYSCALE似乎是更好的选择,而不是cv2.CV_LOAD_IMAGE_GRAYSCALE。 - jeremy_rutman
7
此外,我认为每次使用 cv2.IMREAD_UNCHANGED 都是相当安全的。 - Gall
1
对于使用 jupytermatplotlib 的任何人而言,这个 让我免于精神崩溃. 特别是,即使是灰度图像,plt.imshow() 仍然使用颜色来增强对比度。请使用 plt.imshow(img, cmap='Greys_r') 来覆盖默认设置。 - Hendy
显示剩余3条评论

21

试一下:

 img = cv2.imread('gray.jpg',0)

0代表灰色,1代表彩色


1
那仍然可以让你获得3个频道。 - Oeyvind
1
@Oeyvind,不,它只会给你一个通道,即使最初PNG有3个通道。 - apatsekin

4
如果您想在使用OpenCV加载图像时保留原始通道数量(正如@Gall在评论中已经提到的那样):
img_np = cv2.imread("path/to_img", cv2.IMREAD_UNCHANGED)

cv2.IMREAD_GRAYSCALE - 将所有图像转换为灰度。

如果您还想保留原始的深度(即int16),而不是隐式的int8转换(默认情况下):

img_np = cv2.imread(image_path, cv2.IMREAD_ANYDEPTH | cv2.IMREAD_UNCHANGED)

3

在openCV中,默认情况下读取jpg图像会得到3通道的图像。因此,我不确定您是否可以从jpg文件中看到它已经是灰度图像,但您始终可以将其加载为灰度图像。只有在图像未先转换为灰度图像的情况下才会出现问题,对于您的情况,我认为这种方法行不通。简而言之:您不能将jpg保存为单通道图像。因此,在读取后,您需要再次将其转换为灰度图像或找到一种新方法来确定图像是否为灰度图像。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接