计算机视觉及色彩空间RGB,HSV,HLS,Lab,LMS,XYZ,CMYK

色彩空间是个很重要的概念 在没有接触到这个概念之前我还以为色彩都是3基色RGB混合出来的. 后来才知道还有HSV
还有lab. 在我的概念里, 色彩空间是指 用不同角度的数学空间去描述一个客观现实中的色彩… 同一个色彩可以在不同的色彩空间对应不同的数值,但是它们都代表着同一个现实中的色彩. 那么色彩空间到底有什么用呢? RGB不就可以了么?
在我看来数学空间其实就是一种想象出来的小宇宙, 每个都有不同的角度出发描述图像,. 从一个数学空间映射到另外一个数学空间. 但是不同的数学空间在解决某些问题上比较容易做到. 例如RGB特别适合在数字设备上实现存储和转换还有运算.
那么我为什么要搜索整理出这篇文章呢?
我在工作中发现一张图片的识别和处理时 RGB 面临着一个非常困难的问题. RGB还有RGBA都非常难以做到对色彩中数据维度的高度分离, RGB中除了色彩信息,还包含了亮度和饱和度,还有光照角度信息, 物体深度信息, 这些信息都被压缩编码进了 RGB 中. 要想彻底的做到对图像进行识别, 需要更好的对RGB进行解码, 从RGB中分离出图像的各种维度的信息.
我个人的感觉,之所以目前图像识别如此困难, 很大程度上的原因是没有将图像分解的足够细.
图像不能只是3维的,更应该分解成多维的.可以方便的进行图像分析.
例如一个灰色像素 RGB(125,125,125) 并不仅仅只有一种可能会产生灰色, 有可能是影子造成的, 也有可能是本色就是灰色. 或者旁边反射上去的. 如此种种需要统筹判断.
再例如图像识别中非常重要的边缘检测,物体轮廓检测,作为图像识别的根基,却面临着非常多困难的, 现实世界中边缘有可能是白色的也有可能是灰色的. 例如下面的图.不可能用简单的灰度值大小进行判断. 也不可能通过求梯度和求二阶导数计算得出. 企图通过一个维度的数据就想识别图像的轮廓是不科学的.
在这里插入图片描述
经过opencv的Canny算法求轮廓只会的效果如下
在这里插入图片描述

调整参数s1为最大时
在这里插入图片描述
即便是在这张图上人工找到了合适的参数,但是换做另外一张图就又不合适了.
效果如下 s1和s2都是0的时候
在这里插入图片描述
s1是255
s2是0
在这里插入图片描述

图像轮廓检测目前没有普适性的参数. 目前我觉得最大的影响是光照和阴影对图像识别的带来了巨大的影响,其中光照和阴影我认为是影响图像识别的最主要因素, 如何排除掉光照和阴影对图片信息的影响. 我个人觉得需要一套算法能够将它们单独分离出来, 美女图二已经无法分辨出眼睛和嘴巴了.

目前的深度学习之所以能够做到这么好的效果很大程度上就是因为深度学习对图像识别是建立在多维度分析上的. 而这种分析维度的综合深度是人类程序员通过编程很难达到的深度和广度. 在这里面 梯度下降算法. 起着非常非常重要的作用. 很大程度上减轻了人类程序员寻找维度组合及其逻辑的工作量. 但是目前的深度学习在我看来还仍然无法做到真正的理解一张图片. 只有达到根据图片就可以建立3d模型时才是真正的理解一张图片. 而这里面所面临的挑战多的不胜枚举…
直觉告诉我, 要想真正的学会理解一张照片需要根据现实的反馈来进行学习, 而不是很多的乱七八糟的没有规律的照片的集合… 能做到根据一个物品的360度拍照视频,反向建立出3D模型, 我觉得才是真正的完全理解了图像.

关于图片信息最小维度,
我个人觉得, 需要将图像中的各种基础元素都分离出来,例如:光照,光照强度,光照色彩,光照角度,阴影,阴影角度,透明度,饱和度,色相,灰度,光泽,反光程度,等等都一次性必须计算出来. 会非常有利于后期的数据分析, 即便是这种解码工作非常耗时也是值得的. 后期我们可以通过专用芯片提高机器视觉的处理速度.

另外我觉得,图像识别本身就是一个解码的过程. 将眼睛接收到的混合的压缩信息拆分成独立维度的一个一个的信息然后重组或提取其中想要的信息.

解码是一个非常耗费计算量的工作. 人的眼睛经过上万年的进化达到今天的能力. 其复杂程度还是不容小觑的. 如何设计一套算法让计算机自动进化出这种能力还需要很多的难点需要克服.

以下的很多内容都是摘抄整理自网络.如有侵权请告知

色彩是人的眼睛对于不同频率的光线的不同感受,色彩既是客观存在的(不同频率的光)又是主观感知的,有认识差异。所以人类对于色彩的认识经历了极为漫长的过程,直到近代才逐步完善起来,但至今,人类仍不能说对色彩完全了解并准确表述了,许多概念不是那么容易理解。“色彩空间”一词源于西方的“Color Space”,又称作“色域”,色彩学中,人们建立了多种色彩模型,以一维、二维、三维甚至四维空间坐标来表示某一色彩,这种坐标系统所能定义的色彩范围即色彩空间。我们经常用到的色彩空间主要有RGB,HSV,HLS,Lab,LMS,XYZ,CMYK 等。

RGB
RGB 采用加法混色法,因为它是描述各种“光”通过何种比例来产生颜色。光线从暗黑开始不断叠加 产生颜色。 RGB描述的是红绿蓝三色光的数值。RGBA是在RGB上增加阿尔法通道实现透明效果。
RGB颜色空间以R(Red:红)、G(Green:绿)、B(Blue:蓝)三种基本色为基础,进行不同程度的叠加,产生丰富而广泛的颜色,所以俗称三基色模式。在大自然中有无穷多种不同的颜色,而人眼只能分辨有限种不同的颜色,RGB模式可表示一千六百多万种不同的颜色,在人眼看来它非常接近大自然的颜色,故又称为自然色彩模式。红绿蓝代表可见光谱中的三种基本颜色或称为三原色,每一种颜色按其亮度的不同分为256个等级。当色光三原色重叠时,由于不同的混色比例能产生各种中间色,例如,三原色相加可产生白色。所以RGB模式是加色过程。屏幕显示的基础是RGB模式,彩色印刷品却无法用RGB模式来产生各种彩色,所以,RGB模式常用于视频、多媒体与网页设计。

RGB色彩空间源于使用阴极射线管的彩色电视,RGB分别代表三个基色(R-红色、G-绿色、B-蓝色),具体的色彩值由三个基色叠加而成。在图像处理中,我们往往使用向量表示色彩的值,如(0,0,0)表示黑色、(255, 255, 255)表示白色。其中,255表示色彩空间被量化成255个数,最高亮度值为255(255 = 2^8 - 1,即每个色彩通道用8位表示)。在这个色彩空间中,有256256256种颜色。RGB色彩空间如下图所示(图片来自百度百科)。是一个包含Red、Green、Blue的三维空间。
注:
1、在OpenCV中,RGB色彩空间的顺序是BGR,千万不要弄错了
2、在Java的Bitmap中,RGB色彩空间被表示为ARGB,其中A代表透明度

