Computer vision

Color Spaces

The same colour can be written as different sets of numbers. Picking the right set makes a task easy.

What are colour spaces?

A colour space is a mathematical model for representing colours as numbers.

Why several? Different tasks need different representations.

RGB / BGR

Red, Green, Blue. Device-dependent.

Best for storage and transmission.

HSV

Hue, Saturation, Value. Perceptually intuitive.

Best for colour segmentation.

LAB

Lightness, A (green–red), B (blue–yellow).

Perceptually uniform.

RGB vs BGR

RGB
RGB
BGR
BGR

COLOR_BGR2RGB swaps B and R

RGB is standard in most libraries. BGR is OpenCV's default.

  • Why BGR? Historical reasons: early camera manufacturers and older image-processing libraries used it.
  • Important: always convert BGR to RGB before displaying with matplotlib.
Converted to RGB
BGR shown as if RGB

The HSV colour space

BGR to RGB conversion


        import cv2

        # opencv uses BGR by default
        img_bgr = cv2.imread('image.jpg')
        # ans: blue, green, red order

        # convert to RGB
        img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
        # ans: red, green, blue order

        # channels are swapped
        print(img_bgr[0, 0])  # [B, G, R]
        print(img_rgb[0, 0])  # [R, G, B]
        # ans: the same values, in a different order
      

RGB to grayscale


          # convert to grayscale
          img = cv2.imread('image.jpg')
          gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
          # ans: single-channel intensity

          print(gray.shape)
          # ans: (height, width): no channel dimension

          # grayscale formula (weighted average)
          # Gray = 0.299*R + 0.587*G + 0.114*B
          # ans: green weighs most: the eye is most sensitive to it
        
R0.299
G0.587
B0.114

Converting to HSV


        # convert to HSV
        img = cv2.imread('image.jpg')
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        # ans: hue, saturation, value

        # split HSV channels
        h, s, v = cv2.split(hsv)
        # ans: three separate channels
        print(h.shape)
        # ans: (height, width)

        # HSV ranges in OpenCV
        # ans: H: 0-179, S: 0-255, V: 0-255
      

Colour thresholding in HSV


        # detect red objects using HSV
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

        # define the red range (hue wraps around)
        lower_red = np.array([0, 100, 100])
        upper_red = np.array([10, 255, 255])
        # ans: hue 0-10 is red, with high saturation and value

        mask = cv2.inRange(hsv, lower_red, upper_red)
        # ans: binary mask: red regions are 255

        # apply the mask to extract red objects
        result = cv2.bitwise_and(img, img, mask=mask)
        # ans: keeps only the red regions
      

Try cv2.inRange

img
mask
bitwise_and(img, img, mask)

When H low > H high the range wraps through 179 → 0: two inRange masks joined with cv2.bitwise_or.

Split & merge channels


        # split BGR channels
        b, g, r = cv2.split(img)
        # ans: separate B, G, R channels (each is grayscale)

        # merge channels back
        merged = cv2.merge([b, g, r])
        # ans: reconstructs the original image

        # swap red and blue channels
        swapped = cv2.merge([r, g, b])
        # ans: BGR becomes RGB order: reds and blues trade places
      

The LAB colour space


        # convert to LAB
        img = cv2.imread('image.jpg')
        lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
        # ans: L (lightness), a, b (colour opponents)

        l, a, b = cv2.split(lab)
        # ans: L is a grayscale-like luminance

        # LAB advantages
        # ans: perceptually uniform (distance = perceived difference)
        # ans: useful for colour correction and white balance
      

One photo, three spaces

original

Each channel is shown as a grayscale image: white = 255.

B
G
R

Exercises

Answer first, then press → to check.

Exercises 1 · concepts

What does cvtColor do?


            rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
          

It converts between colour spaces.

Why use HSV for colour detection?

It separates colour (H) from lighting (V), so thresholds are easier.

What does this print?


            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            print(gray.ndim)  # ans: 2: a 2-D array, no channel dimension
          

Which colour order does cv2.imread give you by default?

BGR (blue, green, red).

Exercises 2 · concepts

Which channel matters most for grayscale? Gray = 0.299·R + 0.587·G + 0.114·B

Green (0.587 is the highest weight).

What is the hue range in OpenCV?

0 to 179: it stands for 0 to 360°, divided by 2.

When do you use the LAB colour space?

Colour correction, white balance, whenever you need perceptual uniformity.

What does inRange return?


            mask = cv2.inRange(hsv, lower, upper)
          

A binary mask: 255 where the value is in range, 0 elsewhere.

Exercises 3 · coding

Convert BGR to RGB.


            img_bgr = cv2.imread('img.jpg')
            img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)  # ans:
            # ans: swaps the red and blue channels
          

Extract the red channel from an RGB image.


            r = img_rgb[:, :, 0]  # ans:
            # ans: red is the first channel in RGB
          

Make a red-only image.


            red_only = img_rgb.copy()
            red_only[:, :, 1:] = 0  # ans:
            # ans: green and blue set to 0, red kept
          

Exercises 4 · coding

Detect blue in HSV.


            hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
            lower_blue = np.array([100, 50, 50])
            upper_blue = np.array([130, 255, 255])
            mask = cv2.inRange(hsv, lower_blue, upper_blue)  # ans:
            # ans: a binary mask of the blue regions
          

Apply the mask to the image.


            result = cv2.bitwise_and(img, img, mask=mask)  # ans:
            # ans: extracts only the blue regions
          

Invert the mask.


            inv_mask = cv2.bitwise_not(mask)  # ans:
            # ans: 0 becomes 255 and 255 becomes 0
          

Exercises 5 · mixed

What does this produce?


            b, g, r = cv2.split(img)
            swapped = cv2.merge([r, g, b])
            # ans: an RGB image made from a BGR one
          

Extract the hue channel.


            hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
            hue = hsv[:, :, 0]  # ans:
            # ans: hue values, 0-179 in OpenCV
          

What happens here? Are img and back the same?


            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            back = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
            # ans: a grayscale image with 3 identical channels
            # ans: not the same: the colour information is lost