Solved

# Color harmonies:triada, complement, analogous, monochromatic

Posted on 2011-05-10
Medium Priority
1,051 Views
Last Modified: 2012-05-11
Hi,
I need help in color math. I have one main color and i need to get other colors of chosen harmony.
I need such color harmonies: triada, complement, analogous, monochromatic.
Thanks,
Dima.
0
Question by:HohlovDima
• 7
• 3
10 Comments

LVL 96

Accepted Solution

Bob Learned earned 2000 total points
ID: 35737072
Fabulous question...hadn't thought about this subject in a long, long time!!  Let's take a step in my way back machine, and try to build a good reference point...

Harmonies theory and math
http://www.easyrgb.com/index.php?X=WEEL
http://www.easyrgb.com/index.php?X=MATH

Links and Color Related Sites
http://www.easyrgb.com/index.php?X=LINK

Color Harmonies
http://www.tigercolor.com/color-lab/color-theory/color-harmonies.htm

Complementary
Colors that are opposite each other on the color wheel

Analogous
Analogous color schemes use colors that are next to each other on the color wheel.

Triad
A triadic color scheme uses colors that are evenly spaced around the color wheel.

Split-Complementary
The split-complementary color scheme is a variation of the complementary color scheme. In addition to the base color, it uses the two colors adjacent to its complement.

Rectangle (tetradic)
The rectangle or tetradic color scheme uses four colors arranged into two complementary pairs.

Square
The square color scheme is similar to the rectangle, but with all four colors spaced evenly around the color circle.

Color Harmony Generator -- Open Source on SourceForge.net
http://sourceforge.net/projects/colorharmonygen/
0

LVL 96

Expert Comment

ID: 35737132
I have this HLS/RGB utility class laying around in my bag-o-tricks, that might prove to be useful:

``````using System;
using System.Drawing;

// Source:
//  http://www.vbaccelerator.com/home/NET/Code/Libraries/Graphics/HLS_to_RGB/Hlsrgb_zip_HLSRGB_HLSRGBVB_HLSRGB_vb.asp

public class HlsRgbUtility
{

private byte m_red = 0;
private byte m_green = 0;
private byte m_blue = 0;

private double m_hue = 0;
private double m_luminance = 0;
private double m_saturation = 0;

public HlsRgbUtility(byte red, byte green, byte blue)
{
m_red = red;
m_green = green;
m_blue = blue;
}

public HlsRgbUtility(HlsRgbUtility hlsrgb)
{
m_red = hlsrgb.Red;
m_blue = hlsrgb.Blue;
m_green = hlsrgb.Green;
m_luminance = hlsrgb.Luminance;
m_hue = hlsrgb.Hue;
m_saturation = hlsrgb.Saturation;
}

public HlsRgbUtility(Color c)
{
m_red = c.R;
m_green = c.G;
m_blue = c.B;
ToHLS();
}

public HlsRgbUtility(string htmlColor)
: this(ColorTranslator.FromHtml(htmlColor))
{
}

private HlsRgbUtility()
{
}

public byte Red
{
get { return m_red; }
set { m_red = value; ToHLS(); }
}

public byte Green
{
get { return m_green; }
set { m_green = value; ToHLS(); }
}

public byte Blue
{
get { return m_blue; }
set { m_blue = value; ToHLS(); }
}

public double Luminance
{
get { return m_luminance; }
set
{
if (((value < 0f) | (value > 1f)))
{
throw new ArgumentOutOfRangeException("Luminance", "Luminance must be between 0.0 and 1.0");
}
m_luminance = value;
ToRGB();
}
}

public double Hue
{
get { return m_hue; }
set
{
if (((value < 0f) | (value > 360f)))
{
throw new ArgumentOutOfRangeException("Hue", "Hue must be between 0.0 and 360.0");
}
m_hue = value;
ToRGB();
}
}

public double Saturation
{
get { return m_saturation; }
set
{
if (((value < 0f) | (value > 1f)))
{
throw new ArgumentOutOfRangeException("Saturation", "Saturation must be between 0.0 and 1.0");
}
m_saturation = value;
ToRGB();
}
}

public Color Color
{
get
{
return Color.FromArgb(m_red, m_green, m_blue);
}
}

public string HtmlColor
{
get
{
return ColorTranslator.ToHtml(this.Color);
}
}

public void LightenColor(double lightenBy)
{
m_luminance *= (1f + lightenBy);
if ((m_luminance > 1f))
{
m_luminance = 1f;
}
ToRGB();
}

public void DarkenColor(double darkenBy)
{
m_luminance *= darkenBy;
ToRGB();
}

public HlsRgbUtility(double hue, double luminance, double saturation)
{
if (((saturation < 0f) | (saturation > 1f)))
{
throw new ArgumentOutOfRangeException("Saturation", "Saturation must be between 0.0 and 1.0");
}
if (((hue < 0f) | (hue > 360f)))
{
throw new ArgumentOutOfRangeException("Hue", "Hue must be between 0.0 and 360.0");
}
if (((luminance < 0f) | (luminance > 1f)))
{
throw new ArgumentOutOfRangeException("Luminance", "Luminance must be between 0.0 and 1.0");
}
m_hue = hue;
m_luminance = luminance;
m_saturation = saturation;
ToRGB();
}

private void ToHLS()
{
byte minval = Math.Min(m_red, Math.Min(m_green, m_blue));
byte maxval = Math.Max(m_red, Math.Max(m_green, m_blue));
double mdiff = (maxval * 1.0 - minval * 1.0);
double msum = (maxval * 1.0 + minval * 1.0);
m_luminance = msum / 510f;
if ((maxval == minval))
{
m_saturation = 0f;
m_hue = 0f;
}
else
{
double rnorm = (maxval - m_red) / mdiff;
double gnorm = (maxval - m_green) / mdiff;
double bnorm = (maxval - m_blue) / mdiff;
if ((m_luminance <= 0.5f))
{
m_saturation = (mdiff / msum);
}
else
{
m_saturation = (mdiff / (510f - msum));
}
if ((m_red == maxval))
{
m_hue = 60f * (6f + bnorm - gnorm);
}
if ((m_green == maxval))
{
m_hue = 60f * (2f + rnorm - bnorm);
}
if ((m_blue == maxval))
{
m_hue = 60f * (4f + gnorm - rnorm);
}
if ((m_hue > 360f))
{
m_hue = m_hue - 360f;
}
}
}

private void ToRGB()
{
if ((m_saturation == 0.0))
{
m_red = Convert.ToByte(m_luminance * 255f);
m_green = m_red;
m_blue = m_red;
}
else
{
double rm1;
double rm2;
if ((m_luminance <= 0.5f))
{
rm2 = m_luminance + m_luminance * m_saturation;
}
else
{
rm2 = m_luminance + m_saturation - m_luminance * m_saturation;
}
rm1 = 2f * m_luminance - rm2;
m_red = ToRGB1(rm1, rm2, m_hue + 120f);
m_green = ToRGB1(rm1, rm2, m_hue);
m_blue = ToRGB1(rm1, rm2, m_hue - 120f);
}
}

private byte ToRGB1(double rm1, double rm2, double rh)
{
if ((rh > 360f))
{
rh -= 360f;
}
else if ((rh < 0f))
{
rh += 360f;
}
if ((rh < 60f))
{
rm1 = rm1 + (rm2 - rm1) * rh / 60f;
}
else if ((rh < 180f))
{
rm1 = rm2;
}
else if ((rh < 240f))
{
rm1 = rm1 + (rm2 - rm1) * (240f - rh) / 60f;
}
return Convert.ToByte(rm1 * 255);
}
}
``````
0