RGBA
RGBA是代表Red(红色)Green(绿色)Blue(蓝色)和Alpha(透明度)的色彩空间。
虽然它有的时候被描述为一个颜色空间,但是它其实仅仅是RGB模型的附加了额外的信息。采用的颜色是RGB,可以属于任何一种RGB颜色空间,但是Catmull和Smith在1971至1972年间提出了这个不可或缺的alpha数值,使得alpha渲染和alpha合成变得可能。提出者以alpha来命名是源于经典的线性插值方程αA + (1-α)B所用的就是这个希腊字母。
alpha通道一般用作不透明度参数。如果一个像素的alpha通道数值为0%,那它就是完全透明的(也就是看不见的),而数值为100%则意味着一个完全不透明的像素(传统的数字图像)。在0%和100%之间的值则使得像素可以透过背景显示出来,就像透过玻璃(半透明性),这种效果是简单的二元透明性(透明或不透明)做不到的。它使数码合成变得容易。alpha通道值可以用百分比、整数或者像RGB参数那样用0到1的实数表示。
有时它也被写成ARGB(像RGBA一样,但是第一个数据是alpha),是Macromedia的产品使用的术语。比如,0x80FFFF00是50%透明的黄色,因为所有的参数都在0到255的范围内表示。0x80是128,大约是255的一半。
PNG是一种使用RGBA的图像格式。

HSV 六角锥体模型(Hexcone Model)

HSV色彩空间(Hue-色调、Saturation-饱和度、Value-值)将亮度从色彩中分解出来,在图像增强算法中用途很广。在图像处理项目中,经常将图像从RGB色彩空间转换到了HSV色彩空间,以便更好地感知图像颜色,利用HSV分量从图像中提取感兴趣的区域。

HSV色彩空间也被称为HSB(色调、饱和度、亮度),在PS中常被用到。

HSV色彩空间如下图所示,用一个倒圆锥体表示整个色彩空间:
在这里插入图片描述
色调H
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°;
饱和度S
饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
明度V
明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
RGB和CMY颜色模型都是面向硬件的,而HSV(Hue Saturation Value)颜色模型是面向用户的。
HSV模型的三维表示从RGB立方体演化而来。设想从RGB沿立方体对角线的白色顶点向黑色顶点观察,就可以看到立方体的六边形外形。六边形边界表示色彩,水平轴表示纯度,明度沿垂直轴测量。

以下部分摘自 https://www.cnblogs.com/JorSean/p/9412952.html
RGB到HSV的转换的Demo
(1) 使用OpenCV的cv2.cvtColor(src, cv2.COLOR_BGR2HSV)

OpenCV为我们提供了现成的函数cvtColor(),帮助我们将图像从BGR转换到HSV。

# -*- coding:utf-8 -*-

import cv2

"""
功能:读取一张图片,显示出来,并转化为HSV色彩空间
"""
image = cv2.imread('images/my_wife2.jpg') # 根据路径读取一张图片
cv2.imshow("BGR", image) # 显示图片


# 转化图片到HSV色彩空间
dst = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
cv2.imshow("HSV", dst) # 显示图片
cv2.waitKey(0) # 等待键盘触发事件,释放窗口

输出结果如下

在这里插入图片描述
挺好看的美女,结果被弄成了这个样子。一些初学者包括我自己有时会问,为什么要把好端端的图片转成HSV色彩空间呢。其实这样做大有用处,比如我们要提取美女的头发区域,就可以通过设置HSV色彩空间的高低阈值来做。

# -*- coding:utf-8 -*-

import cv2
import numpy as np   # ------------------改变1

"""
功能:读取一张图片,显示出来,并转化为HSV色彩空间
"""
image = cv2.imread('images/my_wife2.jpg') # 根据路径读取一张图片
cv2.imshow("BGR", image) # 显示图片


# 转化图片到HSV色彩空间
dst = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
cv2.imshow("HSV", dst) # 显示图片


# 根据HSV提取头发 --------------------------------改变2
low_hsv = np.array([0, 0, 46])
high_hsv = np.array([200, 40, 220])
dst = cv2.inRange(dst, low_hsv, high_hsv)
cv2.imshow("result", dst) # 显示图片

cv2.waitKey(0) # 等待键盘触发事件,释放窗口

程序的运行效果如下。我们看到,头发区域显示为白色,这样我们就初步地提取出了头发区域。当然这个效果并不理想,是因为我们设定的阈值不好,如果能动态地设定阈值就好了。
在这里插入图片描述

我们可以利用滑块动态地设置阈值,一边拖动滑块,一边观察图像。OpenCV提供了createTrackbar(),用于创建滑块。代码如下:

# -*- coding:utf-8 -*-

import cv2
import numpy as np

"""
功能:读取一张图片,显示出来,转化为HSV色彩空间
     并通过滑块调节HSV阈值,实时显示
"""

image = cv2.imread('images/my_wife2.jpg') # 根据路径读取一张图片
cv2.imshow("BGR", image) # 显示图片

hsv_low = np.array([0, 0, 0])
hsv_high = np.array([0, 0, 0])

# 下面几个函数,写得有点冗余

def h_low(value):
    hsv_low[0] = value

def h_high(value):
    hsv_high[0] = value

def s_low(value):
    hsv_low[1] = value

def s_high(value):
    hsv_high[1] = value

def v_low(value):
    hsv_low[2] = value

def v_high(value):
    hsv_high[2] = value

cv2.namedWindow('image')
cv2.createTrackbar('H low', 'image', 0, 255, h_low) 
cv2.createTrackbar('H high', 'image', 0, 255, h_high)
cv2.createTrackbar('S low', 'image', 0, 255, s_low)
cv2.createTrackbar('S high', 'image', 0, 255, s_high)
cv2.createTrackbar('V low', 'image', 0, 255, v_low)
cv2.createTrackbar('V high', 'image', 0, 255, v_high)

while True:
    dst = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # BGR转HSV
    dst = cv2.inRange(dst, hsv_low, hsv_high) # 通过HSV的高低阈值,提取图像部分区域
    cv2.imshow('dst', dst)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cv2.destroyAllWindows()

程序运行的效果如下,我们拉动滑块会自动改变HSV的高低阈值,进而根据高低阈值提取的图像区域也会改变:
在这里插入图片描述

HLS
原文来自 https://blog.csdn.net/zhangping1987/article/details/73699335
HLS颜色模型
HLS颜色空间,三个分量分别是色相(H)、亮度(L)、饱和度(S),这三个分量进行数字化处理,取值范围为:
在这里插入图片描述

模型可以通过以下两幅图像理解
在这里插入图片描述
在这里插入图片描述

调节L分量,观察效果
从上图种可以看出,我们固定一个颜色(H),那么随着饱和度(S,Chroma)的增加,颜色越来越深,OpenCV通过定义函数cvtColor实现BGR颜色空间向HLS颜色空间的转换,使用该函数时,最好将输入图像的BGR值归一到[0,1]范围,可以通过调节亮度(L分量)观察L造成的影响:


#include<opencv2/core.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
using namespace cv;
#include<string>
using namespace std;
//颜色显示
Mat colorMap;
//H的取值范围[0,360]
int H = 180;
int MAX_H = 360;
//L的取值范围[0,1]
int L = 0;
int MAX_L = 255;//可以自定义设定
//S的取值范围[0,1]
int S = 0;
int MAX_S = 255;
//颜色显示窗口
string showColor = "H-S";
//回调函数
void callback(int, void*);
int main(int argc, char*argv[])
{
	colorMap.create(Size(MAX_S + 1, MAX_H + 1), CV_32FC3);
	//命名窗口
	namedWindow(showColor, WINDOW_GUI_EXPANDED);
	//调节 V 分量
	createTrackbar("L分量", showColor, &L, MAX_L, callback);
	waitKey(0);
	return 0;
}
void callback(int, void*)
{
	for (int h = 0; h < MAX_H + 1; h++)
	{
		for (int s = 0; s < MAX_S + 1; s++)
		{
			colorMap.at<Vec3f>(h, s) = Vec3f(h, L / float(MAX_L), s / float(MAX_S));
		}
	}
	//颜色空间的转换
	cvtColor(colorMap, colorMap, COLOR_HLS2BGR);
	//显示颜色
	imshow(showColor, colorMap);
}

