Search code examples
pythonpython-3.xpython-imaging-libraryscikit-imageopencv

Converting image to grayscale


I want to convert any image to grayscale, but I don't understand the difference between these implementations.

image = cv2.imread('lenna.jpg')
gray = cv2.cvtColor(image, cv2.IMREAD_GRAYSCALE)

gray1 = rgb2gray(image)

gray2 = cv2.imread('lenna.jpg', cv2.IMREAD_GRAYSCALE)

image1 = Image.open('lenna.jpg', 'r')
gray3 = image1.convert('L')

When I plot them, I get them in blue scale, green scale, green scale and gray respectively. When I should use each one?


Solution

  • You've encountered a spot where Python's type system isn't protecting you in the way that C++ would.

    cv2.IMREAD_GRAYSCALE and cv2.COLOR_BGR2GRAY are values from different enumerations. The former, whose numerical value is 0, applies to cv2.imread(). The latter, whose numerical value is 6, applies to cv2.cvtColor(). C++ would have told you that cv2.IMREAD_GRAYSCALE can't be passed to cv2.cvtColor(). Python quietly accepts the corresponding int value.

    Thus, you think you're asking cv2 to convert a color image to gray, but by passing cv2.IMREAD_GRAYSCALE, cv2.cvtColor() sees the value 0, and thinks you're passing cv2.COLOR_BGR2BGRA. Instead of a grayscale image, you get the original image with an alpha channel added.

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    

    is what you need instead.

    The other issue you're seeing, assuming you're using a Jupyter notebook, is that cv2 layers color planes in BGR order instead of RGB. To display them properly, first do

    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    

    and then display the result.