"How Many Colors Can the Human Eye See?": The Application

26 Apr 2024

How many colors can the human eye see? A thousand? A million? And we are not talking about the quantity that you can name - but about the colors that a person can see and compare.

In this article, we will begin to develop a prototype tool that could be used to answer this question. We will not strive for accuracy; it is important to demonstrate the principle itself. The tool will be as simple as possible so that anyone can repeat the experience.

First, Let's Delve Into a Bit of Theory.

The question, "How many colors can a person see?" has been asked for a long time, but a scientific approach to answering it only began at the end of the 19th century. Studies by Titchener (1896), Boring (1939), and Judd (1939) estimate that humans can see between 33 thousand to 10 million colors! This wide range, however, can be attributed to the lack of precision in the conditions of the observational studies and the absence of accurate measuring instruments.

Regardless, the method of calculation remains roughly the same: the number of color options that we perceive is limited by the resolution of our visual perception system. Color is a sensation that arises in human consciousness when the color-sensitive elements of the eye are stimulated.

A good starting point for your research would be to calculate the proximity of the user-selected color to the suggested one. To do this, it would be logical to utilize the discrete property of the color reproduction system in any computer color model. For instance, in the 24-bit RGB model with a maximum capacity of 16,777,216 colors (256^3).

The most straightforward starting point for your research is to calculate the proximity between the color suggested by the user and the reference color that we provided. This calculation would take advantage of the discrete properties of the color system. As a reminder, in the RGB model, each color is represented by numbers ranging from 0 to 255, which correspond to the intensity of each of the primary colors. For instance, RGB (0,0,0) represents black, while RGB (255,255,0) represents yellow.

In essence, the closer the values of the primary colors in the reference and user-suggested colors are, the greater the accuracy with which the user can select a color. Therefore, the closer the values of the primary colors in both the reference and the user's selected colors, the higher the user's accuracy in selecting a color.

So what could an appropriate formula for this look like?

Let's define test as the reference value and user as the user's value:

E = test - user

test = 100
user = 35
E = 100 - 35 = 65

test = 150
user = 200
E = 150 - 200 = -50

test = 189
user = 189
E = 189 - 189 = 0

Clearly, precision can't be negative, so we have to resort to squaring. A zero corresponds to 100 percent accuracy.

For all three RGB values, the formula would look like this:

Where Delta R, Delta G, and Delta B represent the differences between the reference and user values in the corresponding color channels.

For the final formula, we are missing Delta Emax, a value that is constant and equals the maximum possible distance between 0 and 255.


Therefore, the final formula to calculate the user's accuracy in color selection would look as follows:

Example 1:

Example 2:

As observed, in the first case, we are comparing a pair of distinctly different colors, which results in low accuracy.

Conversely, in the second case, the colors are nearly identical, leading to a high accuracy of 97.4 percent! These calculations are made possible because of the discrete nature of the tools we utilize.

With the calculation mechanism decided upon, we can now progress to the prototype development stage.

We will require the following:

  • Two color fields arranged vertically (to be visible to both eyes simultaneously)

  • A custom color slider

  • An 'Enter' button

  • A results window

Color perception can be split into two categories: sensory and perceptual, the latter involves short-term memory. It is this latter type that we will examine using our application. To enhance the measurement quality, the reference and custom color circles should not be in contact with each other.

user interface

The code for the project can be found in the repository.


<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Color Test</title>
    <link rel="stylesheet"
    <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
    <link rel="stylesheet" href="style.css">
    <div class="container">
        <div class="circle-reference"></div>
        <div class="circle-user"></div>
        <div class="slidecontainer">
            <input type="range" min="0" max="255" value="125" class="slider" id="myRange" oninput="rangeValue()">
        <button id="turnButton" type="click">NEXT</button> 
        <input type="text" id="color-accuracy" value="" >
<script src="script.js"></script>


    padding: 0;
    margin: 0;
    box-sizing: border-box;
    background-color: #338cf9;

//three most important blocks
//store variables for color fields

    --reference-color: rgb(var(--ref-col1),var(--ref-col2),var(--ref-col3));
    --user-color: rgb(var(--uc-col1),var(--uc-col2),var(--uc-col3));

//color field of the reference color