LVL 4

Author Comment

ID: 35737161
Thanks for your help. I opened first two links and find out that i was there but i was confused by one thing. Differences betwen types of harmonies is angle but what about saturation and value(i talk about HSV model)? Or i dont understand something?
Dima.
0

LVL 96

Expert Comment

ID: 35737236
This may take a while to get back on track, since I am mostly concerned with business-level programming functions these days, and not color theory...

A good way to represent a color wheel is using the CIE-L*CH color space. Each color is characterized by Hue, Saturation and Lightness, where the Hue value represent the angular position of the color in the color wheel.
For practical purposes also the HSV and HSL color spaces (popular in computer applications) can be used but they introduce a much higher degree of non-linearity in calculating each color positions.

There isn't much difference, in my opinion between HSV and HSL.  When changing colors, we are most concerned with Hue values.  Saturation and brightness (luminosity) only affect the intensity of the color.

HSL and HSV
http://en.wikipedia.org/wiki/HSL_and_HSV

In each cylinder, the angle around the central vertical axis corresponds to "hue", the distance from the axis corresponds to "saturation", and the distance along the axis corresponds to "lightness", "value" or "brightness".
0

LVL 96

Expert Comment

ID: 35737276
I found an interesting, interactive web site:

http://r0k.us/graphics/SIHwheel.html

that shows HSB values for different selections on the color wheel.

Snapshot.png
0

LVL 4

Author Comment

ID: 35737549
So i only need to change angle on the circle and i will get all harmonies that i need? I dont need to clculate saturation and brightness?
Thanks,
DIma.
0

LVL 96

Expert Comment

ID: 35738336
Yes, I do believe that Hue should be the focus of your math, but remember that saturation and brightness still play a part in the color.  If you look at the Interactive Color Wheel, you can see the full range of the combination of H, S, and B/V/L values.  If you think of the color wheel like a radar, Hue values can be seen as a "sector" (angle), and saturation and brightness can be seen as a "distance" from the center origin.  You need to change the "sector" of the color value to get the colors that you are looking for.  That chart about angles should help you with understanding the degree-relationship between the harmonic color values.
0

LVL 96

Expert Comment

ID: 35738467
If you figure out something specific, I would be very interested to hear!!  It was nice to go down memory lane, back to my days of UI development.  If I find something more concrete, I will try to share...
0

LVL 96

Expert Comment

ID: 35738506
0

LVL 4

Author Comment

ID: 35738649
Thanks a lot. I very appreciate your help. If you find something more please share. I want to create library with all color math.
Dima.
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue canā¦
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the reā¦
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signatā¦
Integration Management Part 2
###### Suggested Courses
Course of the Month15 days, 2 hours left to enroll

#### 839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.