There are several ways in python to generate a greyscale image from an RGB version. One of those is just to read an image as greyscale using OpenCV.
im = cv2.imread(img, 0)
While 0
equals cv2.IMREAD_GRAYSCALE
There are many different algorithms to handle this operation well explained here.
I'm wondering how OpenCV handles this task and which algorithm stands behind cv2.IMREAD_GRAYSCALE
but could neither find any documentation nor reference. Does someone have any idea? A paper reference would be great.
Thanks in advance
ps I'm working with jpg and png.
I think basically @Dan Mašek already answered the question in the comment section.
I will try to summarize the findings for jpg files as an answer and I am glad about any improvements.
If you want to convert your jpg file from CMYK we have to look into grfmt_jpeg.cpp . There exist other files like this for different image codes. Depending on the numbers of color channels cinfo
is assigned. For CMYK images the cinfo
is set to 4
and the function on line 504 icvCvt_CMYK2Gray_8u_C4C1R
is called.
This function can be found in 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;
}
}
and uses fixed variables for the conversion:
#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)
If your image only contains three color channels it seems that libjpeg is used for the conversion. This can be seen in line 717 . (I am not 100% sure if this is the correct line).
In jdcolor.c it can be seen that there a definitions and standards for converting color channels starting from line 41 .
The most important part for your specific question is:
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
which relate to standards of the ITU-R and are used in many other sources I found. More detailed information can be found here and here .
The second source relating to a StackOverflow question makes it clear that the conversion does not only depend on the pure RGB values but also on other parameters as gamma value.
in OpenCV documentation you can find:
IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
Also
When using IMREAD_GRAYSCALE, the codec's internal grayscale conversion will be used, if available. Results may differ to the output of cvtColor()
So it depends on codec's internal grayscale conversion.
More Info: from OpenCV documentation
When using IMREAD_GRAYSCALE, the codec's internal grayscale conversion will be used, if available. Results may differ to the output of cvtColor() On Microsoft Windows* OS and MacOSX*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default. So, OpenCV can always read JPEGs, PNGs, and TIFFs. On MacOSX, there is also an option to use native MacOSX image readers. But beware that currently these native image loaders give images with different pixel values because of the color management embedded into MacOSX. On Linux*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, "libjpeg-dev", in Debian* and Ubuntu*) to get the codec support or turn on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.