C++ · Course navigation

C++: grayscale conversion and thresholding

Convert color pixels to brightness with luminance weights and split them into foreground and background.

On this page
Before you start

C++ structs and vectors.

  • Convert color pixels to brightness with luminance weights and split them into foreground and background.
  • Predict the sample output and explain the state changes.
  • Complete the practice task and check the boundary cases.

The concept

A color pixel has red, green, and blue channels. A grayscale image keeps only brightness. Because human vision is most sensitive to green and least to blue, the standard luma formula weights the channels unequally: 0.299·R + 0.587·G + 0.114·B.

Thresholding turns a grayscale image into a binary one. Pixels brighter than the threshold become 1 (foreground) and the rest become 0. A simple choice of threshold is the mean brightness. Methods such as Otsu's choose it automatically from the histogram. Binary images are the input to many later steps, such as finding connected regions.

Code example

C++
#include <cmath>
#include <iostream>
#include <vector>

struct Rgb {
  int r, g, b;
};

int main() {
  std::vector<Rgb> pixels = {{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 255}};
  std::vector<int> gray;
  double total = 0;
  for (const Rgb& p : pixels) {
    int value = static_cast<int>(std::lround(0.299 * p.r + 0.587 * p.g + 0.114 * p.b));
    gray.push_back(value);
    total += value;
  }
  double threshold = total / gray.size();

  std::cout << "gray:";
  for (int v : gray) {
    std::cout << " " << v;
  }
  std::cout << "\nthreshold: " << threshold << "\nbinary:";
  for (int v : gray) {
    std::cout << " " << (v > threshold ? 1 : 0);
  }
  std::cout << "\n";
}
Output
gray: 76 150 29 255
threshold: 127.5
binary: 0 1 0 1

Follow the code

Open the walkthrough to inspect the example one step at a time.

Show guided walkthrough
Guided walkthroughReady
1#include <cmath>
2#include <iostream>
3#include <vector>
4
5struct Rgb {
6 int r, g, b;
7};
8
9int main() {
10 std::vector<Rgb> pixels = {{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 255}};
11 std::vector<int> gray;
12 double total = 0;
13 for (const Rgb& p : pixels) {
14 int value = static_cast<int>(std::lround(0.299 * p.r + 0.587 * p.g + 0.114 * p.b));
15 gray.push_back(value);
16 total += value;
17 }
18 double threshold = total / gray.size();
19
20 std::cout << "gray:";
21 for (int v : gray) {
22 std::cout << " " << v;
23 }
24 std::cout << "\nthreshold: " << threshold << "\nbinary:";
25 for (int v : gray) {
26 std::cout << " " << (v > threshold ? 1 : 0);
27 }
28 std::cout << "\n";
29}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Weighted sum of the channels, rounded: pure red is 76, pure green 150, pure blue 29, white 255.gray = 76, 150, 29, 255
—
The mean brightness (76 + 150 + 29 + 255) / 4 = 127.5 is used as the threshold.threshold = 127.5
—
Print the threshold; the binary values follow on the same line.threshold = 127.5
—
Only green and white are brighter than 127.5.threshold = 127.5
gray: 76 150 29 255
threshold: 127.5
binary: 0 1 0 1

Behind the scenes

How C++ processes this code

The C++ compiler produces a native executable. Execution enters main, where objects and function calls perform the work.

Cost and common mistakes

O(p) time for p pixels.

  • Averaging the three channels (R+G+B)/3 makes pure blue look as bright as pure green, which does not match perception.
  • A single global threshold fails when lighting is uneven. Adaptive thresholding computes a different threshold for each region.

Try it yourself

Which weights are used by the older NTSC formula and by modern HDTV (Rec. 709)?

Reveal answer and reasoning

NTSC (Rec. 601) uses 0.299, 0.587, 0.114. Rec. 709 uses 0.2126, 0.7152, 0.0722.

Further reading