当前位置: 首页 > news >正文

CIEDE2000 色差公式C++及MATLAB实现

主要功能包括:

输入处理:

接收两个LAB颜色值:[L1, a1, b1] 和 [L2, a2, b2]

LAB颜色空间模拟人眼感知,包含:

L:亮度(0-100)

a:红绿轴(负值绿,正值红)

b:黄蓝轴(负值蓝,正值黄)

核心计算:

色度调整:通过G因子补偿人眼对中性色的感知差异

色调角处理:处理角度跨越360°的特殊情况

差异计算:

ΔL’:亮度差异

ΔC’:调整后的色度差异

ΔH’:色调差异(转换为欧几里得距离)

感知权重:

Sl:亮度差异的感知权重

Sc:色度差异的感知权重

Sh:色调差异的感知权重

旋转项:处理蓝色区域的特殊感知特性

输出结果:

del_C00:色相差分量(仅包含色度和色调差异)

del_E00:总色差值(包含亮度、色度和色调差异)

#include <vector>
#include <cmath>// 定义圆周率常量
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endifstd::vector<double> CIEDE2000Computation(const std::vector<double>& arr) {// =============================================// 步骤1: 提取输入参数// =============================================// 输入数组包含两个LAB颜色值: [L1, a1, b1, L2, a2, b2]double L1 = arr[0];  // 第一个颜色的L分量(亮度)double a1 = arr[1];  // 第一个颜色的a分量(红绿轴)double b1 = arr[2];  // 第一个颜色的b分量(黄蓝轴)double L2 = arr[3];  // 第二个颜色的L分量double a2 = arr[4];  // 第二个颜色的a分量double b2 = arr[5];  // 第二个颜色的b分量// =============================================// 步骤2: 初始化常量// =============================================double kL = 1.0;  // 亮度权重因子double kC = 1.0;  // 色度权重因子double kH = 1.0;  // 色调权重因子// =============================================// 步骤3: 计算初始色度值// =============================================// 计算两个颜色的原始色度(a和b分量的欧几里得距离)double c1 = std::sqrt(a1*a1 + b1*b1);double c2 = std::sqrt(a2*a2 + b2*b2);double c_bar = (c1 + c2) / 2.0;  // 平均色度// =============================================// 步骤4: 计算色度调整因子G// =============================================// G因子用于补偿人眼对中性色的感知差异double G = 0.5 * (1 - std::sqrt(std::pow(c_bar, 7) / (std::pow(c_bar, 7) + std::pow(25.0, 7)));// =============================================// 步骤5: 计算调整后的a分量// =============================================// 应用G因子调整a分量,以补偿感知非线性double a1p = (1 + G) * a1;  // 调整后的第一个颜色a分量double a2p = (1 + G) * a2;  // 调整后的第二个颜色a分量// =============================================// 步骤6: 计算调整后的色度值和色调角// =============================================// 基于调整后的a分量重新计算色度double c1p = std::sqrt(a1p*a1p + b1*b1);  // 调整后的第一个颜色色度double c2p = std::sqrt(a2p*a2p + b2*b2);  // 调整后的第二个颜色色度// 使用atan2函数计算色调角(弧度制)double h1p = std::atan2(b1, a1p);  // 第一个颜色的色调角double h2p = std::atan2(b2, a2p);  // 第二个颜色的色调角// 确保色调角在[0, 2π)范围内if (h1p < 0) h1p += 2 * M_PI;if (h2p < 0) h2p += 2 * M_PI;// =============================================// 步骤7: 计算色调角差值// =============================================double dhp = h2p - h1p;  // 原始色调角差// 处理特殊情况:当任一颜色为中性色时(色度接近0)if (c1p * c2p == 0) {dhp = 0;  // 中性色没有色调差异}// 处理色调角跨越360°边界的情况else if (std::abs(dhp) > M_PI) {if (dhp > 0) {dhp -= 2 * M_PI;  // 正向跨越边界} else {dhp += 2 * M_PI;  // 负向跨越边界}}// =============================================// 步骤8: 计算ΔL', ΔC', ΔH'// =============================================double del_L_p = L2 - L1;  // 亮度差异double del_C_p = c2p - c1p;  // 调整色度差异// 色调差异(转换为色度空间中的距离)double del_H_p = 2 * std::sqrt(c1p * c2p) * std::sin(dhp / 2);// =============================================// 步骤9: 计算平均色调角// =============================================double h_bar = 0;  // 平均色调角初始化// 仅当两个颜色都有色调时计算平均色调角if (c1p * c2p != 0) {if (std::abs(h2p - h1p) <= M_PI) {// 当色调角差小于180°时直接平均h_bar = (h1p + h2p) / 2;} else {// 处理跨越360°边界的平均计算if (h1p + h2p < 2 * M_PI) {h_bar = (h1p + h2p + 2 * M_PI) / 2;} else {h_bar = (h1p + h2p - 2 * M_PI) / 2;}}}// =============================================// 步骤10: 计算中间平均值// =============================================double L_bar_p = (L1 + L2) / 2;    // 平均亮度double C_bar_p = (c1p + c2p) / 2;  // 平均调整色度// =============================================// 步骤11: 计算色调相关参数T// =============================================// T因子表示色调角位置的权重调整double T = 1.0 - 0.17 * std::cos(h_bar - M_PI/6.0)+ 0.24 * std::cos(2*h_bar)+ 0.32 * std::cos(3*h_bar + M_PI/30.0)- 0.20 * std::cos(4*h_bar - 63.0*M_PI/180.0);// =============================================// 步骤12: 计算Δθ和Rc// =============================================double h_bar_deg = h_bar * 180.0 / M_PI;  // 弧度转角度// 计算基于色调位置的旋转因子double del_theta_deg = 30.0 * std::exp(-std::pow((h_bar_deg - 275.0)/25.0, 2));// 计算色度压缩因子double Rc = 2.0 * std::sqrt(std::pow(C_bar_p, 7) / (std::pow(C_bar_p, 7) + std::pow(25.0, 7)));// =============================================// 步骤13: 计算权重因子// =============================================// 亮度差异的权重因子(对中间亮度更敏感)double Sl = 1.0 + (0.015 * std::pow(L_bar_p - 50, 2)) / std::sqrt(20 + std::pow(L_bar_p - 50, 2));// 色度差异的权重因子double Sc = 1.0 + 0.045 * C_bar_p;// 色调差异的权重因子double Sh = 1.0 + 0.015 * C_bar_p * T;// =============================================// 步骤14: 计算旋转项Rt// =============================================// 该项处理蓝色区域的感知非线性double Rt = -std::sin(2 * del_theta_deg * M_PI / 180.0) * Rc;// =============================================// 步骤15: 计算最终结果// =============================================// 计算总色差ΔE00 (CIEDE2000色差)double term1 = std::pow(del_L_p / (kL * Sl), 2);  // 亮度差异项double term2 = std::pow(del_C_p / (kC * Sc), 2);  // 色度差异项double term3 = std::pow(del_H_p / (kH * Sh), 2);  // 色调差异项double cross_term = Rt * (del_C_p / (kC * Sc)) * (del_H_p / (kH * Sh));  // 交叉项double del_E00 = std::sqrt(term1 + term2 + term3 + cross_term);  // 总色差// 计算色相差分量ΔC00 (不包括亮度差异)double del_C00 = std::sqrt(term2 + term3 + cross_term);  // 色相+色度差异// 返回结果向量 [ΔC00, ΔE00]return {del_C00, del_E00};
}

