Solved

# Color harmonies:triada, complement, analogous, monochromatic

Posted on 2011-05-10
938 Views
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

LVL 96

Accepted Solution

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

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.

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.

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

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

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

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

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

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

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

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

0

LVL 4

Author Comment

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

Introduction This article series is supposed to shed some light on the use of IDisposable and objects that inherit from it. In essence, a more apt title for this article would be: using (IDisposable) {}. I’m just not sure how many people would ge…
This article describes a simple method to resize a control at runtime.  It includes ready-to-use source code and a complete sample demonstration application.  We'll also talk about C# Extension Methods. Introduction In one of my applications…
To add imagery to an HTML email signature, you have two options available to you. You can either add a logo/image by embedding it directly into the signature or hosting it externally and linking to it. The vast majority of email clients display l…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…