2015-04-29 12:45:37 Trent1985 阅读数 1748


图像颜色空间是图像颜色集合的数学表示,本小节将针对几种常见颜色空间做个简单介绍。


       /// <summary>
        /// Get rgba value from source image.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static byte[] RGBValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                byte[] rgbaValue = new byte[w * h * 3];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        rgbaValue[x * 3 + y * w * 3] = (byte)temp[x * 4 + y * w * 4];
                        rgbaValue[x * 3 + 1 + y * w * 3] = (byte)temp[x * 4 + 1 + y * w * 4];
                        rgbaValue[x * 3 + 2 + y * w * 3] = (byte)temp[x * 4 + 2 + y * w * 4];
                    }
                }            
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return rgbaValue;
            }
            else
            {
                return null;
            }
        }

4.2 XYZ颜色空间

[空间解析]

XYZ颜色空间:国际照明委员会(CIE)在进行了大量正常人视觉测量和统计,1931年建立了标准色度观察者, 从而奠定了现代CIE标准色度学的定量基础。由于"标准色度观察者"用来标定光谱色时出现负 刺激值,计算不便,也不易理解,因此1931CIERGB系统基础上,改用三个假想的原色XY、 Z建立了一个新的色度系统。将它匹配等能光谱的三刺激值,定名为"CIE1931 标准色度观察者 光谱三刺激值",简称为"CIE1931标准色度观察者"。这一系统叫做"CIE1931标准色度系统"或称为2视场XYZ色度系统"其中Y表示亮度,XY反映颜色的色度特性,色度图如下所示。

        /// <summary>
        /// Get XYZ value from source image.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static double[] XYZValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                double[] xyzValue = new double[w * h * 3];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = temp[x * 4 + y * w * 4];
                        g = temp[x * 4 + 1 + y * w * 4];
                        r = temp[x * 4 + 2 + y * w * 4];
                        xyzValue[x * 3 + y * w * 3] = (double)(0.5767309 * (double)r + 0.1855540 * (double)g + 0.1881852 * (double)b);
                        xyzValue[x * 3 + 1 + y * w * 3] = (double)(0.2973769 * (double)r + 0.6273491 * (double)g + 0.0752741 * (double)b);
                        xyzValue[x * 3 + 2 + y * w * 3] = (double)(0.0270343 * (double)r + 0.0706872 * (double)g + 0.9911085 * (double)b);
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return xyzValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert rgb to xyz.
        /// </summary>
        /// <param name="rgbValue">The rgb value.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] RGBtoXYZ(byte[]rgbValue,int w,int h)
        {
            if (rgbValue != null)
            {
                double[] xyzValue = new double[w * h * 3];
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = rgbValue[x * 3 + y * w * 3];
                        g = rgbValue[x * 3 + 1 + y * w * 3];
                        r = rgbValue[x * 3 + 2 + y * w * 3];
                        xyzValue[x * 3 + y * w * 3] = (double)(0.5767309 * (double)r + 0.1855540 * (double)g + 0.1881852 * (double)b);
                        xyzValue[x * 3 + 1 + y * w * 3] = (double)(0.2973769 * (double)r + 0.6273491 * (double)g + 0.0752741 * (double)b);
                        xyzValue[x * 3 + 2 + y * w * 3] = (double)(0.0270343 * (double)r + 0.0706872 * (double)g + 0.9911085 * (double)b);
                    }
                }
                return xyzValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert xyz to rgb.
        /// </summary>
        /// <param name="xyzValue">The xyz value.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] XYZtoRGB(byte[] xyzValue, int w, int h)
        {
            if (xyzValue != null)
            {
                double[] rgbValue = new double[w * h * 3];
                double xV = 0, yV = 0, zV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        xV = xyzValue[x * 3 + y * w * 3];
                        yV = xyzValue[x * 3 + 1 + y * w * 3];
                        zV = xyzValue[x * 3 + 2 + y * w * 3];
                        rgbValue[x * 3 + y * w * 3] = (byte)(0.0134474 * xV - 0.1183897 * yV + 1.0154096 * zV);
                        rgbValue[x * 3 + 1 + y * w * 3] = (byte)(-0.9692660 * xV + 1.8760108 * yV + 0.0415560 * zV);
                        rgbValue[x * 3 + 2 + y * w * 3] = (byte)(2.0413690 * xV - 0.5649464 * yV - 0.3446944 * zV);
                    }
                }
                return rgbValue;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Get yuv information.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static double[] YUVValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                double[] yuvValue = new double[w * h * 3];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = temp[x * 4 + y * w * 4];
                        g = temp[x * 4 + 1 + y * w * 4];
                        r = temp[x * 4 + 2 + y * w * 4];
                        yuvValue[x * 3 + y * w * 3] = (double)(0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b);
                        yuvValue[x * 3 + 1 + y * w * 3] = (double)(-0.148 * (double)r - 0.289 * (double)g + 0.437 * (double)b);
                        yuvValue[x * 3 + 2 + y * w * 3] = (double)(0.615 * (double)r - 0.515 * (double)g - 0.100 * (double)b);
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return yuvValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert RGB to YUV.
        /// </summary>
        /// <param name="rgbValue">The rgb information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] RGBtoYUV(byte[] rgbValue, int w, int h)
        {
            if (rgbValue != null)
            {
                double[] yuvValue = new double[w * h * 3];
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = rgbValue[x * 3 + y * w * 3];
                        g = rgbValue[x * 3 + 1 + y * w * 3];
                        r = rgbValue[x * 3 + 2 + y * w * 3];
                        yuvValue[x * 3 + y * w * 3] = (double)(0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b);
                        yuvValue[x * 3 + 1 + y * w * 3] = (double)(-0.148 * (double)r - 0.289 * (double)g + 0.437 * (double)b);
                        yuvValue[x * 3 + 2 + y * w * 3] = (double)(0.615 * (double)r - 0.515 * (double)g - 0.100 * (double)b);
                    }
                }
                return yuvValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert yuv to rgb.
        /// </summary>
        /// <param name="yuvValue">The yuv information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] YUVtoRGB(byte[] yuvValue, int w, int h)
        {
            if (yuvValue != null)
            {
                double[] rgbValue = new double[w * h * 3];
                double yV = 0, uV = 0, vV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        yV = yuvValue[x * 3 + y * w * 3];
                        uV = yuvValue[x * 3 + 1 + y * w * 3];
                        vV = yuvValue[x * 3 + 2 + y * w * 3];
                        rgbValue[x * 3 + y * w * 3] = (byte)(1 * yV + 2.032 * uV + 0 * vV);
                        rgbValue[x * 3 + 1 + y * w * 3] = (byte)(1 * yV - 0.395 * uV - 0.581 * vV);
                        rgbValue[x * 3 + 2 + y * w * 3] = (byte)(1 * yV + 0 * uV + 1.140 * vV);
                    }
                }
                return rgbValue;
            }
            else
            {
                return null;
            }
        }