MATLAB

function [rlst] = CIEDE2000Computation(arr)
%CIEDE2000COMPUTATION 此处显示有关此函数的摘要,
%   此处显示详细说明 L1,a1,b1,L2,a2,b2
%   Constants for CIEDE2000 calculation
L1 = arr(1);
a1 = arr(2);
b1 = arr(3);
L2 = arr(4);
a2 = arr(5);
b2 = arr(6);
kL = 1; kC = 1; kH = 1;%compute C1,C2,h'1,h'2
c1 = sqrt(a1^2 + b1^2);%compute C1_ab
c2 = sqrt(a2^2 + b2^2);%compute C2_ab
c_bar = (c1 + c2) / 2;%compute Cave_ab
G = 0.5*(1 - sqrt((c_bar^7)/(c_bar^7 + 25^7)));%compute G
a1p = (1 + G)*a1;%computer a1'
a2p = (1 + G)*a2;%computer a2'
c1p = sqrt(a1p^2 + b1^2);%computer C1'
c2p = sqrt(a2p^2 + b2^2);%computer C2'
%c_bar_p = (c1p + c2p) / 2;%%%compute C'_bar
h1p = atan2(b1,a1p);%compute h1'
h2p = atan2(b2,a2p);%compute h2'
%%h_bar_p = (h1p + h2p) / 2;%%%not clear%compute ΔL',ΔC',ΔH'
del_L_p = L2 - L1;%compute ΔL'
del_C_p = c2p - c1p;%compute ΔC’
dhp = h2p - h1p;%compute h2' - h1'
if c1p*c2p == 0; dhp = 0;%if C1' × C2' = 0,Δh' = 0;
elseif abs(dhp) <= pi; dhp = dhp;%if |Δh' ≤ 180°|,Δh' = dhp;
elseif dhp > pi; dhp = dhp - 2*pi;%if Δh'>180°,Δh' = Δh' - 360°;
elseif dhp < -pi; dhp = dhp + 2*pi;%if Δh'<-180°,Δh' = Δh' +360°;
end
del_H_p = 2 * (c1p*c2p)^(1/2)*sin(dhp/2);%%compute h'_bar
h_bar = h1p + h2p;%compute h'_sum
if c1*c2 == 0; h_bar = 0;
elseif abs(h1p - h2p) <= pi; h_bar = h_bar / 2;
elseif ((abs(h2p - h1p) > pi)&&((h1p + h2p) < 2*pi)); h_bar = ((h2p + h1p) + 2*pi)/2;
elseif ((abs(h2p - h1p) > pi)&&((h1p + h2p) >= 2*pi)); h_bar = ((h2p + h1p) - 2*pi)/2;
end
%%endL_bar_p = (L1 + L2) / 2;%compute Lave'
C_bar_p = (c1p + c2p) / 2;%compute Cave'
Tmp = 1 - 0.17*cos(h_bar - pi/6) + 0.24*cos(2*h_bar) + 0.32*cos(3*h_bar + pi/30) - 0.20*cos(4*h_bar - 63*pi/180);%compute T% Calculate delta C00
del_theta = 30 * exp(-((h_bar-275*180/pi)/25)^2);
Rc = 2 * (C_bar_p^7/(C_bar_p^7+25^7))^(1/2);
Sl = 1 + 0.015*(L_bar_p - 50)^2/(20+(L_bar_p-50)^2)^(1/2);
Sc = 1 + 0.045 * C_bar_p;
Sh = 1 + 0.015 * C_bar_p * Tmp;
Rt = -sin(2 * del_theta) * Rc;
del_E00 = sqrt((del_L_p/(kL*Sl))^2 + (del_C_p/(kC*Sc))^2 + (del_H_p/(kH*Sh))^2 + Rt*((del_C_p/(kC*Sc))*(del_H_p/(kH*Sh))));
del_C00 = sqrt((del_C_p/(kC*Sc))^2 + (del_H_p/(kH*Sh))^2 + Rt*((del_C_p/(kC*Sc))*(del_H_p/(kH*Sh))));rlst = [del_C00,del_E00];
end
http://www.dtcms.com/a/272660.html

