当给定 IMREAD_GRAYSCALE 时,imread() 会做什么?为什么这与 cvtColor() 不同?

问题描述 投票:0回答:2

Python 有多种方法可以从 RGB 版本生成灰度图像。其中之一就是使用 OpenCV 将图像读取为灰度。

im = cv2.imread(path, cv2.IMREAD_GRAYSCALE)

有许多不同的算法来处理此操作这里有很好的解释。

我想知道 OpenCV 如何处理这个任务以及哪种算法支持

cv2.IMREAD_GRAYSCALE
,但找不到任何文档或参考。有人有什么想法吗?纸质参考文献会很棒。

提前致谢

附注我正在处理 jpg 和 png。

algorithm opencv image-processing grayscale imread
2个回答
1
投票

在 OpenCV 文档中你可以找到:

IMREAD_GRAYSCALE = 0,  //!< If set, always convert image to the single channel grayscale image (codec internal conversion).

还有

使用IMREAD_GRAYSCALE时,编解码器内部的灰度转换 如果可用的话将被使用。 结果可能与 cvtColor() 的输出不同

所以这取决于编解码器内部的灰度转换。

更多信息:来自 OpenCV 文档

使用 IMREAD_GRAYSCALE 时,将使用编解码器的内部灰度转换(如果可用)。结果可能与 cvtColor() 的输出不同 在 Microsoft Windows* 操作系统和 MacOSX* 上,默认使用 OpenCV 图像附带的编解码器(libjpeg、libpng、libtiff 和 libjasper)。因此,OpenCV 始终可以读取 JPEG、PNG 和 TIFF。在 MacOSX 上,还可以选择使用本机 MacOSX 图像读取器。但请注意,由于 MacOSX 中嵌入了颜色管理,目前这些本机图像加载器会提供具有不同像素值的图像。 在 Linux*、BSD 版本和其他类 Unix 开源操作系统上,OpenCV 会寻找操作系统映像提供的编解码器。安装相关软件包(不要忘记开发文件,例如 Debian* 和 Ubuntu* 中的“libjpeg-dev”)以获得编解码器支持或在 CMake 中打开 OPENCV_BUILD_3RDPARTY_LIBS 标志。


1
投票

我认为基本上 @Dan Mašek 已经在评论部分回答了问题。
我将尝试总结 jpg 文件的发现作为答案,我很高兴看到任何改进。

CMYK 转灰度

如果您想从 CMYK 转换 jpg 文件,我们必须查看 grfmt_jpeg.cpp。对于不同的图像代码,还存在其他类似的文件。 根据颜色通道的数量分配

cinfo
。对于 CMYK 图像,
cinfo
设置为
4
,并调用 第 504 行
icvCvt_CMYK2Gray_8u_C4C1R
上的函数。
这个函数可以在utils.cpp中找到:

void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* cmyk, int cmyk_step,
                                uchar* gray, int gray_step, Size size )
{
    int i;
    for( ; size.height--; )
    {
        for( i = 0; i < size.width; i++, cmyk += 4 )
        {
            int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
            c = k - ((255 - c)*k>>8);
            m = k - ((255 - m)*k>>8);
            y = k - ((255 - y)*k>>8);
            int t = descale( y*cB + m*cG + c*cR, SCALE );
            gray[i] = (uchar)t;
        }
        gray += gray_step;
        cmyk += cmyk_step - size.width*4;
    }
}

并使用固定变量进行转换:

#define  SCALE  14
#define  cR  (int)(0.299*(1 << SCALE) + 0.5)
#define  cG  (int)(0.587*(1 << SCALE) + 0.5)
#define  cB  ((1 << SCALE) - cR - cG)

RGB/BGR 转灰度

如果您的图像仅包含三个颜色通道,则似乎使用 libjpeg 进行转换。这可以在第 717 行中看到。 (我不能 100% 确定这是否是正确的行)。

jdcolor.c中可以看到,从第41行开始有转换颜色通道的定义和标准。

您的具体问题最重要的部分是:

the conversion equations to be implemented are therefore
R = Y + 1.402 * Cr
G = Y - 0.344136286 * Cb - 0.714136286 * Cr
B = Y + 1.772 * Cb
Y = 0.299 * R + 0.587 * G + 0.114 * B

ITU-R 标准相关,并在我发现的许多其他来源中使用。 更详细的信息可以在这里这里找到。

与 StackOverflow 问题相关的第二个来源清楚地表明,转换不仅取决于纯 RGB 值,还取决于其他参数(如伽玛值)。

OpenCV 使用的标准似乎是 Rec。 601.

© www.soinside.com 2019 - 2024. All rights reserved.