上述程序的运行界面如下,通过调节L分量,观察其效果:
在这里插入图片描述

可以发现随着L的增大,所有的颜色逐渐消失,显示为白色,符合模型。

调节S分量观察其效果

#include<opencv2/core.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
using namespace cv;
#include<string>
using namespace std;
//颜色显示
Mat colorMap;
//H的取值范围[0,360]
int H = 180;
int MAX_H = 360;
//L的取值范围[0,1]
int L = 0;
int MAX_L = 255;//可以自定义设定
//S的取值范围[0,1]
int S = 0;
int MAX_S = 255;
//颜色显示窗口
string showColor = "H-L";
//回调函数
void callback(int, void*);
int main(int argc, char*argv[])
{
	colorMap.create(Size(MAX_L + 1, MAX_H + 1), CV_32FC3);
	//命名窗口
	namedWindow(showColor, WINDOW_GUI_EXPANDED);
	//调节 V 分量
	createTrackbar("S分量", showColor, &S, MAX_S, callback);
	waitKey(0);
	return 0;
}
void callback(int, void*)
{
	for (int h = 0; h < MAX_H + 1; h++)
	{
		for (int l = 0; l < MAX_L + 1; l++)
		{
			colorMap.at<Vec3f>(h, l) = Vec3f(h, l / float(MAX_L), S / float(MAX_S));
		}
	}
	//颜色空间的转换
	cvtColor(colorMap, colorMap, COLOR_HLS2BGR);
	//显示颜色
	imshow(showColor, colorMap);
}

运行结果如下:
在这里插入图片描述

可以发现S很小时,几乎看不到颜色,随着S的增大,颜色信息也越来越明显。

通过上面显示的图谱可以看出,可以通过分割H分量,确定颜色。

调节H分量

#include<opencv2/core.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
using namespace cv;
#include<string>
using namespace std;
//颜色显示
Mat colorMap;
//H的取值范围[0,360]
int H = 180;
int MAX_H = 360;
//L的取值范围[0,1]
int L = 0;
int MAX_L = 255;//可以自定义设定
//S的取值范围[0,1]
int S = 0;
int MAX_S = 255;
//颜色显示窗口
string showColor = "L-S";
//回调函数
void callback(int, void*);
int main(int argc, char*argv[])
{
	colorMap.create(Size(MAX_S + 1, MAX_L + 1), CV_32FC3);
	//命名窗口
	namedWindow(showColor, WINDOW_GUI_EXPANDED);
	//调节 H 分量
	createTrackbar("H分量", showColor, &H, MAX_H, callback);
	callback(0, 0);
	waitKey(0);
	return 0;
}
void callback(int, void*)
{
	for (int l = 0; l < MAX_L + 1; l++)
	{
		for (int s = 0; s < MAX_S + 1; s++)
		{
			colorMap.at<Vec3f>(l, s) = Vec3f(H, l / float(MAX_L), s / float(MAX_S));
		}
	}
	//颜色空间的转换
	cvtColor(colorMap, colorMap, COLOR_HLS2BGR);
	//显示颜色
	imshow(showColor, colorMap);
}

效果如下:
在这里插入图片描述

观察到L很大或者很小时,H的变换颜色值的变化非常小

Lab (lαβ)
以下内容来自 https://blog.csdn.net/qq_38701868/article/details/89433038 和 百度百科

Lab模式是根据Commission International Eclairage(CIE)在1931年所制定的一种测定颜色的国际标准建立的。于1976年被改进,并且命名的一种色彩模式。Lab颜色模型弥补了RGB和CMYK两种色彩模式的不足。它是一种设备无关的颜色模型,也是一种基于生理特征的颜色模型。 [1] Lab颜色模型由三个要素组成,一个要素是亮度(L),a 和b是两个颜色通道。a包括的颜色是从深绿色(低亮度值)到灰色(中亮度值)再到亮粉红色(高亮度值);b是从亮蓝色(低亮度值)到灰色(中亮度值)再到黄色(高亮度值)。因此,这种颜色混合后将产生具有明亮效果的色彩。

Lab模式既不依赖光线,也不依赖于颜料,它是CIE组织确定的一个理论上包括了人眼可以看见的所有色彩的色彩模式。Lab模式弥补了RGB和CMYK两种色彩模式的不足。同RGB颜色空间相比,Lab是一种不常用的色彩空间。它是在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。1976年,经修改后被正式命名为CIELab。它是一种设备无关的颜色系统,也是一种基于生理特征的颜色系统。这也就意味着,它是用数字化的方法来描述人的视觉感应。Lab颜色空间中的L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;a表示从红色到绿色的范围,取值范围是[127,-128];b表示从黄色到蓝色的范围,取值范围是[127,-128]。下图所示为Lab颜色空间的图示; [1]
在这里插入图片描述
色彩空间一方面要符合人眼的视觉感知特性,另一方面应方便图像的处理。图像色彩迁移的过程是一个改变图像颜色基调的过程,通常希望在改变图像的一个颜色属性时,不改变图像其它的颜色属性。由前面的介绍可知,RGB空间的三通道具有很强的相关性,而lαβ空间的各通道具有最小的相关性。所以,在lαβ空间对图像的颜色进行出来将会变得十分方便。因此,选择在lαβ空间进行图像间的色彩迁移,这就需要将图像从RGB空间转换到lαβ空间。
1.从RGB空间到lαβ空间的转换

需要进行3次变换,即RGB->CIEXYZ->LMS->lαβ,具体步骤如下:

1)从RGB空间到CIE XYZ空间的转换
在这里插入图片描述

2)从CIE XYZ空间到LMS空间的转换
在这里插入图片描述

通过1、2可以得到RGB空间到LMS空间的转换
在这里插入图片描述

   由于数据在LMS空间比较分散,所以进一步将其转换到以10为底的对数空间,这样不仅使数据分布更加聚敛,而且符号人类对于颜色感觉的心理物理学研究结果。

在这里插入图片描述

3)从LMS空间到lαβ空间的转换
在这里插入图片描述

这一变换是基于对数据的主成分分析(PCA,Principal ComponentAnalysis)得到的,其中l为第一主成分,α为第二主成分,β为第三主成分。

经过这三个步骤就完成了从RGB空间到lαβ空间的转换。

色彩空间的逆转换

当图像在lαβ空间进行处理之后,为了显示处理的结果,需要把图像转换到RGB空间,具体步骤为:

1)从lαβ空间到LMS对数空间的转换

在这里插入图片描述

2)从LMS对数空间到LMS线性空间的转换

在这里插入图片描述

3)从LMS空间到RGB空间的转换

在这里插入图片描述

添上C++代码:

void RgbToLab(BYTE R,BYTE G,BYTE B,double& l,double& a,double& b)
{
	double L = 0.3811*R + 0.5783*G + 0.0402*B;
	double M = 0.1967*R + 0.7244*G + 0.0782*B;
	double S = 0.0241*R + 0.1288*G + 0.8444*B;
 
	//若RGB值均为0,则LMS为0,防止数学错误log0
	if(L!=0) L = log(L)/log(10);
	if(M!=0) M = log(M)/log(10);
	if(S!=0) S = log(S)/log(10);
 
	l = (L + M + S)/sqrt(3);
	a = (L + M - 2*S)/sqrt(6);
	b = (L - M)/sqrt(2);
 
}
void LabToRgb(double l,double a,double b,BYTE& R,BYTE& G,BYTE& B)
{
	l /= sqrt(3);
	a /= sqrt(6); 
	b /= sqrt(2);
	double L = l + a + b;
	double M = l + a - b;
	double S = l - 2*a;
 
	L = pow(10,L);
	M = pow(10,M);
	S = pow(10,S);
 
	double dR = 4.4679*L - 3.5873*M + 0.1193*S;
	double dG = -1.2186*L + 2.3809*M - 0.1624*S;
	double dB = 0.0497*L - 0.2439*M + 1.2045*S;
 
	//防止溢出,若求得RGB值大于255则置为255,若小于0则置为0
	if (dR>255) R=255;
	else if (dR<0) R=0;
	else R = BYTE(dR);
 
	if (dG>255) G=255;
	else if (dG<0) G=0;
	else G = BYTE(dG);
 
	if (dB>255) B=255;
	else if (dB<0) B=0;
	else B = BYTE(dB);
}

LMS
在这里插入图片描述

LMS是由人眼的三种锥体的响应表示的颜色空间,以其在长波长,中波长和短波长处的响应度(灵敏度)峰命名。

在执行色适应时估计样本在不同光源下的外观时,通常使用LMS色彩空间。当一个或多个锥体有缺陷时,它也可用于色盲的研究。

理论
所有颜色都可以通过第一个格拉斯曼定律由三原色表示(对于人类观察者)。因此,可以在三维向量空间中为每个颜色阴影分配颜色位置。这种方法是抽象的象征主义,它是着色方法,颜色的比色法和技术处理所必需的,例如该屏幕的颜色再现。色彩空间适用于不同的任务,并用作CIE标准色彩空间,RGB色彩空间,CMYK色彩空间或LAB色彩空间。

直接来自光源或从表面间接的可见光范围内的辐射会产生颜色刺激。这在人类视觉器官的三个锥体中产生颜色价值 – 颜色值。在身体的后续过程中,这被视为色调。术语“三刺激”用于色心的“刺激”反应,尽管该术语用于修正的标准化合价。

为了说明,图中显示了引脚的“光谱价”。使用显微镜光谱仪直接在人类L,M和S锥以及人体棒上测量这些值。此外,这些读数还记录在由Bowmaker执行的恒河猴上。

每只眼睛的颜色受体具有单独的光谱灵敏度。在感知过程中,它被塑造成神经系统中特定的感官印象。这适用于每只眼睛,无论是动物还是人类,以及随后的神经仪器。每个正常颜色的人都有三种类型的“颜色敏感”锥体。这些被称为L,M和S锥的灵敏度最大值的位置。

在德语文献中有时会设置为S针K针。 L锥体主要感知来自长波红色范围的辐射的颜色刺激,M锥体中间绿色区域和S / K锥化该光谱的短波蓝色范围。视觉接收系统还包括棒,英语:棒。

尽管这些锥体的光谱吸收特性(例如由遗传变异引起)的个体差异以及由个人染色或年龄由浊度确定的眼睛中的晶状体或玻璃体的特定影响,但吸收曲线很好地一致对于所有正常视力的人,

可感知的颜色刺激的整体,即颜色,最终映射到这三个量L,M,S。在“客观世界”中,每个光谱分布的强度分别为0%到100%甚至连续分级)波长在约380nm和780nm之间的颜色刺激。

偶尔,感觉最大值之后的这三个致因色值也由R(ot),G(绿),B(lau)表示。由于这可能导致与RGB色彩空间的坐标混淆,所以P,D,T也是常见的,由此在失色的受体中使用失败的受体,即P [rotanopia],D [uteropanopia]和T [ritanopie] 。另一个系统使用希腊字母ρ,γ,β。 Rho代表L-或R-,γ代表M-或G-,β代表S-锥或蓝色敏感的。

它可以形成一个三维向量空间,它由三个轴L,M,S所跨越。

光谱颜色是比色法中光谱的足够窄的部分,带宽Δλ几乎为0纳米,实际上最多可达1纳米。

历史
单个吸收光谱L(λ),M(λ)和S(λ)的测量是一项复杂的测量任务。 CIE系统的基础由Maxwell,König,Dieterici和Abney的测量和工作奠定,这些测量和工作在1922年由OSA(美国光学学会)总结并以编辑形式出版。由于当时测量的可能性和准确性不足,David Wright(1928)和John Guild(1931)独立进行了新的更准确的色彩匹配和光度比较,并创建了新的基础数据库。各自的数据非常吻合,也确认了在准确度范围内的旧测量数据。 1931年,Wright和Guild的数据被CIE International推荐为数据库。 Stiles,Burch和Speranskaya后来提供了扩展该系统的进一步数据,并确认了Wright和Guild的测量结果。然后Bowmaker使用显微镜光谱仪测量直接在物体上的锥体的吸收特性。直接测量显示LMS灵敏度值只能间接计算到该点,与测量结果(即实际值)非常吻合。

由于用于技术目的的原始LMS色彩空间包含一些缺点,所以销价LMS被虚拟标准价XYZ替代并且基于CIE标准1931.由于这些计量原因,个体的数目限于总共17个选定个体在20世纪30年代。公会本人只对7人进行了测量。这仍然被认为是进一步的缺点和潜在的错误来源。尽管如此,Stiles在1955年的后续测量中发现,来自这17个人的数据代表并保证了2°标准观察者的充分表现。然而,由于CIE标准值今天盛行,主要是通过使用计算机技术的DIN99色彩空间等转换来校正。

为了适应偏离标准观察者的所有正常观察的观察者,对CIE数据应用2°和10°标准观察者的补充数据集(标准偏差观测者,标准偏差观测者)。

XYZ
XYZ表色系统,1931CIE-XYZ系统,就是在RGB系统的基础上,用数学方法,选用三个理想的原色来代替实际的三原色,从而将CIE-RGB系统中的光谱三刺激值和色度坐标r、g、b均变为正值。
国际照明委员会(CIE)在进行bai了大量正常人视觉测量和统计du,1931年建立了标准色zhi度观察dao者, 从而奠定了现代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空间不能直观地评价颜色。

在这里插入图片描述

CMYK

当阳光照射到一个物体上时,这个物体将吸收一部分光线,并将剩下的光线进行反射,反射的光线就是我们所看见的物体颜色。这是一种减色色彩模式,同时也是与RGB模式的根本不同之处。不但我们看物体的颜色时用到了这种减色模式,而且在纸上印刷时应用的也是这种减色模式。CMYK代表印刷上用的四种颜色,C代表青色(Cyan),M代表洋红色(Magenta),Y代表黄色(Yellow),K代表黑色(Black)。因为在实际应用中,青色、洋红色和黄色很难叠加形成真正的黑色,最多不过是褐色而已。因此才引入了K——黑色。黑色的作用是强化暗调,加深暗部色彩。

CMYK 印刷过程中使用减法混色法,因为它描述的是需要使用何种油墨,通过光的反射显示出颜色。它是在一种白色介质(画板,页面等)上使用油墨来体现图像。CMYK描述的是青,品红,黄和黑四种油墨的数值。根据不同的油墨,介质,和印刷特性,存在多种CMYK色彩空间。(可以通过色点扩张或者转换各种油墨数值从而得到不同的外观).