.circle-reference {
    height: 200px;
    width: 200px;
    background-color: var(--reference-color);
    border-radius: 50%;

//user color field

.circle-user {
    height: 200px;
    width: 200px;
    background-color: var(--user-color);
    border-radius: 50%;

    background-color: #ffffff;
    width: 50% 50%;
    height: 75%;
    padding: 30px 30px;
    position: absolute;
    flex-wrap: wrap;
    transform: translate(-50%,-50%);
    left: 50%;
    top: 50%;
    border-style: double;
    border-width: thick;
    border-radius: 10px;
    box-shadow: 0 25px 50px rgba(7, 20, 35, 0.2);
    margin-left: auto;
    margin-right: auto;
.slidecontainer {
    width: 200px; 
.slider {
    -webkit-appearance: none; 
    appearance: none;
    width: 100%; 
    height: 25px; 
    background: #d3d3d3; 
    outline: none; 
    opacity: 0.7; 
    -webkit-transition: .2s; 
    transition:  .2s;
.slider:hover {
    opacity: 1; 
.slider::-webkit-slider-thumb {
    -webkit-appearance: none; 
    appearance: none;
    width: 25px; 
    height: 25px; 
    background: #101010; 
    cursor: pointer; 
.slider::-moz-range-thumb {
    width: 25px; 
    height: 25px; 
    cursor: pointer; 
    width: 75px;
    font-size: 18px;
    font-family: "Poppins", sans-serif;
    border-radius: 5px;
    font-family: "Poppins", sans-serif;
    font-size: 18px;
    text-align: center;
    font-size: 18px;
    width: 50px;
    font-family: "Poppins", sans-serif;
    border-radius: 5px;


var colors=[35,200,10]// starting values of color fields, you can use absolutely any

let slider = document.getElementById("myRange");
let root = document.documentElement;
const turnButton = document.getElementById('turnButton');

//update the slider value
function rangeValue(){
    root.style.setProperty ('--uc-col2', slider.value)
//listen to the new measurement button
turnButton.addEventListener('click', ()=>{
    userColor=[];//reset custom color
    userColor=[colors[0], Number(slider.value), colors[2]];//update custom color
    colorAccuracy(userColor);//start calculating the accuracy of the match
    slider.value=125; //return the slider to the middle of the scale
// accuracy calculation block 
function colorAccuracy(){
    deltaR = colors[0]-userColor[0]; //delta red
    deltaG = colors[1]-userColor[1]; //delta green
    deltaB = colors[2]-userColor[2]; //delta blue
    deltaE = Math.sqrt(Math.pow(deltaR, 2) + Math.pow(deltaG, 2) + Math.pow(deltaB, 2)); //delta of compared parameters
    colAcc= (1- deltaE/441.67)*100; //percentage of accuracy
    document.getElementById('color-accuracy').value=colAcc.toFixed(2); //post in the results window
    newColor(); //generate a new reference color
//function for generating values from 0 to 255, each new color is random
function getRandomIntInclusive(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1) + min); 
//new color generation function
  function newColor(){
    for(i=0; i<3; i++){
		//update the parameters of all color fields
    root.style.setProperty ('--ref-col1', colors[0]);
    root.style.setProperty ('--ref-col2', colors[1]);
    root.style.setProperty ('--ref-col3', colors[2]);
    root.style.setProperty ('--uc-col1', colors[0]);
    root.style.setProperty ('--uc-col2', slider.value);
    root.style.setProperty ('--uc-col3', colors[2]);

Upon clicking the "NEXT" button, a new reference color is randomly generated. You can adjust the custom color using the slider, attempting to match it as closely as possible to the reference color. Once you press the "NEXT" button again, the colors will refresh, and the accuracy of your color selection will be displayed in the results window.

If we need to make the test more predictable — for instance, if we're conducting a laboratory study under controlled conditions — we can choose reference color settings from a pre-prepared array. By incorporating localStorage into our code, we can retain measurement results for further calculations.

How Might This Be Applied?

One example of applying the discrete properties of measurement tools is the research conducted by the Dehancer Team in 2023-2024. This study focuses on the number of colors an individual can distinguish, based on factors such as their age, the number of attempts made, and the time spent on the test.

How many colors can you see? (c) Dehancer Team

For instance, from this graph, we can conclude that given the same time to complete the test, older users typically perform slightly better than their younger counterparts. This can be attributed to differences in visual experience and color perception needs across various age groups.

You're invited to participate in the study by using the Dehancer Color Test.

The second part of this series will focus on the algorithm used to calculate the number of colors based on the data we have gathered.