4.4 HIS颜色空间

 [空间解析]

  HIS颜色空间是从人的视觉系统出发,用色调(Hue)、色饱和度(SaturationChroma)和亮度 (IntensityBrightness)来描述色彩。HSI色彩空间可以用一个圆锥空间模型来描述。用这种 描述HIS色彩空间的圆锥模型相当复杂,但确能把色调、亮度和色饱和度的变化情形表现得很清楚。通常把色调和饱和度通称为色度,用来表示颜色的类别与深浅程度,HS包含了颜色信息,而I则与颜色信息无关。

  HIS颜色空间模型如下图所示:

        /// <summary>
        /// Get his information.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static double[] HISValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                double[] hisValue = new double[w * h * 3];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                double r = 0, g = 0, b = 0;
                double hV = 0, degree = 0, iV = 0, sV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = (double)temp[x * 4 + y * w * 4]/255.0;
                        g = (double)temp[x * 4 + 1 + y * w * 4]/255.0;
                        r = (double)temp[x * 4 + 2 + y * w * 4]/255.0;
                        degree = Math.Acos(0.5 * ((r - g) + (r - b)) / Math.Sqrt((r - g) * (r - g) + (r - b) * (g - b) + 0.0000001)) / (2 * Math.PI);
                        hV = (b <= g) ? degree : 1.0 - degree;
                        iV = (double)(r + g + b) / 3.0;
                        sV = 1.0 - 3.0 * (double)Math.Min(r, Math.Min(g, b)) / (double)(r + g + b + 0.00000001);
                        hisValue[x * 3 + y * w * 3] = hV;
                        hisValue[x * 3 + 1 + y * w * 3] = iV;
                        hisValue[x * 3 + 2 + y * w * 3] = sV;
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return hisValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert rgb to his.
        /// </summary>
        /// <param name="rgbValue">The rgb information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] RGBtoHIS(byte[] rgbValue, int w, int h)
        {
            if (rgbValue != null)
            {
                double[] hisValue = new double[w * h * 3];
                double r = 0, g = 0, b = 0;
                double hV = 0, degree = 0, iV = 0, sV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = (double)rgbValue[x * 3 + y * w * 3]/255.0;
                        g = (double)rgbValue[x * 3 + 1 + y * w * 3]/255.0;
                        r = (double)rgbValue[x * 3 + 2 + y * w * 3]/255.0;
                        degree = Math.Acos(0.5 * ((r - g) + (r - b)) / Math.Sqrt((r - g) * (r - g) + (r - b) * (g - b) + 0.0000001)) / (2 * Math.PI);
                        hV = (b <= g) ? degree : 1.0 - degree;
                        iV = (double)(r + g + b) / 3.0;
                        sV = 1.0 - 3.0 * (double)Math.Min(r, Math.Min(g, b)) / (double)(r + g + b + 0.00000001);
                        hisValue[x * 3 + y * w * 3] = hV;
                        hisValue[x * 3 + 1 + y * w * 3] = iV;
                        hisValue[x * 3 + 2 + y * w * 3] = sV;
                    }
                }
                return hisValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert his to rgb.
        /// </summary>
        /// <param name="hisValue">The his information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] HIStoRGB(byte[] hisValue, int w, int h)
        {
            if (hisValue != null)
            {
                double[] rgbValue = new double[w * h * 3];
                double hV = 0, iV = 0, sV = 0;
                double r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        hV = hisValue[x * 3 + y * w * 3];
                        iV = hisValue[x * 3 + 1 + y * w * 3];
                        sV = hisValue[x * 3 + 2 + y * w * 3];
                        hV = hV * 2 * Math.PI;
                        if (hV >= 0 && hV < 2 * Math.PI / 3)
                        {
                            r = (double)(iV * (1.0 + (sV * Math.Cos(hV) / Math.Cos(Math.PI / 3 - hV))));
                            b = (double)(iV * (1.0 - sV));
                            g = (double)(3.0 * iV - r - b);
                        }
                        else if (hV >= 2 * Math.PI / 3 && hV < 4 * Math.PI / 3)
                        {
                            g = (double)(iV * (1.0 + sV * Math.Cos(hV - 2 * Math.PI / 3) / Math.Cos(Math.PI - hV)));
                            r = (double)(iV * (1.0 - sV));
                            b = (double)(3.0 * iV - r - g);
                        }
                        else
                        {
                            g = (double)(iV * (1.0 - sV));
                            b = (double)(iV * (1.0 + sV * Math.Cos(hV - 4 * Math.PI / 3) / Math.Cos(5 * Math.PI / 3 - hV)));
                            r = (double)(3.0 * iV - g - b);
                        }
                        rgbValue[x * 3 + y * w * 3] = (byte)(Math.Min(255, b * 255.0));
                        rgbValue[x * 3 + 1 + y * w * 3] = (byte)(Math.Min(255, g * 255.0));
                        rgbValue[x * 3 + 2 + y * w * 3] = (byte)(Math.Min(255, r * 255.0));
                    }
                }
                return rgbValue;
            }
            else
            {
                return null;
            }
        }


        /// <summary>
        /// Get YIQ information.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static double[] YIQValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                double[] yiqValue = new double[w * h * 3];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = temp[x * 4 + y * w * 4];
                        g = temp[x * 4 + 1 + y * w * 4];
                        r = temp[x * 4 + 2 + y * w * 4];
                        yiqValue[x * 3 + y * w * 3] = (double)(0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b);
                        yiqValue[x * 3 + 1 + y * w * 3] = (double)(0.596 * (double)r - 0.275 * (double)g - 0.321 * (double)b);
                        yiqValue[x * 3 + 2 + y * w * 3] = (double)(0.212 * (double)r - 0.523 * (double)g + 0.311 * (double)b);
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return yiqValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert rgb to yiq.
        /// </summary>
        /// <param name="rgbValue">The rgb information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] RGBtoYIQ(byte[] rgbValue, int w, int h)
        {
            if (rgbValue != null)
            {
                double[] yiqValue = new double[w * h * 3];
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = rgbValue[x * 3 + y * w * 3];
                        g = rgbValue[x * 3 + 1 + y * w * 3];
                        r = rgbValue[x * 3 + 2 + y * w * 3];
                        yiqValue[x * 3 + y * w * 3] = (double)(0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b);
                        yiqValue[x * 3 + 1 + y * w * 3] = (double)(0.596 * (double)r - 0.275 * (double)g - 0.321 * (double)b);
                        yiqValue[x * 3 + 2 + y * w * 3] = (double)(0.212 * (double)r - 0.523 * (double)g + 0.311 * (double)b);
                    }
                }
                return yiqValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert yiq to rgb.
        /// </summary>
        /// <param name="yiqValue">The yiq information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] YIQtoRGB(byte[] yiqValue, int w, int h)
        {
            if (yiqValue != null)
            {
                double[] rgbValue = new double[w * h * 3];
                double yV = 0, iV = 0, qV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        yV = yiqValue[x * 3 + y * w * 3];
                        iV = yiqValue[x * 3 + 1 + y * w * 3];
                        qV = yiqValue[x * 3 + 2 + y * w * 3];
                        rgbValue[x * 3 + 2 + y * w * 3] = (byte)(1 * yV + 0.9560 * iV + 0.6210 * qV);
                        rgbValue[x * 3 + 1 + y * w * 3] = (byte)(1 * yV - 0.2720 * iV - 0.6470 * qV);
                        rgbValue[x * 3 + y * w * 3] = (byte)(1 * yV - 1.1070 * iV + 1.7040 * qV);
                    }
                }
                return rgbValue;
            }
            else
            {
                return null;
            }
        }