CMYK模式俗称四色打印模式,是最佳的打印模式。但是在进行实际打印时,两种模式存在转换问题,具体原因如下:

     1.  CMYK模式编辑虽然能够避免色彩的损失,但运算速度很慢。主要原因如下:

           1)、即使在CMYK模式下工作,Photoshop也必须将CMYK模式转变为显示器所使用的RGB模式。

           2)、对于同样的图像,RGB模式只需要处理三个通道即可,而CMYK模式则需要处理四个。

     2.  用户所使用的扫描仪和显示器都是RGB设备,所以无论什么时候使用CMYK模式工作都有把RGB模式转换为CMYK模式这样一个过程。因此,是否应用CMYK模式进行编辑都存在RGB模式和CMYK模式转换的问题。

   对于RGB模式和CMYK模式转换的问题,可以先用RGB模式进行编辑工作,再用CMYK模式进行打印工作,在打印前才进行转换,然后加入必要的色彩校正,锐化和修整。这样虽然使Photoshop在CMYK模式下速度慢一些,但可节省大部分编辑时间。这种打印前的模式转换,并不是避免图像损失最佳的途径,最佳方法是将Lab模式和CMYK模式相结合使用,这样可以最大程度的减少图像失真。

优点:可以满足打印的需求,解决RGB不能打印的问题
缺点:一定程度上存在色彩的缺失,运行速度慢

接下来的部分是来自另外一个网址. 为防止如此重要的文章丢失我这里就再复制黏贴一次. 全当备份
接下来的部分是来自另外一个网址. 为防止如此重要的文章丢失我这里就再复制黏贴一次. 全当备份
接下来的部分是来自另外一个网址. 为防止如此重要的文章丢失我这里就再复制黏贴一次. 全当备份
接下来的部分是来自另外一个网址. 为防止如此重要的文章丢失我这里就再复制黏贴一次. 全当备份
原文在 https://www.cnblogs.com/free-thinker/p/4831903.html

在做图像处理时,我们一般采用的是RGB空间,但是在某些特殊情况下,我们也会用到其他的颜色空间。本文主要介绍一些常见的颜色空间的概念和转换公式。

颜色的实质是一种光波。它的存在是因为有三个实体:光线、被观察的对象以及观察者。人眼是把颜色当作由被观察对象吸收或者反射不同波长的光波形成的。例如,当在一个晴朗的日子里,我们看到阳光下的某物体呈现红色时,那是因为该物体吸收了其它波长的光,而把红色波长的光反射到我们人眼里的缘故。当然,我们人眼所能感受到的只是波长在可见光范围内的光波信号。当各种不同波长的光信号一同进入我们的眼睛的某一点时,我们的视觉器官会将它们混合起来,作为一种颜色接受下来。同样我们在对图像进行颜色处理时,也要进行颜色的混合,但我们要遵循一定的规则,即我们是在不同颜色模式下对颜色进行处理的。

1.RGB颜色模式

虽然可见光的波长有一定的范围,但我们在处理颜色时并不需要将每一种波长的颜色都单独表示。因为自然界中所有的颜色都可以用红、绿、蓝(RGB)这三种颜色波长的不同强度组合而得,这就是人们常说的三基色原理。因此,这三种光常被人们称为三基色或三原色。有时候我们亦称这三种基色为添加色(Additive Colors),这是因为当我们把不同光的波长加到一起的时候,得到的将会是更加明亮的颜色。把三种基色交互重叠,就产生了次混合色:青(Cyan)、洋红(Magenta)、黄(Yellow)。这同时也引出了互补色(Complement Colors)的概念。基色和次混合色是彼此的互补色,即彼此之间最不一样的颜色。例如青色由蓝色和绿色构成,而红色是缺少的一种颜色,因此青色和红色构成了彼此的互补色。在数字视频中,对RGB三基色各进行8位编码就构成了大约16.7万种颜色,这就是我们常说的真彩色。顺便提一句,电视机和计算机的监视器都是基于RGB颜色模式来创建其颜色的。

2.Lab颜色模式

Lab颜色是由RGB三基色转换而来的,它是由RGB模式转换为HSB模式和CMYK模式的桥梁。该颜色模式由一个发光率(Luminance)和两个颜色(a,b)轴组成。它由颜色轴所构成的平面上的环形线来表示颜色的变化,其中径向表示色饱和度的变化,自内向外,饱和度逐渐增高;圆周方向表示色调的变化,每个圆周形成一个色环;而不同的发光率表示不同的亮度并对应不同环形颜色变化线。它是一种具有“独立于设备”的颜色模式,即不论使用任何一种监视器或者打印机,Lab的颜色不变。

RGB=>Lab


|X|   |0.433910  0.376220  0.189860| |R/255|
|Y| = |0.212649  0.715169  0.072182|*|G/255|
|Z|   |0.017756  0.109478  0.872915| |B/255|

L = 116*Y
1/3

for Y>0.008856
	L = 903.3*Y      for Y<=0.008856

a = 500*(f(X)-f(Y))
b = 200*(f(Y)-f(Z))
其中  f(t)=t
1/3

for t>0.008856
      f(t)=7.787*t+16/116    for t<=0.008856

3.HSB颜色模式

从心理学的角度来看,颜色有三个要素:色泽(Hue)、饱和度(Saturation)和亮度(Brightness)。HSB颜色模式便是基于人对颜色的心理感受的一种颜色模式。它是由RGB三基色转换为Lab模式,再在Lab模式的基础上考虑了人对颜色的心理感受这一因素而转换成的。因此这种颜色模式比较符合人的视觉感受,让人觉得更加直观一些。它可由底与底对接的两个圆锥体立体模型来表示,其中轴向表示亮度,自上而下由白变黑;径向表示色饱和度,自内向外逐渐变高;而圆周方向,则表示色调的变化,形成色环。

RGB=>HSB

V=max(R,G,B)
S=(V-min(R,G,B))*255/V   if V!=0, 0 otherwise

       (G - B)*60/S,  if V=R
H= 180+(B - R)*60/S,  if V=G
   240+(R - G)*60/S,  if V=B

若 H<0,则 H=H+360
使用上面从 0° 到 360° 变化的公式计算色调( hue)值,确保它们被 2 除后能试用于8位。

4.YUV颜色模式

这是电视系统中常用的颜色模式,即电视中所谓的分量(Component)信号。该模式由一个亮度信号Y和两个色差信号U、V组成。它是利用了人眼对亮度信号敏感而对色度信号相对不敏感的特点,将RGB颜色通过亮度信号公式Y=039R+050G+011B转换为一个亮度信号Y和两个色差分量信号U(R-Y)、V(B-Y),即对色差信号进行了频带压缩。毫无疑问,这是以牺牲信号的质量为代价的。

RGB<=>YUV

Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B

R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U

5.CMYK颜色模式

这是彩色印刷使用的一种颜色模式。它由青(Cyan)、洋红(Magenta)、黄(Yellow)和黑(Black)四种颜色组成。其中黑色之所以用K来表示,是为避免和RGB三基色中的蓝色(Blue,用B表示)发生混淆。该种模式的创建基础和RGB不同,它不是靠增加光线,而是靠减去光线,因为和监视器或者电视机不同的是,打印纸不能创建光源,它不会发射光线,只能吸收和反射光线。因此通过对上述四种颜色的组合,便可以产生可见光谱中的绝大部分颜色了。

RGB<=CMYK

R = (255 - C) * ((255 - K) / 255) 
G = (255 - M) * ((255 - K) / 255) 
B = (255 - Y) * ((255 - K) / 255) 

6.部分程序code

HSI=>RGB

