All pastes #1329075 Raw Edit

rgb_t and hsv_t

public text v1 · immutable
#1329075 ·published 2009-02-06 15:44 UTC
rendered paste body
//*****************************************************************************************
//  File:       ColorLib.cs
//  Project:    TouchlessLib
//  Author(s):  Michael Wasserman (Michael.Wasserman@microsoft.com)
//
//  These helper classes represent colors.
//
//  TODO: Improve HSV colorspace binning/partitioning? Replace with grouping/clustering?
//  TODO: Replace RGB->HSV with a lookup table?
//*****************************************************************************************

using System;
using System.Collections.Generic;
using System.Text;

namespace TouchlessLib
{
    /// <summary>
    /// Represents a color in RGB (Red, Green, Blue)
    /// byte Red: [0-255]
    /// byte Grn: [0-255]
    /// byte Blu: [0-255]
    /// </summary>
    internal struct RGB
    {
        public static byte HSV_MAX_RED = 255;
        public static byte HSV_MAX_GRN = 255;
        public static byte HSV_MAX_BLU = 255;

        /// <summary>
        /// Create a new RGB (Red, Green, Blue) struct
        /// </summary>
        /// <param name="r">RGB Red [0-255]</param>
        /// <param name="g">RGB Green [0-255]</param>
        /// <param name="b">RGB Blue [0-255]</param>
        public RGB(byte r, byte g, byte b)
        {
            this.r = r; this.g = g; this.b = b;
        }

        /// <summary>
        /// Create a new RGB (Red, Green, Blue) struct from an ARGB int
        /// </summary>
        /// <param name="argb">ARGB integer in the format 0xAARRGGBB</param>
        public RGB(int argb)
        {
            this.b = (byte)(argb & 0xff);
            this.g = (byte)((argb >>= 8) & 0xff);
            this.r = (byte)((argb >> 8) & 0xff);
        }

        #region Accessors

        /// <summary>
        /// RGB Red [0-255]
        /// </summary>
        public byte Red
        {
            get { return r; }
            set { r = value; }
        }

        /// <summary>
        /// RGB Green [0-255]
        /// </summary>
        public byte Grn
        {
            get { return g; }
            set { g = value; }
        }

        /// <summary>
        /// RGB Blue [0-255]
        /// </summary>
        public byte Blu
        {
            get { return b; }
            set { b = value; }
        }

        #endregion Accessors

        #region Static Conversion Methods

        /// <summary>
        /// Convert a System.Drawing.Color to its corresponding RGB
        /// </summary>
        /// <param name="c">A System.Drawing.Color</param>
        /// <returns>A corresponding RGB structure</returns>
        public static RGB ConvertFromColor(System.Drawing.Color c)
        {
            return new RGB(c.R, c.G, c.B);
        }

        /// <summary>
        /// Convert an RGB structure to its corresponding System.Drawing.Color
        /// </summary>
        /// <param name="rgb">An RGB structure</param>
        /// <returns>A corresponding System.Drawing.Color</returns>
        public static System.Drawing.Color ConvertToColor(RGB rgb)
        {
            return System.Drawing.Color.FromArgb(rgb.r, rgb.g, rgb.b);
        }

        /// <summary>
        /// Convert an RGB structure to its corresponding HSV structure
        /// </summary>
        /// <param name="rgb">An RGB structure</param>
        /// <returns>A corresponding HSV structure</returns>
        public static HSV ConvertToHSV( RGB rgb )
        {
            HSV hsv = new HSV();
            byte min, max;

            // Find the min / max for r, g, b
            if (rgb.r <= rgb.g)
            {
                if (rgb.r >= rgb.b) { min = rgb.b; max = rgb.g; }
                else { min = rgb.r; max = (rgb.g >= rgb.b)? rgb.g : rgb.b; }
            }
            else if (rgb.r <= rgb.b) { min = rgb.g; max = rgb.b; }
            else { max = rgb.r; min = (rgb.g <= rgb.b) ? rgb.g : rgb.b; }

            // HSV value and saturation
            hsv.Val = max;
            hsv.Sat = (byte)((max == 0) ? 0 : 255* (max - min) / max);

            // HSV hue
            if (max == min) hsv.Hue = 0;
            else
            {
                if (max == rgb.r) hsv.Hue = (short)((60 * (rgb.g - rgb.b) / (max - min) + 360) % 360);
                else if (max == rgb.g) hsv.Hue = (short)(60 * (rgb.b - rgb.r) / (max - min) + 120);
                else if (max == rgb.b) hsv.Hue = (short)(60 * (rgb.r - rgb.g) / (max - min) + 240);
            }

            return hsv;
        }

        #endregion

        private byte r;
        private byte g;
        private byte b;
    }


    /// <summary>
    /// Represents a color in HSV (Hue, Saturation, Value)
    /// byte Hue: [0-360]
    /// byte Sat: [0-255]
    /// byte Val: [0-255]
    /// </summary>
    internal struct HSV
    {
        public static short HSV_MAX_HUE = 360;
        public static byte HSV_MAX_SAT = 255;
        public static byte HSV_MAX_VAL = 255;

        /// <summary>
        /// Create a new HSV (Hue, Saturation, Value) struct
        /// </summary>
        /// <param name="h">HSV Hue [0-360]</param>
        /// <param name="s">HSV Saturation [0-255]</param>
        /// <param name="v">HSV Value [0-255]</param>
        public HSV(short h, byte s, byte v)
        {
            this.h = h; this.s = s; this.v = v;
        }