4.6 HSV颜色空间

[空间解析]

  HSV彩色空间是一种适合肉眼分辨的模型。
  H—色相,表示色彩信息,即所处的光谱颜色的位置。该参数用角度量来表示,红、绿、蓝分别相隔120度。互补色分别相差180度。
  S—饱和度,该参数为一比例值,范围从01,它表示成所选颜色的纯度和该颜色最大的纯度之间的比率。S=0时,只有灰度。
  V—亮度,表示色彩的明亮程度,范围从01

  HSV颜色空间模型如下图所示:

        /// <summary>
        /// Get HSV information.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static double[] HSVValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                double[] hsvValue = new double[w * h * 3];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                double r = 0, g = 0, b = 0;
                double min = 0, max = 0;
                double hV = 0, sV = 0, vV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = (double)temp[x * 4 + y * w * 4]/255.0;
                        g = (double)temp[x * 4 + 1 + y * w * 4]/255.0;
                        r = (double)temp[x * 4 + 2 + y * w * 4]/255.0;
                        min = Math.Min(r, Math.Min(g, b));
                        max = Math.Max(r, Math.Max(g, b));
                        if (max == min)
                            hV = 0;
                        if (max == r && g >= b)
                            hV = 60.0 * (g - b) / (max - min);
                        if (max == r && g < b)
                            hV = 60.0 * (g - b) / (max - min) + 360.0;
                        if (max == g)
                            hV = 60.0 * (b - r) / (max - min) + 120.0;
                        if (max == b)
                            hV = 60.0 * (r - g) / (max - min) + 240.0;
                        if (max == 0)
                            sV = 0;
                        else
                            sV = (max - min) / max;
                        vV = max;
                        hsvValue[x * 3 + y * w * 3] = (double)(hV);
                        hsvValue[x * 3 + 1 + y * w * 3] = (double)(sV);
                        hsvValue[x * 3 + 2 + y * w * 3] = (double)(vV);
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return hsvValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert rgb to hsv.
        /// </summary>
        /// <param name="rgbValue">The rgb information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] RGBtoHSV(byte[] rgbValue, int w, int h)
        {
            if (rgbValue != null)
            {
                double[] hsvValue = new double[w * h * 3];
                double r = 0, g = 0, b = 0;
                double min = 0, max = 0;
                double hV = 0, sV = 0, vV = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        r = (double)rgbValue[x * 3 + 2 + y * w * 3] / 255.0;
                        g = (double)rgbValue[x * 3 + 1 + y * w * 3] / 255.0;
                        b = (double)rgbValue[x * 3 + y * w * 3] / 255.0;
                        min = Math.Min(r, Math.Min(g, b));
                        max = Math.Max(r, Math.Max(g, b));
                        if (max == min)
                            hV = 0;
                        if (max == r && g >= b)
                            hV = 60.0 * (g - b) / (max - min);
                        if (max == r && g < b)
                            hV = 60.0 * (g - b) / (max - min) + 360.0;
                        if (max == g)
                            hV = 60.0 * (b - r) / (max - min) + 120.0;
                        if (max == b)
                            hV = 60.0 * (r - g) / (max - min) + 240.0;
                        if (max == 0)
                            sV = 0;
                        else
                            sV = (max - min) / max;
                        vV = max;
                        hsvValue[x * 3 + y * w * 3] = (double)(hV);
                        hsvValue[x * 3 + 1 + y * w * 3] = (double)(sV);
                        hsvValue[x * 3 + 2 + y * w * 3] = (double)(vV);
                    }
                }
                return hsvValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert hsv to rgb.
        /// </summary>
        /// <param name="hsvValue">The hsv information.</param>
        /// <param name="w">The width of souce image.</param>
        /// <param name="h">The height of souce image.</param>
        /// <returns></returns>
        public static double[] HSVtoRGB(byte[] hsvValue, int w, int h)
        {
            if (hsvValue != null)
            {
                double[] rgbValue = new double[w * h * 3];
                double hV = 0, sV = 0, vV = 0, r = 0, g = 0, b = 0, p = 0, q = 0, t = 0;
                int hN = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        hV = hsvValue[x * 3 + y * w * 3];
                        sV = hsvValue[x * 3 + 1 + y * w * 3];
                        vV = hsvValue[x * 3 + 2 + y * w * 3];
                        if (hV < 0)
                            hV = 360 + hV;
                        hN = (int)(hV / 60);
                        p = vV * (1.0 - sV);
                        q = vV * (1.0 - (hV / 60.0 - hN) * sV);
                        t = vV * (1.0 - (1.0 - (hV / 60.0 - hN)) * sV);
                        switch (hN)
                        {
                            case 0:
                                r = vV;
                                g = t;
                                b = p;
                                break;
                            case 1:
                                r = q;
                                g = vV;
                                b = p;
                                break;
                            case 2:
                                r = p;
                                g = vV;
                                b = t;
                                break;
                            case 3:
                                r = p;
                                g = q;
                                b = vV;
                                break;
                            case 4:
                                r = t;
                                g = p;
                                b = vV;
                                break;
                            case 5:
                                r = vV;
                                g = p;
                                b = q;
                                break;
                            default:
                                break;
                        }
                        rgbValue[x * 3 + y * w * 3] = (byte)(255.0 * b);
                        rgbValue[x * 3 + 1 + y * w * 3] = (byte)(255.0 * g);
                        rgbValue[x * 3 + 2 + y * w * 3] = (byte)(255.0 * r);
                    }
                }
                return rgbValue;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Get cmyk information.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <returns></returns>
        public static double[] CMYKValue(WriteableBitmap src)
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                double[] cmykValue = new double[w * h * 4];
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = temp[x * 4 + y * w * 4];
                        g = temp[x * 4 + 1 + y * w * 4];
                        r = temp[x * 4 + 2 + y * w * 4];
                        cmykValue[x * 4 + y * w * 4] = (double)(g + b);
                        cmykValue[x * 4 + 1 + y * w * 4] = (double)(r + b);
                        cmykValue[x * 4 + 2 + y * w * 4] = (double)(r + g);
                        cmykValue[x * 4 + 3 + y * w * 4] = (double)(Math.Min((g + b), Math.Min((r + b), (r + g))));
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return cmykValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert rgb to cmyk.
        /// </summary>
        /// <param name="rgbValue">The rgb information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] RGBtoCMYK(byte[] rgbValue, int w, int h)
        {
            if (rgbValue != null)
            {
                double[] cmykValue = new double[w * h * 4];
                int r = 0, g = 0, b = 0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        b = rgbValue[x * 3 + y * w * 3];
                        g = rgbValue[x * 3 + 1 + y * w * 3];
                        r = rgbValue[x * 3 + 2 + y * w * 3];
                        cmykValue[x * 4 + y * w * 4] = (double)(g + b);
                        cmykValue[x * 4 + 1 + y * w * 4] = (double)(r + b);
                        cmykValue[x * 4 + 2 + y * w * 4] = (double)(r + g);
                        cmykValue[x * 4 + 3 + y * w * 4] = (double)(Math.Min((g + b), Math.Min((r + b), (r + g))));
                    }
                }
                return cmykValue;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Convert cmyk to rgb.
        /// </summary>
        /// <param name="cmykValue">The cmyk information.</param>
        /// <param name="w">The width of source image.</param>
        /// <param name="h">The height of source image.</param>
        /// <returns></returns>
        public static double[] CMYKtoRGB(byte[] cmykValue, int w, int h)
        {
            if (cmykValue != null)
            {
                double[] rgbValue = new double[w * h * 3];
                double cV = 0, mV = 0, yV = 0,kV=0;
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        cV = cmykValue[x * 4 + y * w * 3];
                        mV = cmykValue[x * 4 + 1 + y * w * 3];
                        yV = cmykValue[x * 4 + 2 + y * w * 3];
                        kV = cmykValue[x * 4 + 3 + y * w * 3];
                        rgbValue[x * 3 + y * w * 3] = (byte)(0.5 * (mV + cV - yV));
                        rgbValue[x * 3 + 1 + y * w * 3] = (byte)(0.5 * (yV + cV - mV));
                        rgbValue[x * 3 + 2 + y * w * 3] = (byte)(0.5 * (mV + yV - cV));
                    }
                }
                return rgbValue;
            }
            else
            {
                return null;
            }
        }

