Python | Grayscaling of Images using OpenCV
Grayscaling is the process of converting an image from other color spaces e.g. RGB, CMYK, HSV, etc. to shades of gray. It varies between complete black and complete white.
Importance of grayscaling
- Fewer dimensions: RGB images have three channels, while grayscale images have only one.
- Simpler models: Less input data reduces complexity and speeds up training.
- Algorithm-ready: Some methods, such as Canny edge detection, work only on grayscale images.
Let's learn the different image processing methods to convert a colored image into a grayscale image.
Method 1: Using the cv2.cvtColor() function
import cv2
image = cv2.imread('C:\\Documents\\full_path\\tomatoes.jpg')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow('Grayscale', gray_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Input:

Output:

Explanation:
- cv2.imread(): Reads the image file (OpenCV loads color images as BGR by default).
- cv2.cvtColor(): Converts color spaces; cv2.COLOR_BGR2GRAY produces a single-channel grayscale image.
- cv2.imshow(): Opens a window to display the image.
Method 2: Using the cv2.imread() function with flag=zero
In this method, we can directly load an image in grayscale mode by passing the flag 0 to cv2.imread(). This saves us from having to convert the image separately after loading.
import cv2
img = cv2.imread('C:\\Documents\\full_path\\tomatoes.jpg', 0)
cv2.imshow('Grayscale Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output
Explanation:
- cv2.imread(path, 0): Reads the image directly in grayscale (single-channel).
- cv2.imshow(): Displays the single-channel image.
- cv2.waitKey() / cv2.destroyAllWindows(): Controls display lifetime.
Method 3.1 Weighted Method (Recommended)
This method uses standard luminance weights (0.2989R + 0.5870G + 0.1140B) to account for human visual sensitivity—more to green, less to red, least to blue. It produces a more realistic and visually accurate grayscale image.
import cv2
img_weighted = cv2.imread('C:\\Documents\\full_path\\tomatoes.jpg')
rows, cols = img_weighted.shape[:2]
for i in range(rows):
for j in range(cols):
gray = 0.2989 * img_weighted[i, j][2] + 0.5870 * img_weighted[i, j][1] + 0.1140 * img_weighted[i, j][0]
img_weighted[i, j] = [gray, gray, gray]
cv2.imshow('Grayscale Image (Weighted)', img_weighted)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output

Explanation:
- rows, cols = img_weighted.shape[:2]: extracts image height (rows) and width (cols) from the shape.
- Nested for loops are used to iterate over every pixel in the image.
- Weighted formula: Gray = 0.2989*R + 0.5870*G + 0.1140*B (indices: R=[2], G=[1], B=[0] in OpenCV).
- Assigning [gray, gray, gray] preserves a 3-channel image for display.
- This produces visually more accurate grayscale than simple averaging, but is still slower than OpenCV’s native conversions.
Method 3.2: Using the pixel manipulation (Average method)
This method converts an image to grayscale by averaging the contributions of color channels (RGB). It’s a simple approach but not very accurate because it treats all colors equally, ignoring how the human eye perceives brightness.
import cv2
img = cv2.imread('C:\\Documents\\full_path\\tomatoes.jpg')
rows, cols = img.shape[:2]
for i in range(rows):
for j in range(cols):
gray = (img[i, j, 0] + img[i, j, 1] + img[i, j, 2]) / 3
img[i, j] = [gray, gray, gray]
cv2.imshow('Grayscale Image (Average)', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output
Explanation:
- rows, cols = img.shape[:2]: extracts image height (rows) and width (cols) from the shape.
- Nested loops for i in range(rows): for j in range(cols): iterate over every pixel row (y) then column (x).
- img[i, j, 0], img[i, j, 1], img[i, j, 2] correspond to B, G, R respectively (OpenCV uses BGR order).
- gray = (B+G+R)/3 computes the average intensity; assigning [gray, gray, gray] writes the value into all three channels (keeps a 3-channel image for display).
Note: This method is simple but less accurate (human eye weights colors unequally) and slow in Python due to per-pixel loops.