相关文章:

  • 【零基础学AI】第35讲:策略梯度方法 - 连续控制任务实战
  • Swift 图论实战:DFS 算法解锁 LeetCode 323 连通分量个数
  • 快速搭建服务器,fetch请求从服务器获取数据
  • ReentrantLock 与 Synchronized 的区别
  • 给MySQL做定时备份,一天3次
  • method_name字段是什么
  • 单片机基础(STM32-DAY2(GPIO))
  • Linux驱动06 --- UDP
  • 飞书AI技术体系
  • web 系统对接飞书三方登录完整步骤实战使用示例
  • 低温冷启动 高温热启动
  • OpenCV 图像进阶处理:特征提取与车牌识别深度解析
  • 醋酸镨:闪亮的稀土宝藏,掀开科技应用新篇章
  • Spring IoC 如何注入一些简单的值(比如配置文件里的字符串、数字)?
  • 【文献阅读】Depth Anything: Unleashing the Power of Large-Scale Unlabeled Data
  • MyBatis 使用教程及插件开发
  • 自动驾驶环境感知:天气数据采集与融合技术实战
  • AI-Sphere-Butler项目语音切换数字人管家形象功能老是开发不成功。
  • Oracle 数据库管理与维护实战指南(用户权限、备份恢复、性能调优)
  • 深度学习与图像处理案例 │ 基于深度学习的自动驾驶小车
  • GitHub上优秀的开源播放器项目介绍及优劣对比
  • 申请注册苹果iOS企业级开发者证书需要公司拥有什么规模条件
  • Nacos的基本功能以及使用Feign进行微服务间的通信
  • 【网络编程】 TCP 协议栈的知识汇总
  • ZW3D 二次开发-创建圆柱体
  • Qt cannot find C:\WINDOWS\TEMP\cctVBBgu: Invalid argument
  • QT5使用cmakelists引入Qt5Xlsx库并使用
  • 达梦数据库不兼容 SQL_NO_CACHE 报错解决方案
  • C++交叉编译工具链制作以及QT交叉编译环境配置
  • 生产环境CI/CD流水线构建与优化实践指南