最后,分享一个专业的图像处理网站(微像素),里面有很多源代码下载:

2019-02-11 10:24:46 limiyudianzi 阅读数 805

最为大家熟悉的色彩空间就是rgb色彩空间和灰度色彩空间了,除此之外HSV,YCbCr也都各有应用。这里我们就简单的介绍一下色彩空间变化,这就涉及到python中skimag.color的应用

首先skimage支持的色彩空间有:
[‘rgb’, ‘hsv’, ‘rgb cie’, ‘xyz’, ‘yuv’, ‘yiq’, ‘ypbpr’, ‘ycbcr’, ‘ydbdr’]
常用的操作有

# 转换色彩空间通用的方法
# arr是要转换的图片,fromspace是arr图片的色彩空间,
# tospace是要转换成为的色彩空间。
skimage.color.convert_colorspace(arr, fromspace, tospace)

#除此之外还有很多简短的方便的函数比如:
Skimage.color.rgb2gray(rgb)
Skimage.color.gray2rgb(gray)
Skimage.color.hsv2rgb(hsv)
Skimage.color.rgb2hsv(rgb)

下面我们就展示一个宇航员图片的例子,需要综合用到上一讲所涉及到的示例图片的读取,显示,以及显示图像的属性等知识。

import skimage
img = skimage.data.astronaut() #读取图片
skimage.io.imshow(img)
skimage.io.show()

img_gray = skimage.color.rgb2gray(img) #灰度图
skimage.io.imshow(img_gray)
skimage.io.show()

img_hsv = skimage.color.rgb2hsv(img) #hsv空间
skimage.io.imshow(img_hsv)
skimage.io.show()

在这里插入图片描述

上面是其对应的显示结果和属性,这里有一个坑就是变成了灰度图之后,整个图像会被归一化,还需要手动变成我们熟悉的0到255的强度,同时hsv空间的三个通道分别是色调H,饱和度S和明度V,色调是0到360度,其他两个都是0到1,这里变成hsv空间之后色调好像也被归一化了。之所以显示的这么魔性是因为数据的存储都是使用的numpy数据格式,并没有指明是什么色彩空间之类的,所以在imshow的时候应该就直接被当做了归一化的RGB图像进行显示了。

更多skimage教程请看这里

2018-02-02 14:50:32 u014030821 阅读数 2519

第六章 彩色图像处理

其实彩色图像的处理方法与灰度图像极其类似,很多时候我们把彩色图像分割成各分量的图像,然后使用灰度图像处理方法来处理它们。

一:颜色模型

1.1 RGB彩色模型

每种颜色出现在红、绿、蓝的原色光谱分量中。RGB原色值位于3个角上;二次色青色、深红色和黄色位于另外3个角上,黑色位于原点处,白色位于远离远点最远的角上。该模型中,灰度沿着连接这两点的直线从黑色延伸到白色。假定所有的颜色值都归一化了。
这里写图片描述

1.2 CMY和CMYK彩色模型

RGB模型为光的三基色,CMY描述的是颜料的三原色;一般应用于彩色打印机和复印机等。可由RGB转换得到(已经归一化):
这里写图片描述
等量的颜料原色青色、深红色和黄色可以生成黑色,但产生的黑色是不纯的,因此加入第四种颜色——黑色,构成CMYK彩色模型,及“四色打印”。

1.3 HSI彩色模型

RGB模型、CMY模型和其他类似的彩色模型都无法很好地适应人类实际上解释的颜色。因此,使用 色调、饱和度和亮度(HSI) 来描述物体,可以很好地符合人类视觉。
这里写图片描述

1.4 色彩转换

RGB->HSI:
这里写图片描述 这里写图片描述
这里写图片描述
这里写图片描述
HSI->RGB:
1. 0<=H<120:
这里写图片描述
2. 120<=H<240:
这里写图片描述
这里写图片描述
3. 240<=H<360:
这里写图片描述
这里写图片描述

二:彩色图像处理基础

2.1 伪彩色图像处理

伪彩色图像处理指基于一种指定的规则对灰度值赋以颜色的处理。伪彩色的主要应用是人目视视察和解释单幅图像或序列图像中的灰度级事件。(灰度图像->灰度分层处理->彩色图像)。

2.1.1 灰度分层

这里写图片描述
这里写图片描述