void HSI2RGB (BYTE &BR,BYTE &BG,BYTE &BB,BYTE BH,BYTE BS,BYTE BI)
{
int nHValue = static_cast<int>(BH);
int nSValue = static_cast<int>(BS);
int nLValue = static_cast<int>(BI);

float fHAngle = ((float)nHValue ) / 255 * 360;

float H = fHAngle / 180 * PI;
float S = ((float)nSValue ) / 100;
float I = ((float)nLValue ) / 100;

float R = -1;
float G = -1;
float B = -1;

if(fHAngle >= 0 && fHAngle < 120)
{
  B = I * ( 1.0 - S );
  R = I * ( 1.0 + ( S * cos( H ) / cos( 60.0 / 180 * PI - H ) ) ); 
  G = 3.0 * I - ( B + R );
}
else if(fHAngle >= 120 && fHAngle < 240)
{
  R = I * ( 1.0 - S );
  G = I * ( 1.0 + S * cos( H - 120.0 / 180 * PI ) / cos( 180.0 / 180 * PI - H )  );
  B = 3.0 * I - ( R + G );
}
else if(fHAngle >= 240 && fHAngle < 360)
{
  G = I * ( 1.0 - S );
  B = I * ( 1.0 + S * cos( H - 240.0 / 180 * PI ) / cos( 300.0 / 180 * PI - H ) );
  R = 3.0 * I - ( G + B );
}
int R_value_in_rgb = R * 255;
int G_value_in_rgb = G * 255;
int B_value_in_rgb = B * 255;
BR = static_cast<BYTE>(R_value_in_rgb);
BG = static_cast<BYTE>(G_value_in_rgb);
BB = static_cast<BYTE>(B_value_in_rgb);
}

RGB=>HSI

void  RGB2HSI(BYTE r,BYTE g,BYTE b,BYTE &h,BYTE &s,BYTE &i)
{
	short m_fr = static_cast<short>(r);
	short m_fg = static_cast<short>(g);
	short m_fb = static_cast<short>(b);
	
	float m_fiR = static_cast<float>(m_fr) / 255;
	float m_fsG = static_cast<float>(m_fg) / 255;
	float m_fhB = static_cast<float>(m_fb) / 255;
	  
	if( m_fr == m_fg && m_fg == m_fb)
	{
	  int iHValue = 0;
	  int iSValue = 0;
	  int iLValue = ((float)m_fr)/ 255 * 100;
	  h = static_cast<BYTE>(iHValue);
	  s = static_cast<BYTE>(iSValue);
	  i = static_cast<BYTE>(iLValue);  
	  return;
	}
	float max_value_of_rgb = GetMax( m_fiR, m_fsG, m_fhB );
	float min_value_of_rgb = GetMin( m_fiR, m_fsG, m_fhB );
	float fSumRGB =m_fiR + m_fsG + m_fhB ;
	if( fSumRGB <= 0.0 )
	  fSumRGB = 0.001;
	float I = (m_fiR + m_fsG + m_fhB) / 3;
	float S = 1.0 - 3.0 * min_value_of_rgb / fSumRGB;
	float H = acos( (( m_fiR - m_fsG ) + ( m_fiR - m_fhB ))/2 / sqrt( ( m_fiR - m_fsG )*( m_fiR - m_fsG ) + ( m_fiR -m_fhB ) * ( m_fsG - m_fhB)  + 0.0001 ) );
	float fHAngle = H / PI * 180;
	if( m_fsG < m_fhB )
	  fHAngle = 360 - fHAngle;
	if( fHAngle > 360.0 )
	  fHAngle = 360.0;
	int nHValue = fHAngle / 360 * 255;
	int nSValue = S * 100;
	int nLValue = I * 100;
	h = nHValue;
	s = nSValue;
	i = nLValue;
}

先来了解一些概念:
1.RGB是一种加色模型,就是将不同比例的Red/Green/Blue混合在一起得到新颜色.通常RGB颜色模型表示为:
image

2.HSB(HSV) 通过色相/饱和度/亮度三要素来表达颜色.

H(Hue):表示颜色的类型(例如红色,绿色或者黄色).取值范围为0—360.其中每一个值代表一种颜色.

S(Saturation):颜色的饱和度.从0到1.有时候也称为纯度.(0表示灰度图,1表示纯的颜色)

B(Brightness or Value):颜色的明亮程度.从0到1.(0表示黑色,1表示特定饱和度的颜色)

image

后面地址是一个在线的观察RGB到HSB转换的工具:
http://web.bentley.edu/empl/c/ncarter/MA307/color-converter.html

用RGB来表示颜色虽然方便,但是两个相近的颜色的RGB值却可能相差十万八千里。用HSV(Hue色相、Saturation饱和度、Value(Brightness)明度,也叫HSB)来表示颜色就比较符合人们的习惯。

RGB到HSV(HSB)的转换:

HSV(HSB)到RGB的转换:

根据以上说明,有以下转换公式(Java代码):

public static float[] rgb2hsb(int rgbR, int rgbG, int rgbB) { 
    assert 0 <= rgbR && rgbR <= 255; 
    assert 0 <= rgbG && rgbG <= 255; 
    assert 0 <= rgbB && rgbB <= 255; 
    int[] rgb = new int[] { rgbR, rgbG, rgbB }; 
    Arrays.sort(rgb); 
    int max = rgb[2]; 
    int min = rgb[0]; 
 
    float hsbB = max / 255.0f; 
    float hsbS = max == 0 ? 0 : (max - min) / (float) max; 
 
    float hsbH = 0; 
    if (max == rgbR && rgbG >= rgbB) { 
        hsbH = (rgbG - rgbB) * 60f / (max - min) + 0; 
    } else if (max == rgbR && rgbG < rgbB) { 
        hsbH = (rgbG - rgbB) * 60f / (max - min) + 360; 
    } else if (max == rgbG) { 
        hsbH = (rgbB - rgbR) * 60f / (max - min) + 120; 
    } else if (max == rgbB) { 
        hsbH = (rgbR - rgbG) * 60f / (max - min) + 240; 
    } 
 
    return new float[] { hsbH, hsbS, hsbB }; 
} 
 
public static int[] hsb2rgb(float h, float s, float v) { 
    assert Float.compare(h, 0.0f) >= 0 && Float.compare(h, 360.0f) <= 0; 
    assert Float.compare(s, 0.0f) >= 0 && Float.compare(s, 1.0f) <= 0; 
    assert Float.compare(v, 0.0f) >= 0 && Float.compare(v, 1.0f) <= 0; 
 
    float r = 0, g = 0, b = 0; 
    int i = (int) ((h / 60) % 6); 
    float f = (h / 60) - i; 
    float p = v * (1 - s); 
    float q = v * (1 - f * s); 
    float t = v * (1 - (1 - f) * s); 
    switch (i) { 
    case 0: 
        r = v; 
        g = t; 
        b = p; 
        break; 
    case 1: 
        r = q; 
        g = v; 
        b = p; 
        break; 
    case 2: 
        r = p; 
        g = v; 
        b = t; 
        break; 
    case 3: 
        r = p; 
        g = q; 
        b = v; 
        break; 
    case 4: 
        r = t; 
        g = p; 
        b = v; 
        break; 
    case 5: 
        r = v; 
        g = p; 
        b = q; 
        break; 
    default: 
        break; 
    } 
    return new int[] { (int) (r * 255.0), (int) (g * 255.0), 
            (int) (b * 255.0) }; 
} 

几种颜色模型的转换公式

XYZ=>RGB

var_X = X / 100        //X from 0 to  95.047    
var_Y = Y / 100        //Y from 0 to 100.000
var_Z = Z / 100        //Z from 0 to 108.883

var_R = var_X *  3.2406 + var_Y * -1.5372 + var_Z * -0.4986
var_G = var_X * -0.9689 + var_Y *  1.8758 + var_Z *  0.0415
var_B = var_X *  0.0557 + var_Y * -0.2040 + var_Z *  1.0570

