Dichromacy, or How Dogs View the World


The original source code for this post is wrong as pointed out by a friendly soul in the comments section. I have since updated the images on this post to reflect that fact /ssodelta

This post was updated July 1st, 2016. The new source is based on the DELTA Colour Library. The full code for the protanopia-filter is:

public class ProtanopiaFilter implements DImageFilter {

 @Override
 public Colour filter(int x, int y, Colour[][] raster) {
 Colour c = raster[x][y];
 c.convert(ColourSpace.LMS);
 
 double[] lms = c.getData();
 
 double Lp = 2.02344*lms[1] - 2.52581*lms[2],
 Mp = lms[1],
 Sp = lms[2];
 
 return new Colour(new double[]{Lp, Mp, Sp}, ColourSpace.LMS);
 }

}

Most humans see a whole bunch of colors – red, green, blue, violet, maroon etc., but some people are unfortunately born color-blind, and thus have trouble differentiating hues, which regular people find easy. For example, the red-green color blindness, which I’ll assume most people have heard of. Basically, if you’re red-green color blind, this image looks uniform:

This is because the human eye interprets color using three color receptors – red, green and blue. However, in some people, one or more of these receptors don’t work as well, making it harder to tell certain colors apart. When you only have two color receptors, you have a condition called dichromacy. Some animals, however, are permanent dichromats – this includes our canine friends – dogs are dichromats. There are several kinds of dichromacy, protanopia is the most common amongst humans, and there is a general consensus that this is how dogs view the world. Consider this rainbow:

color

If you have protanopia (or is a dog) this rainbow would look something like this instead

out

Notice how similar the blue and green colors look to a dog – no wonder it can’t as easily as us spot a blue ball in green grass. Anyway, the above protanopia rainbow was rendered using a program I wrote myself. I’ll account for how to convert regular RGB color codes to their protanopia representation in the following section.

To be able to perform this conversion, we first need to convert RGB color space into LMS color space. LMS color space is another way to represent colors using their approximate wavelengths. Remember how the human eye has three receptors? Each color channel in LMS represents one of these receptors:

Human color vision and the LMS color space.

To do this, we use the following equation: (reference)

Capture1

This is just simple matrix multiplication, and we now have another triplet LMS representing our pixel. Next up, we’ll convert this to protanopia vision using the following formula; L_p, M_p, S_p all represent the protanopia version of the channel:

Capture2

Notice how the and S channels remain the same. If we discuss other types of color blindness, they might also change. Finally, we’ll convert back from LMS to RGB using the following formula:

Capture3

I have made two classes in Java, that do this exact conversion, which I have included in the link at the top of this post – and a wrapper class for BufferedImage, which eases the conversion. Using this formula, we can imagine how dogs view different scenarios:

A colorful meadow (credit):

natureout

Beautiful tropical birds (credit):birdout

Personally, I’m glad I have full color vision, as the world is much more beautiful when you have a wide range of colors, however sometimes I’m bummed out by the fact that I’m not a mantis shrimp – they have 16 color receptors, completely dwarfing our 3 color receptors. I don’t have the brain power to even understand 4 color receptors, so 16 seems completely mind-boggling to me.

10 thoughts on “Dichromacy, or How Dogs View the World

  1. Nice article, but NOT a correct implementation. Blue should stay blue, red does not turn into blue, but into something greenish.

    1. You are correct that the implementation isn’t correct, as there are small pixels that are rendered incorrectly on the images (random red pixels).

      1. You know what, this actually makes excellent sense. I had wondered why the images looked a bit strange. Yours makes a lot more sense. Thanks for pointing this out 🙂

      2. I took a look at the code. The matrix multiplications seem OK.
        I suspect the function ‘public int getRGB()’; too much bit-juggling going on there.

      3. You are welcome!
        There is an inconsistency in the code. In a Set() function, you put red in the lowest 8 bits of an int, but in the Get(),the lowest 8 bits are assigned to blue.
        The random red pixels are probably caused by overflow: a value slightly less than zero should be mapped to zero, not to -1, which equals 255 in an unsigned char.

  2. Hi! If I just wanted to get a color to change to dog vision how would i do that? Currently, generating a color r = (int) random(0, 255);
    g = (int) random(0, 255);
    b = (int) random(0, 255);
    c = color(r, g, b);
    RGB rgb = new RGB(c).getProtanopia();
    this is what prints out: dogvision$RGB@1febd225

  3. you are really a excellent webmaster. The site loading speed is amazing.
    It sort of feels that you’re doing any unique trick. In addition, The contents are
    masterwork. you have performed a fantastic activity in this
    matter!

Leave a reply to Lambert Zijp Cancel reply