        #region Accessors

        /// <summary>
        /// HSV Hue [0-360]
        /// </summary>
        public short Hue
        {
            get { return h; }
            set { h = value; }
        }

        /// <summary>
        /// HSV Saturation [0-255]
        /// </summary>
        public byte Sat
        {
            get { return s; }
            set { s = value; }
        }

        /// <summary>
        /// HSV Value [0-255]
        /// </summary>
        public byte Val
        {
            get { return v; }
            set { v = value; }
        }

        #endregion Accessors

        #region Static Conversion Methods

        /// <summary>
        /// Convert a System.Drawing.Color to its corresponding HSV
        /// </summary>
        /// <param name="c">A System.Drawing.Color</param>
        /// <returns>A corresponding HSV structure</returns>
        public static HSV ConvertFromColor(System.Drawing.Color c)
        {
            return RGB.ConvertToHSV(new RGB(c.R, c.G, c.B));
        }

        /// <summary>
        /// Convert an HSV structure to its corresponding System.Drawing.Color
        /// </summary>
        /// <param name="hsv">An HSV structure</param>
        /// <returns>A corresponding System.Drawing.Color</returns>
        public static System.Drawing.Color ConvertToColor(HSV hsv)
        {
            RGB rgb = HSV.ConvertToRGB(hsv);
            return System.Drawing.Color.FromArgb(rgb.Red, rgb.Grn, rgb.Blu);
        }

        /// <summary>
        /// Convert an HSV structure to its corresponding RGB structure
        /// </summary>
        /// <param name="hsv">An HSV structure</param>
        /// <returns>A corresponding RGB structure</returns>
        public static RGB ConvertToRGB(HSV hsv)
        {
            int h = (hsv.h / 60) % 6;
            float f = hsv.h / 60.0F - hsv.h / 60;
            byte p = (byte)((hsv.v * (HSV.HSV_MAX_SAT - hsv.s)) / HSV.HSV_MAX_SAT);
            byte q = (byte)((hsv.v * (HSV.HSV_MAX_SAT - f * hsv.s)) / HSV.HSV_MAX_SAT);
            byte t = (byte)((hsv.v * (HSV.HSV_MAX_SAT - (1 - f) * hsv.s)) / HSV.HSV_MAX_SAT);
            RGB rgb = new RGB();
            if (h == 0) rgb = new RGB(hsv.v, t, p);
            else if (h == 1) rgb = new RGB(q, hsv.v, p);
            else if (h == 2) rgb = new RGB(p, hsv.v, t);
            else if (h == 3) rgb = new RGB(p, q, hsv.v);
            else if (h == 4) rgb = new RGB(t, p, hsv.v);
            else if (h == 5) rgb = new RGB(hsv.v, p, q);
            return rgb;
        }

        /// <summary>
        /// Returns an HSV representing the binned version of the argument HSV color
        /// </summary>
        /// <param name="hsv">The HSV color to be binned and then used to generate the hash key</param>
        /// <param name="binCounts">The count of bins per Hue, Sat, Val space</param>
        public static HSV GetBinnedHSV(HSV hsv, HSV binCounts)
        {
            HSV binnedHSV = new HSV();
            binnedHSV.Hue = (short)(hsv.Hue * (binCounts.Hue - 1) / HSV.HSV_MAX_HUE);
            binnedHSV.Sat = (byte)(hsv.Sat * (binCounts.Sat - 1) / HSV.HSV_MAX_SAT);
            binnedHSV.Val = (byte)(hsv.Val * (binCounts.Val - 1) / HSV.HSV_MAX_VAL);
            return binnedHSV;
        }

        #endregion

        private short h;
        private byte s;
        private byte v;
    }

    /// <summary>
    /// A hash key that represents an HSV color
    /// </summary>
    internal struct ColorKey
    {
        /// <summary>
        /// Constructor that takes an HSV color
        /// </summary>
        /// <param name="h">The HSV color used to generate the hash key</param>
        public ColorKey(HSV h)
        {
            hsv = h;
            key = h.Hue + h.Sat * HSV.HSV_MAX_HUE + h.Val * HSV.HSV_MAX_SAT * HSV.HSV_MAX_HUE;
        }

        /// <summary>
        /// The HSV Value used to generate the hash key
        /// </summary>
        public HSV Hsv
        {
            get { return hsv; }
            set
            {
                hsv = value;
                key = value.Hue + value.Sat * HSV.HSV_MAX_HUE + value.Val * HSV.HSV_MAX_SAT * HSV.HSV_MAX_HUE;
            }
        }

        /// <summary>
        /// Provides a hash key from the HSV value
        /// </summary>
        /// <returns>A unique int used as a hash key for this color (depends on HSV colorspace partitioning model)</returns>
        public override int GetHashCode()
        {
            return key;
        }

        /// <summary>
        /// Hashtable equality tester
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>Returns true if the color components (h,s,v) are the same</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof(ColorKey))
                return false;
            ColorKey other = (ColorKey)obj;
            return other.hsv.Hue == hsv.Hue
                && other.hsv.Sat == hsv.Sat
                && other.hsv.Val == hsv.Val;
        }

        private HSV hsv;
        private int key;
    }
}