if ( var_R > 0.0031308 ) var_R = 1.055 * ( var_R ^ ( 1 / 2.4 ) ) - 0.055
else                     var_R = 12.92 * var_R
if ( var_G > 0.0031308 ) var_G = 1.055 * ( var_G ^ ( 1 / 2.4 ) ) - 0.055
else                     var_G = 12.92 * var_G
if ( var_B > 0.0031308 ) var_B = 1.055 * ( var_B ^ ( 1 / 2.4 ) ) - 0.055
else                     var_B = 12.92 * var_B

R = var_R * 255
G = var_G * 255
B = var_B * 255

RGB => XYZ

var_R = ( R / 255 )        //R from 0 to 255
var_G = ( G / 255 )        //G from 0 to 255
var_B = ( B / 255 )        //B from 0 to 255

if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
else                   var_R = var_R / 12.92
if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
else                   var_G = var_G / 12.92
if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
else                   var_B = var_B / 12.92

var_R = var_R * 100
var_G = var_G * 100
var_B = var_B * 100

X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505

XYZ => Yxy

//X from 0 to 95.047      

//Y from 0 to 100.000
//Z from 0 to 108.883

Y = Y
x = X / ( X + Y +Z )
y = Y / ( X + Y +Z )

Yxy —> XYZ

//Y from 0 to 100
//x from 0 to 1
//y from 0 to 1

X = x * ( Y / y )
Y = Y
Z = ( 1 - x - y ) * ( Y / y )

XYZ —> Hunter-Lab

(H)L = 10 * sqrt( Y )
(H)a = 17.5 * ( ( ( 1.02 * X ) - Y ) / sqrt(Y ) )
(H)b = 7 * ( ( Y - ( 0.847 * Z ) ) / sqrt(Y ) )

Hunter-Lab —> XYZ


var_Y = (H)L / 10
var_X = (H)a / 17.5 * (H)L / 10
var_Z = (H)b / 7 * (H)L / 10

Y = var_Y ^ 2
X = ( var_X + Y ) / 1.02
Z = -( var_Z - Y ) / 0.847

XYZ —> CIE-L*ab

var_X = X / ref_X          //ref_X =  95.047 

var_Y = Y / ref_Y          //ref_Y = 100.000
var_Z = Z / ref_Z          //ref_Z = 108.883

if ( var_X > 0.008856 ) var_X = var_X ^ ( 1/3 )
else                    var_X = ( 7.787 * var_X ) + ( 16 / 116 )
if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
else                    var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
if ( var_Z > 0.008856 ) var_Z = var_Z ^ ( 1/3 )
else                    var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )

CIE-L* = ( 116 * var_Y ) - 16
CIE-a* = 500 * ( var_X - var_Y )
CIE-b* = 200 * ( var_Y - var_Z )

CIE-L*ab —> XYZ

var_Y = ( CIE-L* + 16 ) / 116
var_X = CIE-a* / 500 + var_Y
var_Z = var_Y - CIE-b* / 200

if ( var_Y^3 > 0.008856 ) var_Y = var_Y^3
else                      var_Y = ( var_Y - 16 / 116 ) / 7.787
if ( var_X^3 > 0.008856 ) var_X = var_X^3
else                      var_X = ( var_X - 16 / 116 ) / 7.787
if ( var_Z^3 > 0.008856 ) var_Z = var_Z^3
else                      var_Z = ( var_Z - 16 / 116 ) / 7.787

X = ref_X * var_X     //ref_X =  95.047    

Y = ref_Y * var_Y     //ref_Y = 100.000
Z = ref_Z * var_Z     //ref_Z = 108.883

CIE-Lab —> CIE-LCH°


var_H = arc_tangent( CIE-b*, CIE-a* )  //Quadrant by signs

if ( var_H > 0 ) var_H = ( var_H / PI ) * 180
else             var_H = 360 - ( abs( var_H ) / PI ) * 180

CIE-L* = CIE-L*
CIE-C* = sqrt( CIE-a* ^ 2 + CIE-b* ^ 2 )
CIE-H° = var_H

CIE-LCH° —>CIE-Lab

//CIE-H° from 0 to 360°

CIE-L* = CIE-L*
CIE-a* = cos( degree_2_radian( CIE-H° ) ) *CIE-C*
CIE-b* = sin( degree_2_radian( CIE-H° ) ) *CIE-C*

XYZ —> CIE-L*uv


var_U = ( 4 * X ) / ( X + ( 15 * Y ) + ( 3 * Z ) )
var_V = ( 9 * Y ) / ( X + ( 15 * Y ) + ( 3 *Z ) )

var_Y = Y / 100
if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
else                    var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )

ref_X =  95.047     
ref_Y = 100.000
ref_Z = 108.883

ref_U = ( 4 * ref_X ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )
ref_V = ( 9 * ref_Y ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )

CIE-L* = ( 116 * var_Y ) - 16
CIE-u* = 13 * CIE-L* * ( var_U - ref_U )
CIE-v* = 13 * CIE-L* * ( var_V - ref_V )

CIE-L*uv —> XYZ

var_Y = ( CIE-L* + 16 ) / 116
if ( var_Y^3 > 0.008856 ) var_Y = var_Y^3
else                      var_Y = ( var_Y - 16 / 116 ) / 7.787

ref_X =  95.047    
ref_Y = 100.000
ref_Z = 108.883

ref_U = ( 4 * ref_X ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )
ref_V = ( 9 * ref_Y ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )

var_U = CIE-u* / ( 13 * CIE-L* ) + ref_U
var_V = CIE-v* / ( 13 * CIE-L* ) + ref_V

Y = var_Y * 100
X =  - ( 9 * Y * var_U ) / ( ( var_U - 4 ) * var_V  - var_U * var_V )
Z = ( 9 * Y - ( 15 * var_V * Y ) - ( var_V * X ) ) / ( 3 * var_V )

RGB —> HSL

var_R = ( R / 255 )                     //RGB from 0 to 255
var_G = ( G / 255 )
var_B = ( B / 255 )

var_Min = min( var_R, var_G, var_B )    //Min. value of RGB
var_Max = max( var_R, var_G, var_B )    //Max. value of RGB
del_Max = var_Max - var_Min             //Delta RGB value

L = ( var_Max + var_Min ) / 2

if ( del_Max == 0 )                     //This is a gray, no chroma...
{
   H = 0                                //HSL results from 0 to 1
   S = 0
}
else                                    //Chromatic data...
{
   if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min )
   else           S = del_Max / ( 2 - var_Max - var_Min )

   del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max

   if      ( var_R == var_Max ) H = del_B - del_G
   else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
   else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R

   if ( H < 0 ) ; H += 1
   if ( H > 1 ) ; H -= 1
}

 

HSL —> RGB

if ( S == 0 )                      //HSL from 0 to 1
{
   R = L * 255                      //RGB results from 0 to 255
   G = L * 255
   B = L * 255
}
else
{
   if ( L < 0.5 ) var_2 = L * ( 1 + S )
   else           var_2 = ( L + S ) - ( S * L )

   var_1 = 2 * L - var_2

   R = 255 * Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) )
   G = 255 * Hue_2_RGB( var_1, var_2, H )
   B = 255 * Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) )
}

Hue_2_RGB

Hue_2_RGB( v1, v2, vH )             //Function Hue_2_RGB
{
   if ( vH < 0 ) vH += 1
   if ( vH > 1 ) vH -= 1
   if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH )
   if ( ( 2 * vH ) < 1 ) return ( v2 )
   if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 )
   return ( v1 )
}

RGB —> HSV


var_R = ( R / 255 )                     //RGB from 0 to 255
var_G = ( G / 255 )
var_B = ( B / 255 )