2.1.2 灰度到彩色变换

这里写图片描述
这里写图片描述

2.2 全彩色图像处理

令c代表RGB彩色空间的一个任意向量:
这里写图片描述
c的分量仅是一幅彩色图像在一点处的RGB分量,可以认为彩色分量是坐标(x,y)的函数:
这里写图片描述
即把彩色图像分解为各分量的灰度图像。
这里写图片描述

三:彩色图像处理

3.1 彩色变换

彩色变换主要涉及在单一色彩模型内处理彩色图像的分量,而不是这些分量在不同模型间的转换。
这里写图片描述
这里写图片描述
主要思路还是将彩色图像的各分量分开,以灰度图像处理的方式分别处理。
1. 补色;
2. 彩色分层;
3. 色调和彩色矫正;
4. 直方图处理;
5. 平滑和锐化;
6. 基于彩色的图像分割。

3.2 平滑和锐化

平滑:
这里写图片描述
这里写图片描述
锐化:
这里写图片描述

3.3 基于彩色的图像分割

  1. HSI彩色空间分割;
  2. RGB向量空间分割;
  3. 彩色边缘检测。
2017-03-20 14:59:37 dominating_ 阅读数 1363

原理介绍:


颜色空间也称彩色模型(又称彩色空间或彩色系统)它的用途是在某些标准下用通常可接受的方式对彩色加以说明。 本质上,彩色模型是坐标系统和子空间的阐述。位于系统的每种颜色都有单个点表示。现在使用的彩色模型很多,主要是由于彩色科学是一个包括很多应用的很宽的领域。 在彩色图像处理中,选择合适的彩色模型是很重要的。从应用的角度来看,人们提出的众多彩色模型可以分为两类。一类面向诸如彩色显示器或彩色打印机之类输出显示场合使用的硬设备。另一类面向视觉感知或者说以彩色处理分析为目的的应用,如动画中的彩色图形,各种图像处理的算法等。 


RGB(红绿蓝)


RGB是依据人眼识别的颜色定义出的空间,可表示大部分颜色。是图像处理中最基本、最常用、面向硬件的颜色空间,是一种光混合的体系。

RGB颜色空间最常用的用途就是显示器系统,彩色阴极射线管,彩色光栅图形的显示器都使用R、G、B数值来驱动R、G、B 电子枪发射电子,并分别激发荧光屏上的R、G、B三种颜色的荧光粉发出不同亮度的光线,并通过相加混合产生各种颜色。扫描仪也是通过吸收原稿经反射或透射而发送来的光线中的R、G、B成分,并用它来表示原稿的颜色。

模型:


可以看到RGB颜色模式用三维空间中的一个点表示一种颜色,每个点有三个分量,分别表示红、绿、蓝的亮度值,亮度值限定为【0,1】。在RGB模型的立方体中,原点对应的颜色为黑色,它的三个分量值都为0;距离原点最远的顶点对应的颜色为白色,它的三个分量值都为1。从黑色到白色的灰度值分布在这两个点的连线上,该虚线称为灰度线;立方体的其余各点对应不同的颜色,即三原色红、绿、蓝及其混合色黄、品红、青色。

HSI


HSI色彩空间是从人的视觉系统出发,用色调(Hue)、饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩。

H——表示颜色的相位角。红、绿、蓝分别相隔120度;互补色分别相差180度,即颜色的类别。
S——表示成所选颜色的纯度和该颜色最大的纯度之间的比率,范围:[0,  1],即颜色的深浅程度。
I——表示色彩的明亮程度,围:[0, 1],人眼对亮度很敏感!

模型:



可以看到HSI色彩空间和RGB色彩空间只是同一物理量的不同表示法,因而它们之间存在着转换关系:HSI颜色模式中的色调使用颜色类别表示,饱和度与颜色的白光光亮亮度刚好成反比,代表灰色与色调的比例,亮度是颜色的相对明暗程度。

CMYK


CMYK是一种依靠反光的色彩模式,我们是怎样阅读报纸的内容呢?是由阳光或灯光照射到报纸上,再反射到我们的眼中,才看到内容。它需要有外界光源,如果你在黑暗房间内是无法阅读报纸的。只要在屏幕上显示的图像,就是RGB模式表现的。只要是在印刷品上看到的图像,就是CMYK模式表现的。大多数在纸上沉积彩色颜料的设备,如彩色打印机和复印机,要求输入CMY数据,在内部进行RGB到CMY的转换。

模型:



青色Cyan、品红色Magenta、黄色Yellow是光的二次色,是颜料的颜色。而K取的是black最后一个字母,之所以不取首字母,是为了避免与蓝色(Blue)混淆。当红绿蓝三原色被混合时,会产生白色,当混合青色、品红色、黄色三原色时会产生黑色。从理论上来说,只需要CMY三种油墨就足够了,但是由于目前制造工艺还不能造出高纯度的油墨,CMY相加的结果实际是一种暗红色。

YUV


YUV 颜色空间在 PAL,NTSC和 SECAM复合颜色视频标准中使用。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。黑白电视系统只使用亮度信号(Y);彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,色度信号(U,V)以一种特殊的方式加入亮度信号,这样,黑白电视接收机能够显示正常的黑白图像,而彩色电视接收机能够对对附加的色度信号进行解码从而显示彩色图像。

人眼对色度的敏感程度要低于对亮度的敏感程度。人类视网膜上的视网膜杆细胞要多于视网膜锥细胞,说得通俗一些,视网膜杆细胞的作用就是识别亮度,而视网膜锥细胞的作用就是识别色度。所以,你的眼睛对于亮和暗的分辨要比对颜色的分辨精细一些。正是因为这个,在我们的视频存储中,没有必要存储全部颜色信号。所以把YUV分开存储,Y信号是黑白信号,是以全分辨率存储的,而色度信号并不是用全分辨率存储的。

模式:




颜色空间是一系列颜色的数学表现形式。三种最流行的颜色模型是RGB(用于计算机图形);YIQ,YUV或YCbCr(用于视频系统)和CMYK(用于彩色打印)。但是,这三种颜色没有一种和我们直觉概念上的色调,饱和度,亮度有直接的联系。这就使我们暂时去追寻其它的模型,如HIS和HSV,它们能简化编程,处理和终端用户操作。

RGB与HSI转换


RGB转HSI




HSI转RGB


给定 HSI空间中的 (h, s, l) 值定义的一个颜色,带有 h 在指示色相角度的值域 [0, 360)中,分别表示饱和度和亮度的s 和 l 在值域 [0, 1] 中,相应在 RGB 空间中的 (r, g, b) 三原色,带有分别对应于红色、绿色和蓝色的 r, g 和 b 也在值域 [0, 1] 中,它们可计算为:

首先,如果 s = 0,则结果的颜色是非彩色的、或灰色的。在这个特殊情况,r, g 和 b 都等于 l。注意 h 的值在这种情况下是未定义的。当 s ≠ 0 的时候,可以使用下列过程:



RGB转CMYK




RGB与YUV 转换


伽马校正后的转换




源码


考虑到RGB与CMYK、YUV转换很简单,所以这里展示RGB与HSI颜色互转的C++代码

  1. //================================================================================  
  2. /// @brief HLS <====> RGB  
  3. ///  
  4. /// [1]H是色相,代表了6种颜色,分成0~6区域,用一个模型来表述就是一个双(六)棱椎,其中的L是HSL立方体的主对角线。  
  5. //     RGB立方体的顶点:红、黄、绿、青、蓝和品红就成为HSL六角形的顶点,0-360度的范围内有6种颜色,但是它不是平均分布的,如绿色最多.  
  6. ///    H是0-360,L和S是0.00%-100.00%    
  7. //================================================================================  
  8. //HLS ---> RGB  
  9. void RGBtoHLS (int rgb, double& H, double& L, double& S)  
  10. {  
  11.     Color color(rgb);  
  12.     RGBtoHLS(color.R, color.G, color.B, H, L, S);  
  13. }  
  14.   
  15. //HLS ---> RGB  
  16. void RGBtoHLS (int r, int g, int b, double& H, double& L, double& S)  
  17. {  
  18.     int   n_cmax = max(r, max(g, b));  
  19.     int   n_cmin = min(r, min(g, b));  
  20.   
  21.     double Delta = 0;  
  22.     double Max = 0, Min = 0;  
  23.     double Redf = 0, Greenf = 0, Bluef = 0;  
  24.   
  25.     Redf    = (r / 255.0f);  
  26.     Greenf  = (g / 255.0f);  
  27.     Bluef   = (b / 255.0f);   
  28.   
  29.     Max     = max(max(Redf, Greenf), Bluef);  
  30.     Min     = min(min(Redf, Greenf), Bluef);  
  31.   
  32.     H = 0;  
  33.     L = (Max + Min) / 2.0f;  
  34.     S = 0;  
  35.   
  36.     if (Max == Min)  
  37.     {  
  38.         return;  
  39.     }  
  40.   
  41.     Delta = (Max - Min);  
  42.     if (L < 0.5)  
  43.         S = Delta / (Max + Min);  
  44.     else  
  45.         S = Delta / (2.0 - Max - Min);  
  46.   
  47.     if (Redf == Max)  
  48.     {  
  49.         if (Greenf >= Bluef)  
  50.         {  
  51.             H = (Greenf - Bluef) / Delta;  
  52.         }  
  53.         else  
  54.         {  
  55.             H = 6.0 + (Greenf - Bluef) / Delta;  
  56.         }  
  57.     }         
  58.     else if (Greenf == Max)  
  59.         H = 2.0 + (Bluef - Redf) / Delta;  
  60.     else  
  61.         H = 4.0 + (Redf - Greenf) / Delta;  
  62.   
  63.     H /= 6.0; //除以6,表示在那个部分。  
  64.   
  65.     if (H < 0.0)  
  66.         H += 1.0;     
  67.     if (H > 1)  
  68.         H -= 1;  
  69.   
  70.     H = (int)(H * 360); //转成[0, 360]  
  71. }  
  72.   
  73. void Color_HueToRgb(double p, double q, double Ht, double *Channel)  
  74. {  
  75.     if (Ht < 0.0)  
  76.         Ht += 1.0;  
  77.     else if (Ht > 1.0)  
  78.         Ht -= 1.0;  
  79.   
  80.     if ((6.0 * Ht) < 1.0)  
  81.         *Channel = (p + (q - p) * Ht * 6.0);  
  82.     else if ((2.0 * Ht) < 1.0)  
  83.         *Channel = (q);  
  84.     else if ((3.0 * Ht) < 2.0)  
  85.         *Channel = (p + (q - p) * ((2.0F / 3.0F) - Ht) * 6.0);  
  86.     else  
  87.         *Channel = (p);  
  88. }  
  89.   
  90. //RGB ---> HLS  
  91. void HLStoRGB (double H, double L, double S, BYTE &r, BYTE &g, BYTE &b)  
  92. {  
  93.     double M1 = 0, M2 = 0;  
  94.     double Redf = 0, Greenf = 0, Bluef = 0;  
  95.   
  96.     double hue = H / 360;  
  97.   
  98.     if (S == 0)//灰色  
  99.     {  
  100.         Redf    = L;  
  101.         Greenf  = L;  
  102.         Bluef   = L;  
  103.     }  
  104.     else  
  105.     {  
  106.         if (L <= 0.5)  
  107.             M2 = L * (1.0 + S);  
  108.         else  
  109.             M2 = L + S - L * S;  
  110.   
  111.         M1 = (2.0 * L - M2);  
  112.   
  113.         Color_HueToRgb(M1, M2, hue + (1.0F / 3.0F), &Redf);  
  114.         Color_HueToRgb(M1, M2, hue, &Greenf);  
  115.         Color_HueToRgb(M1, M2, hue - (1.0F / 3.0F), &Bluef);  
  116.     }  
  117.   
  118.     r = (BYTE)(Redf * 255);  
  119.     g = (BYTE)(Bluef * 255);  
  120.     b = (BYTE)(Greenf * 255);  
  121. }  
2017-02-23 22:04:40 Mac_lzq 阅读数 6263
参考博文:

RGB颜色空间 
RGB(red,green,blue)颜色空间最常用的用途就是显示器系统,彩色阴极射线管,彩色光栅图形的显示器 都使用R、G、B数值来驱动R、G、B 电子枪发射电子,并分别激发荧光屏上的R、G、B三种颜色的荧光粉发出不同亮度的光线,并通过相加混合产生各种颜色;扫描仪也是通过吸收原稿经反射或透射而发送来 的光线中的R、G、B成分,并用它来表示原稿的颜色。RGB色彩空间称为与设备相关的色彩空间,因为不同 的扫描仪扫描同一幅图像,会得到不同色彩的图像数据;不同型号的显示器显示同一幅图像,也会有不同 的色彩显示结果。显示器和扫描仪使用的RGB空间与CIE 1931 RGB真实三原色表色系统空间是不同的,后者 是与设备无关的颜色空间。btw:Photoshop的色彩选取器(Color Picker)。可以显示HSB、RGB、LAB和CMYK 色彩空间的每一种颜色的色彩值。

在计算机技术中使用最广泛的颜色空间是RGB颜色空间,它是一种与人的视觉系统结构密切相关的模型。根据人眼睛的结构,所有的颜色都可以看成三个基本颜色-红色(red)、绿色(green)和蓝色(blue)的不同组合,大部分显示器都采用这种颜色模型。对一幅三通道彩色数字图像对每个图像像素(x,y),需要指出三个矢量分量R、G、B;
根据美国国家电视制式委员会NTSC制式的标准,当白色的亮度用Y来表示是,它和红基色(R)、绿基色(G)、蓝基色(B)的关系可用如下的方程等式描述:

图1 RGB彩色空间

2 人视网膜中三种不同视锥细胞的光谱相对敏感性

        RGB对应到显示器的三个刺激值,组成三维正交坐标系统,该系统中任何颜色都落入RGB彩色立方体内,在RGB颜色模型中,黑色在原点处,白色位于离原点最远的角上,灰度级沿着这两点的连线分布,每一个分量图像都是其原色图像。

RGB颜色空间最大的优点就是适合于显示系统,直观且容易理解。但是对彩色描述上的应用还有以下不足:

(1) RGB颜色空间利用三个颜色分量的线性组合来表示颜色,因此不同的色彩难以用精确的数值来表示,定量分析困难。

(2) 在RGB颜色系统中,三个颜色分量之间是高度相关的,即只要亮度改变,三个分量都会相应的改变,如果一个颜色的某一个分量发生了一定程度的改变,那么这颜色很可能也要发生改变。

(3) RGB颜色空间是一种均匀性较差的颜色空间,人眼对于三个颜色分量的敏感程度是不一样的,如果颜色的相似性直接用欧氏距离来度量,其结果与人眼视觉会有较大的偏差。


HSV颜色空间 
HIS(Hue-Intensity-Saturation)颜色空间是图像处理中另外一个常用的颜色空间,它从人的视觉系统出发,用色调(Hue)、饱和度(Saturation或Chroma)和亮度(Intensity或Brightness)来描述颜色。HIS颜色空间可以用图3的圆锥空间模型来描述。其中,色调H由角度表示,其取值范围是 ,其中表示红色,表示黄色,表示绿色,表示蓝色,表示品红色。饱和度S是HIS彩色空间中轴线到彩色点的半径长度,彩色点离轴线的距离越近,表示颜色的白光越多。强度I用轴线方向上的高度表示,圆锥体的轴线描述了灰度级,强度最小值时为黑色,强度最大值时为白色。每个和轴线正交的切面上的点,其强度值都是相等的。

HSV(hue,saturation,value)颜色空间的模型对应于圆柱坐标系中的一个圆锥形子集,圆锥的顶面对应于V=1. 它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮。色彩H由绕V轴的旋转角给定。红色对应于 角度0° ,绿色对应于角度120°,蓝色对应于角度240°。在HSV颜色模型中,每一种颜色和它的补色相差180° 。 饱和度S取值从0到1,所以圆锥顶面的半径为1。HSV颜色模型所代表的颜色域是CIE色度图的一个子集,这个 模型中饱和度为百分之百的颜色,其纯度一般小于百分之百。在圆锥的顶点(即原点)处,V=0,H和S无定义, 代表黑色。圆锥的顶面中心处S=0,V=1,H无定义,代表白色。从该点到原点代表亮度渐暗的灰色,即具有不同 灰度的灰色。对于这些点,S=0,H的值无定义。可以说,HSV模型中的V轴对应于RGB颜色空间中的主对角线。 在圆锥顶面的圆周上的颜色,V=1,S=1,这种颜色是纯色。HSV模型对应于画家配色的方法。画家用改变色浓和 色深的方法从某种纯色获得不同色调的颜色,在一种纯色中加入白色以改变色浓,加入黑色以改变色深,同时 加入不同比例的白色,黑色即可获得各种不同的色调。前面这一大段我相信看起来也比较费劲,虽然已经尽力准确的去解释了,但我还是建议具体使用请着重数学公式,结合图示理解 ,效果更佳。



色相 (Hue):指物体传导或反射的波长。更常见的是以颜色如红色,橘色或绿色来辨识,取 0 到 360 度的数值来衡量。 
饱和度 (Saturation):又称色度,是指色彩的强度或纯度。饱和度代表灰色与色调的比例,并以 0% (灰色) 到 100% (完全饱和) 来衡量。

亮度 (Intensity):是指颜色的相对明暗度,通常以 0% (黑色) 到 100% (白色) 的百分比来衡量。

虽然这种描述HIS颜色空间的圆锥模型相当复杂,但却能把色调、亮度和饱和度的变化情形表现得很清楚。通常把色调和饱和度通称为色度,用来表示颜色的类别与深浅程度。由于人的视觉对亮度的敏感程度远强于对颜色浓淡的敏感程度,为了便于颜色处理和识别,经常采用HIS颜色空间,它比RGB颜色空间更符合人的视觉特性。在图像处理和计算机视觉中大量算法都可在HIS颜色空间上使用,它们可以分开处理而且是相互独立的。因此,在HIS颜色空间可以大大简化图像分析和处理的工作量
必须说明,HIS颜色空间和RGB颜色空间只是同一物理量的不同表示方法

