颜色空间的互相转换

news/2024/11/14 12:20:43/文章来源:https://www.cnblogs.com/skmcj/p/18355885

前言

在上一篇中,我们介绍了常见颜色空间的一些定义及表示,在这一章中,我们将大致了解各个颜色空间的互相转换

颜色转换算法

由于有些颜色空间可能并不能直接转换,或着过于繁杂,本文主要介绍由RGB向其它空间的转换,涉及到的代码也采用Ts进行演示讲解

在文章的最后面,会给出封装的转换算法(TS版),如对文章内容不感兴趣,可直接拖到文末查看获取方法

HEX

将一个RGB颜色转换为HEX模式,其实就是将十进制值转换为十六进制,没什么好说的,直接看代码理解即可

/*** RGB 转为 HEX* @param {number} r [0-255]红色通道值* @param {number} g [0-255]绿色通道值* @param {number} b [0-255]蓝色通道值* @param {boolean} ad 是否带 # ,默认带有* @return {HEX} 返回转换的 hex 值*/
const rgbToHex = function (r: number,g: number,b: number,ad: boolean = true
): HEX {if (ad) return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;else return `${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
};

主要就是按顺序将RGB各分量值,通过左移运算转换为一个对应十六进制的十进制数,最后将其转换为十六进制字符串即可

CMYK

RGB只有三个通道(取值范围0-255),而CMYK有四个通道(取值范围0-100),故从RGBCMYK的转换主要两个过程:

  • RGBCMY

    • \(C = (255 - R) / 255\)
    • \(M = (255 - G) / 255\)
    • \(Y = (255 - B) / 255\)
  • CMYCMYK

    • \(K = \min (C, M, Y)\)
    • \(C = (C - K) / (1 - K)\)
    • \(M = (M - K) / (1 - K)\)
    • \(Y = (Y - K) / (1 - K)\)

具体的代码为:

/*** RGB 转为 CMYK* @param {number} r [0-255]红色通道值* @param {number} g [0-255]绿色通道值* @param {number} b [0-255]蓝色通道值* @return {CMYK} 返回转换的 cmyk 值*/
const rgbToCmyk = function (r: number,g: number,b: number
): CMYK {let c = (255 - r) / 255;let m = (255 - g) / 255;let y = (255 - b) / 255;let k = Math.min(c, m, y);if (k === 1) {// 此时为纯黑色,其它分量均为零c = m = y = 0;} else {let kk = 1 - k;c = (c - k) / kk;m = (m - k) / kk;y = (y - k) / kk;}return {c: toFixed(c * 100, 0),m: toFixed(m * 100, 0),y: toFixed(y * 100, 0),k: toFixed(k * 100, 0)};
};// toFixed为一个保留指定小数位的函数

该算法只是比较粗糙的转换,由于两个颜色空间色域并不一致,故转换过程中可能会存在一定程度的颜色偏差和失真

HSV

在开始转换之前,先分析一下各分量的值域,首先是RGB,值域为[0-255];接着是HSVH值域为[0-360]SV的值域是[0-100]

转换的第一步就是统一分量值域

  • 先将RGB的值域转换为[0-1],由此计算出来的SV值域也为[0-1](H不变),后续根据需要转变即可
  • 然后,根据一下公式步骤计算
  • hsv

对应的转换代码为:

/*** RGB 转为 HSV* @param {number} r [0-255]红色通道值* @param {number} g [0-255]绿色通道值* @param {number} b [0-255]蓝色通道值* @return {HSV} 返回转换的 hsv 值*/
const rgbToHsv = function (r: number,g: number,b: number
): HSV {r = r / 255; // [0, 1]g = g / 255; // [0, 1]b = b / 255; // [0, 1]const max = Math.max(r, g, b);const min = Math.min(r, g, b);const d = max - min;const v = max;const s = max === 0 ? 0 : d / max;let h = 0;if (d !== 0) {switch (max) {case r:h = (g - b) / d + (g < b ? 6 : 0);break;case g:h = (b - r) / d + 2;break;case b:h = (r - g) / d + 4;break;default:break;}h = h / 6;}// 返回时再规整值域return {h: toFixed(h * 360),s: toFixed(s * 100),v: toFixed(v * 100)};
};

HSL

在转换前,同样需先确定好各分量的计算值域

HSLHSV比较类似,其中的H均表示色调(色相),值域为[0-360];接着规定SL的值域为[0-1],故RGB同样需转换为[0-1]的值

接着根据计算公式计算:

hsl

具体的代码如下:

/*** RGB 转为 HSL* @param {number} r [0-255]红色通道值* @param {number} g [0-255]绿色通道值* @param {number} b [0-255]蓝色通道值* @return {HSL} 返回转换的 hsl 值*/
const rgbToHsl = function (r: number,g: number,b: number
): HSL {r = r / 255; // [0, 1]g = g / 255; // [0, 1]b = b / 255; // [0, 1]const max = Math.max(r, g, b);const min = Math.min(r, g, b);const d = max - min;const l = (max + min) / 2;const s = d === 0 ? 0 : l > 0.5 ? d / (2 - 2 * l) : d / (2 * l);let h = 0;if (d !== 0) {switch (max) {case r:h = (g - b) / d + (g < b ? 6 : 0);break;case g:h = (b - r) / d + 2;break;case b:h = (r - g) / d + 4;break;default:break;}h = h / 6;}return {h: toFixed(h * 360),s: toFixed(s * 100),l: toFixed(l * 100)};
};

LAB

LAB是一种色域极广的颜色模式,相较于RGB,其采用更加科学的颜色表示方法,它是基于人眼对颜色的感知来定义的,其主要有三个分量:L表示亮度,A表示绿色到红色的色差,B表示蓝色到黄色的色差

由于两个颜色空间的定义原理,RGB无法直接转换为LAB,需用XYZ作为一个中间层,即RGBXYZ,再转LAB

XYZ也是一个颜色空间,其全称为CIE 1931 XYZ色彩空间(也叫做CIE 1931色彩空间),由国际照明委员会(CIE)于1931年创立。

XYZ是为了解决更精确地定义色彩而提出来的, 其三个分量中, XY代表的是色度, 而Y既可以代表亮度也可以代表色度,单位为nit

在日常生活中,我们无法用RGB来精确定义颜色, 因为,不同的设备显示的RGB其实都是不一样的,不同的设备, 显示同一个RGB, 在人眼看出来可能是千差万别的, XYZ就是为了解决这样的问题,使不同设备颜色显示更精确

具体的转换步骤为:

  • RGB归一化,即值域转变为[0-1]
  • RGB值进行逆伽马校正
    • 具体就是将各分量值传入逆伽马校正的函数内求结果,可根据实际情况使用不同标准的逆伽马函数或者设备的校准曲线
  • 接着将校正后的RGB转换为XYZ空间值
  • 接着将XYZ进行归一计算,使其归一到参考白点,常用的是D65白点(0.950456, 1, 1.088754)
  • 然后将XYZ值再进行非线性变换
  • 最后计算转换为LAB

大致的数学公式如下:

rgb转lab

大致的代码如下:

/*** RGB 转为 XYZ* @param {number} r [0-255]红色通道值* @param {number} g [0-255]绿色通道值* @param {number} b [0-255]蓝色通道值* @return {XYZ} 返回转换的 xyz 值*/
const rgbToXyz = function (r: number,g: number,b: number
): XYZ {// 归一化r = r / 255;g = g / 255;b = b / 255;r = gamma(r);g = gamma(g);b = gamma(b);let x = 0.4124564 * r + 0.3575761 * g + 0.1804375 * b;let y = 0.2126729 * r + 0.7151522 * g + 0.072175 * b;let z = 0.0193339 * r + 0.119192 * g + 0.9503041 * b;return {x,y,z};
};const XN = 0.950456;
const YN = 1;
const ZN = 1.088754;/*** XYZ 转 LAB* @param x* @param y* @param z*/
const xyzToLab = function (x: number,y: number,z: number
): LAB {// 归一化x = x / XN;y = y / YN;z = z / ZN;x = f(x);y = f(y);z = f(z);let l = 116 * y - 16;let a = 500 * (x - y);let b = 200 * (y - z);return {l,a,b};
};/*** RGB 转为 LAB* @param {number} r [0-255]红色通道值* @param {number} g [0-255]绿色通道值* @param {number} b [0-255]蓝色通道值* @return {LAB} 返回转换的 Lab 值*/
const rgbToLab = function (r: number,g: number,b: number
): LAB {let xyz = rgbToXyz(r, g, b);let lab = xyzToLab(xyz.x, xyz.y, xyz.z);return {l: toFixed(lab.l),a: toFixed(lab.a),b: toFixed(lab.b)};
};/*** XYZ 转 LAB 的非线性变换* @param {number} t x, y, z的值*/
function f(t: number): number {// Math.pow(29 / 6, 2) / 3 = 7.787037037037035// 16 / 116 = 0.13793103448275862if (t > 0.008856) {return Math.pow(t, 1 / 3);} else {return 7.787037037037035 * t + 0.13793103448275862;}
}/*** gamma变换* @param t - r, g, b值*/
function gamma(t: number) {return t > 0.04045 ?Math.pow((t + 0.055) / 1.055, 2.4): t / 12.92;
}

上方给出的转换方法并不是绝对的,不同转换方法会有不同标准,具体根据自己需要选择

由于篇幅有限,这里只给出了RGB转换向其它的空间的,至于其它空间转换向RGB的并没给出,但具体的代码均封装为一个包(TS版),具体可按下列方法获取

封装的转换算法获取方法:在公众号:代码杂谈内回复颜色转换算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/782981.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TGI 多-LoRA: 部署一次,搞定 30 个模型的推理服务

你是否已厌倦管理多个 AI 模型所带来的复杂性和高成本? 那么, 如果你可以部署一次就搞定 30 个模型推理服务会如何? 在当今的 ML 世界中,哪些希望充分发挥其数据的价值的组织可能最终会进入一个“微调的世界”。在这个世界,各个组织会构建大量模型,其中每个模型都针对特定…

计算机常用软件和语言

关于CSP-J初赛的学习笔记3.计算机常用软件和语言 3.1 计算机软件系统 计算机软件通常分为系统软件和应用软件两大类;系统软件 即支持应用软件开发和运行的一类计算机软件。一般包括操作系统,语言处理程序,数据库系统,网络管理系统等应用软件 即为特定领域开发,并为特定目的…

「Day 7—离散化 树状数组 线段树」

离散化 定义 离散化本质是一种哈希,是一种用来处理数据的方法。 1.创建原数组的副本。 2.将副本中的值从小到大排序。 3.将排序好的副本去重。 4.查找原数组的每一个元素在副本中的位置,位置即为排名,将其作为离散化后的值。 B3694 数列离散化 代码 #include<iostream>…

chrome无法下载文件

用的电脑是Mac Air M1,安装了127版本的chrome,总有几次在浏览器上下载文件的时候明明点击了下载按钮,chrome图标显示已经有下载的内容了,但是打开下载文件夹却不显示显示下载的文件,扒拉看了一下说是迅雷插件要关闭,后面发现自己也没安装迅雷插件。解决方案: 把这两个关…

万兆以太网协议栈的FPGA实现(一):常识+PCSPMA+结构

参考: https://docs.amd.com/r/zh-CN/pg210-25g-ethernet/%E7%AE%80%E4%BB%8B?tocId=59kIPN67Q57xorWh9w6GTA 10GbE以太网MAC和PHY - 者旨於陽 - 博客园 (cnblogs.com) 什么是CML电平-CSDN博客 10G Ethernet PCS/PMA v6.0 Product Guide (PG068) • 查看器 • AMD 技术信息门…

Two-Processor Scheduling 学习笔记

再高没有高爸高。为什么有人联考放论文题啊?不过好有趣。参考的 glx 博客。 考虑这么一个问题,给定一张偏序图,即一个满足传递性和非自反性的偏序关系 \(\succ\) 连成的 DAG。你需要对这张图进行拓扑排序,每次可以同时删去一个或者两个零入度点,问最少删多少次可以把图删空…

【原创软件】第8期:pdf转图片软件FAST_PDF2PNG,可选分辨率快速pdf转图片

一、背景 因为经常处理扫描件,需要将扫描件或者电子书先转为图片进行优化处理。为了省去人工时间,制作了一个软件FAST_PDF2PNG。尽管已经有不少软件可以完成该功能,但是杀鸡焉用牛刀。 本工具仅约4M,小巧方便。(优点:速度快,比pdf补丁丁更快,可选分辨率72-1200dpi,含有…

2024暑假集训测试23

前言比赛链接。T2 部分分给得特别足,\(60pts\),而且他不可能剩下的数据全放菊花,所以得到了 \(76pts\),但赛时想了很长时间正解,没有想出来,给后面题剩的时间不多,就都胡暴力了,\(T4\) 甚至忘了剪枝,剪完之后 \(20pts\to 60pts\) 没绷住。 说到这儿要吐槽一下 T4 数据…

了解LSTM网络(英文博客汉化)

Understanding LSTM Networks-了解LSTM网络原文来自于大神Cristopher Colah于2015年在Github上发布的一篇博客, 窃以为此文不失为一篇入门神经网络的经典文章, 遂产生了汉化的想法, 附原文链接Understanding LSTM Networks什么是RNN 人类不会时时刻刻都从头开始思考。譬如当你读…

[Spring]Bean生命周期

生命周期的概要流程 Bean 的生命周期概括起来就是 4 个阶段:实例化(Instantiation) 属性赋值(Populate) 初始化(Initialization) 销毁(Destruction)实例化:第 1 步,实例化一个 bean 对象; 属性赋值:第 2 步,为 bean 设置相关属性和依赖; 初始化:第 3~7 步,步骤…

4-反向传播

从这张图片,可以看出。不管我们有多少层,都可以化简成最简形式。我们添加的层就没有意义。 所以我们要对每一层的输出做非线性变换,增加模型的复杂程度,使它没法化简反向传播的流程pytorch的tensor数据结构看到代码,要能把计算图构建出来,而不是简单的乘除运算在上面这张…

QSortFilterProxyModel和QTreeView排序功能

1、需求,创建一个树有多层结构,同一层按照插入顺序逆序排列; ui.treeView->setHeaderHidden(true); //tree widget头标题是否显示,此处隐藏标题//ui.treeWidget->header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);ui.treeView->heade…