var_Min = min( var_R, var_G, var_B )    //Min. value of RGB
var_Max = max( var_R, var_G, var_B )    //Max. value of RGB
del_Max = var_Max - var_Min             //Delta RGB value

V = var_Max

if ( del_Max == 0 )                     //This is a gray, no chroma...
{
   H = 0                                //HSV results from 0 to 1
   S = 0
}
else                                    //Chromatic data...
{
   S = del_Max / var_Max

   del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max

   if      ( var_R == var_Max ) H = del_B - del_G
   else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
   else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R

   if ( H < 0 ) ; H += 1
   if ( H > 1 ) ; H -= 1
}

HSV —> RGB

if ( S == 0 )                       //HSV from 0 to 1
{
   R = V * 255
   G = V * 255
   B = V * 255
}
else
{
   var_h = H * 6
   if ( var_h == 6 ) var_h = 0      //H must be < 1
   var_i = int( var_h )             //Or ... var_i = floor( var_h )
   var_1 = V * ( 1 - S )
   var_2 = V * ( 1 - S * ( var_h - var_i ) )
   var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) )

   if      ( var_i == 0 ) { var_r = V     ; var_g = var_3 ; var_b = var_1 }
   else if ( var_i == 1 ) { var_r = var_2 ; var_g = V     ; var_b = var_1 }
   else if ( var_i == 2 ) { var_r = var_1 ; var_g = V     ; var_b = var_3 }
   else if ( var_i == 3 ) { var_r = var_1 ; var_g = var_2 ; var_b = V   }
   else if ( var_i == 4 ) { var_r = var_3 ; var_g = var_1 ; var_b = V   }
   else                   { var_r = V     ; var_g = var_1 ; var_b = var_2 }

   R = var_r * 255                  //RGB results from 0 to 255
   G = var_g * 255
   B = var_b * 255
}

RGB —> CMY

//RGB values from 0 to 255
//CMY results from 0 to 1

C = 1 - ( R / 255 )
M = 1 - ( G / 255 )
Y = 1 - ( B / 255 )

CMY —> RGB

//CMY values from 0 to 1
//RGB results from 0 to 255

R = ( 1 - C ) * 255
G = ( 1 - M ) * 255
B = ( 1 - Y ) * 255

CMY —> CMYK

//CMYK and CMY values from 0 to 1

var_K = 1

if ( C < var_K )   var_K = C
if ( M < var_K )   var_K = M
if ( Y < var_K )   var_K = Y
if ( var_K == 1 ) { //Black
   C = 0
   M = 0
   Y = 0
}
else {
   C = ( C - var_K ) / ( 1 - var_K )
   M = ( M - var_K ) / ( 1 - var_K )
   Y = ( Y - var_K ) / ( 1 - var_K )
}
K = var_K

CMYK —> CMY

//CMYK and CMY values from 0 to 1

C = ( C * ( 1 - K ) +K )
M = ( M * ( 1 - K ) + K )
Y = ( Y * ( 1 - K ) + K )

将彩色图像转化为灰度的方法有两种,一个是令RGB三个分量的数值相等,输出后便可以得到灰度图像,另一种是转化为YCbCr格式,将Y分量提取出来,YCbCr格式中的Y分量表示的是图像的亮度和浓度所以只输出Y分量,得到的图像就是灰度图像了。我在这里选择第二种方法实现。

YCbCr是通过有序的三元组来表示的,三元由Y(Luminance)、Cb(Chrominance-Blue)和Cr(Chrominance-Red)组成,其中Y表示颜色的明亮度和浓度,而Cb和Cr则分别表示颜色的蓝色浓度偏移量和红色浓度偏移量。人的肉眼对由YCbCr色彩空间编码的视频中的Y分量更敏感,而Cb和Cr的微小变化不会引起视觉上的不同,根据该原理,通过对Cb和Cr进行子采样来减小图像的数据量,使得图像对存储需求和传输带宽的要求大大降低,从而达到在完成图像压缩的同时也保证了视觉上几乎没有损失的效果,进而使得图像的传输速度更快,存储更加方便。我们要的到灰度图像,首先要将采集到的彩色图像转化为YCbCr。

在这里插入图片描述

这是OV7725的手册中给出的RGB888 to YCbCr的算法公式。简单明了,将一副图片的RGB分量提取出来,然后用上面的公式进行运算,得到YcbCr分量,然后在合成显示即可。这样显示出来的是YcbCr色彩空间的图片,我们只取Y分量作为新的图片的三个分量合成,得到的即是这幅彩色图片的灰度图。下面先记录一些MATLAB在图像处理中常用语法和函数。

合成和提取RGB的三个分量
fR、fG、fB分别表示RGB三个分量的图像。一副RGB图像可以利用cat(级联)操作符合成彩色图像。

rgb_image = cat(3, fR, fG, fB)

提取三个分量

fR = RGB(:, :, 1); 红色分量

fG = RGB(:, :, 2); 绿色分量

fB = RGB(:, :, 3); 蓝色分量

size()函数得到图片的行列数
[ROW, COL,DIM] = size(R_data); 得到一副图像的行列数。

显示图片
figure, imshow(imag) 保存第一幅图像并同时显示第二幅图像。

显示图片用imshow()函数,前面加个figure; 可以在原来显示的基础上重新打开一个窗口显示。

生成矩阵函数
zeros函数——生成零矩阵

ones函数——生成全1阵

【zeros的使用方法】

B=zeros(n):生成n×n全零阵。

B=zeros(m,n):生成m×n全零阵。

B=zeros([m n]):生成m×n全零阵。

B=zeros(d1,d2,d3……):生成d1×d2×d3×……全零阵或数组。

B=zeros([d1 d2 d3……]):生成d1×d2×d3×……全零阵或数组。

B=zeros(size(A)):生成与矩阵A相同大小的全零阵。

【ones的使用方法】

ones的使用方法与zeros的使用方法类似。

RGB转YcbCr色彩空间MATLAB代码实现

 1 %将一幅640*480的彩色图片转换成显示成灰度显示?
 2 clc;
 3 clear all;
 4 close all;
 5 
 6 RGB_data = imread('lena.jpg');%图像读入
 7 
 8 R_data =    RGB_data(:,:,1);
 9 G_data =    RGB_data(:,:,2);
10 B_data =    RGB_data(:,:,3);
11 
12 imshow(RGB_data);
13 
14 [ROW,COL, DIM] = size(RGB_data); %提取图片的行列数
15 
16 Y_data = zeros(ROW,COL);
17 Cb_data = zeros(ROW,COL);
18 Cr_data = zeros(ROW,COL);
19 Gray_data = RGB_data;
20 %YCbCr_data = RGB_data;
21 
22 for r = 1:ROW 
23     for c = 1:COL
24         Y_data(r, c) = 0.299*R_data(r, c) + 0.587*G_data(r, c) + 0.114*B_data(r, c);
25         Cb_data(r, c) = -0.172*R_data(r, c) - 0.339*G_data(r, c) + 0.511*B_data(r, c) + 128;
26         Cr_data(r, c) = 0.511*R_data(r, c) - 0.428*G_data(r, c) - 0.083*B_data(r, c) + 128;
27     end
28 end 
29 
30 % YCbCr_data(:,:,1)=Y_data;
31 % YCbCr_data(:,:,2)=Cb_data;
32 % YCbCr_data(:,:,3)=Cr_data;
33 
34 % figure;
35 % imshow(YCbCr_data);
36 
37 Gray_data(:,:,1)=Y_data;
38 Gray_data(:,:,2)=Y_data;
39 Gray_data(:,:,3)=Y_data;
40 
41 figure;
42 imshow(Gray_data);
  • 11
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值