图3 HIS/HSV彩色空间(

   图4 HIS/HSV彩色空间(二

在HIS颜色空间中进行彩色图像分割有两个优点:

(1)   H和S分量与人感受彩色的方式相似,彩色图像中的每一个均匀性彩色区域都对应一个相一致的色度和饱和度,色度和饱和度能够被用来进行独立于亮度的彩色区域分割。

(2)   I分量与颜色信息无关。


Lab 颜色空间
Lab颜色空间是由CIE(国际照明委员会)制定的一种色彩模式。自然界中任何一点色都可以在Lab空间中表达出来,它的色彩空间比RGB空间还要大。另 外,这种模式是以数字化方式来描述人的视觉感应, 与设备无关,所以它弥补了RGB和CMYK模式必须依赖于设备色彩特性的不足。 由于Lab的色彩空间要比RGB模式和CMYK模式的色彩空间大。这就意味着,RGB、CMYK所能描述的色彩信息,在Lab颜色空间中都能得以影身寸。
Lab颜色空间取坐标Lab,其中L亮度;a的正数代表红色,负端代表绿色;b的正数代表黄色, 负端代表兰色(a,b)有L=116f(y)-16, a=500[f(x/0.982)-f(y)], b=200[f(y)-f(z/1.183 )];其中: f(x)=7.787x+0.138, x〈0.008856; f(x)=(x)1/3,x〉0.008856

CIE-lab/luv色彩空间


CIE(Commission International del’Eclairage)国际标准照明委员会于1931年建立了一系列表示可见光谱的颜色空间标准。它有三个基本量,用X、Y、Z表示,通过X、Y、Z能够表示任何一种颜色,X、Y、Z的值能够利用R、G、B线性表示出来,相对于RGB颜色空间,XYZ颜色空间几乎能包含人类能够感觉到的所有颜色,但XYZ颜色空间仍然是一种不均匀的颜色空间。因此在CIE-XYZ颜色空间的基础上又有了CIE-Lab,CIE-Luv等颜色空间。 
国际照明委员会制定了Lab颜色空间,人类所能感觉到的任何颜色都可以在Lab颜色空间中表示出来,其颜色空间比RGB颜色空间还大,可以直接使用欧几里德距离来衡量两种颜色的差异性。这种模式是以数字化的方式来描述人的视觉感觉,它与显示器的色移、输出设备以及其他设备无关。Lab系统是一个优秀的亮度和彩色分离器,它在图像压缩方面很有用。其中L代表亮度,a的正方向代表红色,负方向代表绿色,b的正方向代表黄色,负方向代表蓝色。Lab颜色空间由XYZ转换而得的

图5 CIE-Lab彩色空间
YUV颜色空间 
在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD(点耦合器件)摄像机,它把摄得的彩色图像 信号,经分色、分别放大校正得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y、B-Y, 最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这就是我们常用的YUV色彩空间。 采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量, 那么这样表示的图就是黑白灰度图。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机 的兼容问题,使黑白电视机也能接收彩色信号。根据美国国家电视制式委员会,NTSC制式的标准,当白光的 亮度用Y来表示时,它和红、绿、蓝三色光的关系可用如下式的方程描述:Y=0.3R+0.59G+0.11B 这就是常用 的亮度公式。色差U、V是由B-Y、R-Y按不同比例压缩而成的。如果要由YUV空间转化成RGB空间,只要进行 相反的逆运算即可。与YUV色彩空间类似的还有Lab色彩空间,它也是用亮度和色差来描述色彩分量,其中L为 亮度、a和b分别为各色差分量。
YUV、YCbCr:

该颜色空间主要是基于人眼对亮度比对色度敏感这一特性而来的,将颜色分量和亮度分量分离开来。早期的黑白电视机和彩色电视机的原理也是有此而来的,具体转换公式可以参照ITU标准公式。


RGB三颜色分量转换为YUV422之后,图像的数据量便减少了1/3,如果是YUV420,则数据量便减少了一半。常用这种转换后的数据进行图像压缩编码。

也有一些图像边缘增强的算法,在此颜色空间展开。主要是因为色彩信息和亮度信息分离开来了。

CMYK颜色空间 
CMYK(cyan,magenta,yellow)颜色空间应用于印刷工业,印刷业通过青(C)、品(M)、黄(Y)三原色油墨的不同 网点面积率的叠印来表现丰富多彩的颜色和阶调,这便是三原色的CMY颜色空间。实际印刷中,一般采用青 (C)、品(M)、黄(Y)、黑(BK)四色印刷,在印刷的中间调至暗调增加黑版。当红绿蓝三原色被混合时,会产生 白色,但是当混合蓝绿色、紫红色和黄色三原色时会产生黑色。既然实际用的墨水并不会产生纯正的颜色, 黑色是包括在分开的颜色,而这模型称之为CMYK。CMYK颜色空间是和设备或者是印刷过程相关的,则工艺方法、 油墨的特性、纸张的特性等,不同的条件有不同的印刷结果。所以CMYK颜色空间称为与设备有关的表色空间。 而且,CMYK具有多值性,也就是说对同一种具有相同绝对色度的颜色,在相同的印刷过程前提下,可以用分种 CMYK数字组合来表示和印刷出来。这种特性给颜色管理带来了很多麻烦,同样也给控制带来了很多的灵活性。 在印刷过程中,必然要经过一个分色的过程,所谓分色就是将计算机中使 用的RGB颜色转换成印刷使用的CMYK 颜色。在转换过程中存在着两个复杂的问题,其一是这两个颜色空间在表现颜色的范围上不完全一样,RGB的 色域较大而CMYK则较小,因此就要进行色域压缩;其二是这两个颜色都是和具体的设备相关的,颜色本身没有 绝对性。因此就需要通过一个与设备无关的颜色空间来进行转换,即可以通过以上介绍的XYZ或LAB色空间来 进行转换。

CMY颜色空间 
CMY是一种颜料混合配色体系 

RGB是一种光混合配色体系

C - Cyan 〈互补色〉 R - Red  
M - Magenta 品红 〈互补色〉 G - Green 绿 
Y - Yellow 〈互补色〉 B - Blue

工业印刷中用前一种配色体系(因为是用颜料印刷),但是如果用CMY来配黑色的话很难,往往配出的是一种灰黑色,所以实际应用时还单独有黑色,即K - 黑色,故而工业中实用的印刷使用CMYK体系。

·C和R相反,M和G相反,Y和B相反

其他颜色模型:

HSL颜色空间 
HSL(hue,saturation,lightness)颜色空间,这个颜色空间都是用户台式机图形程序的颜色表示, 用六角形锥体表示自己的颜色模型。

HSB颜色空间 
HSB(hue,saturation,brightness)颜色空间,这个颜色空间都是用户台式机图形程序的颜色表示, 用六角形锥体表示自己的颜色模型。

Ycc颜色空间 
柯达发明的颜色空间,由于PhotoCd在存储图像的时候要经过一种模式压缩,所以 PhotoCd采用了 Ycc颜色空间,Ycc空间将亮度作由它的主要组件,具有两个 单独的颜色通道,采用Ycc颜色空间 来保存图像,可以节约存储空间。

XYZ颜色空间 
国际照明委员会(CIE)在进行了大量正常人视觉测量和统计,1931年建立了"标准色度观察者", 从而奠定了现代CIE标准色度学的定量基础。由于"标准色度观察者"用来标定光谱色时出现负刺激值,计算不便,也不易理解,因此1931年CIE在RGB 系统基础上,改用三个假想的原色X、Y、 Z建立了一个新的色度系统。将它匹配等能光谱的三刺激值,定名为"CIE1931 标准色度观察者 光谱三刺激值",简称为"CIE1931标准色度观察者"。这一系统叫做"CIE1931标准色度系统"或称为" 2° 视场XYZ色度系统"。CIEXYZ颜色空间稍加变换就可得到Yxy色彩空间,其中Y取三刺激值中Y的值, 表示亮度,x、y反映颜色的色度特性。定义如下:在色彩管理中,选择与设备无关的颜色空间是 十分重要的,与设备无关的颜色空间由国际照明委员会(CIE)制定,包括CIEXYZ和CIELAB两个标准。 它们包含了人眼所能辨别的全部颜色。而且,CIEYxy测色制的建立给定量的确定颜色创造了条件。 但是,在这一空间中,两种不同颜色之间的距离值并不能正确地反映人们色彩感觉差别的大小, 也就是说在CIEYxy色厦图中,在 不同的位置不同方向上颜色的宽容量是不同的,这就是Yxy颜色空间 的不均匀性。这一缺陷的存在,使得在Yxy及XYZ空间不能直观地评价颜色。




常用色彩空间

博文 来自: lpsl1882
没有更多推荐了,返回首页