【色度学】HSP 色彩空间
2020-10-15 本文已影响0人
罗引杰
由于HSL 和 HSV 的值并不能反应人眼看到的真实亮度(如下图),实际上人眼看青色会很亮, 但是在HSV模型中, 青色表现的亮度和蓝色一样, 为了解决这种亮度表示问题,所以引入了HSP色彩空间, 以反应人眼看到的真实的颜色;
image.pngHSP 的亮度公式定义为:
image.png
互转公式:
//如果是BT709 或 sRGB 色域参数如下, 不同的色域使用不同的Pr Pg Pb
#define Pr .299
#define Pg .587
#define Pb .114
// public domain function by Darel Rex Finley, 2006
//
// This function expects the passed-in values to be on a scale
// of 0 to 1, and uses that same scale for the return values.
//
// See description/examples at alienryderflex.com/hsp.html
void RGBtoHSP(
double R, double G, double B,
double *H, double *S, double *P) {
// Calculate the Perceived brightness.
*P=sqrt(R*R*Pr+G*G*Pg+B*B*Pb);
// Calculate the Hue and Saturation. (This part works
// the same way as in the HSV/B and HSL systems???.)
if (R==G && R==B) {
*H=0.; *S=0.; return; }
if (R>=G && R>=B) { // R is largest
if (B>=G) {
*H=6./6.-1./6.*(B-G)/(R-G); *S=1.-G/R; }
else {
*H=0./6.+1./6.*(G-B)/(R-B); *S=1.-B/R; }}
else if (G>=R && G>=B) { // G is largest
if (R>=B) {
*H=2./6.-1./6.*(R-B)/(G-B); *S=1.-B/G; }
else {
*H=2./6.+1./6.*(B-R)/(G-R); *S=1.-R/G; }}
else { // B is largest
if (G>=R) {
*H=4./6.-1./6.*(G-R)/(B-R); *S=1.-R/B; }
else {
*H=4./6.+1./6.*(R-G)/(B-G); *S=1.-G/B; }}}
// public domain function by Darel Rex Finley, 2006
//
// This function expects the passed-in values to be on a scale
// of 0 to 1, and uses that same scale for the return values.
//
// Note that some combinations of HSP, even if in the scale
// 0-1, may return RGB values that exceed a value of 1. For
// example, if you pass in the HSP color 0,1,1, the result
// will be the RGB color 2.037,0,0.
//
// See description/examples at alienryderflex.com/hsp.html
void HSPtoRGB(
double H, double S, double P,
double *R, double *G, double *B) {
double part, minOverMax=1.-S ;
if (minOverMax>0.) {
if ( H<1./6.) { // R>G>B
H= 6.*( H-0./6.); part=1.+H*(1./minOverMax-1.);
*B=P/sqrt(Pr/minOverMax/minOverMax+Pg*part*part+Pb);
*R=(*B)/minOverMax; *G=(*B)+H*((*R)-(*B)); }
else if ( H<2./6.) { // G>R>B
H= 6.*(-H+2./6.); part=1.+H*(1./minOverMax-1.);
*B=P/sqrt(Pg/minOverMax/minOverMax+Pr*part*part+Pb);
*G=(*B)/minOverMax; *R=(*B)+H*((*G)-(*B)); }
else if ( H<3./6.) { // G>B>R
H= 6.*( H-2./6.); part=1.+H*(1./minOverMax-1.);
*R=P/sqrt(Pg/minOverMax/minOverMax+Pb*part*part+Pr);
*G=(*R)/minOverMax; *B=(*R)+H*((*G)-(*R)); }
else if ( H<4./6.) { // B>G>R
H= 6.*(-H+4./6.); part=1.+H*(1./minOverMax-1.);
*R=P/sqrt(Pb/minOverMax/minOverMax+Pg*part*part+Pr);
*B=(*R)/minOverMax; *G=(*R)+H*((*B)-(*R)); }
else if ( H<5./6.) { // B>R>G
H= 6.*( H-4./6.); part=1.+H*(1./minOverMax-1.);
*G=P/sqrt(Pb/minOverMax/minOverMax+Pr*part*part+Pg);
*B=(*G)/minOverMax; *R=(*G)+H*((*B)-(*G)); }
else { // R>B>G
H= 6.*(-H+6./6.); part=1.+H*(1./minOverMax-1.);
*G=P/sqrt(Pr/minOverMax/minOverMax+Pb*part*part+Pg);
*R=(*G)/minOverMax; *B=(*G)+H*((*R)-(*G)); }}
else {
if ( H<1./6.) { // R>G>B
H= 6.*( H-0./6.); *R=sqrt(P*P/(Pr+Pg*H*H)); *G=(*R)*H; *B=0.; }
else if ( H<2./6.) { // G>R>B
H= 6.*(-H+2./6.); *G=sqrt(P*P/(Pg+Pr*H*H)); *R=(*G)*H; *B=0.; }
else if ( H<3./6.) { // G>B>R
H= 6.*( H-2./6.); *G=sqrt(P*P/(Pg+Pb*H*H)); *B=(*G)*H; *R=0.; }
else if ( H<4./6.) { // B>G>R
H= 6.*(-H+4./6.); *B=sqrt(P*P/(Pb+Pg*H*H)); *G=(*B)*H; *R=0.; }
else if ( H<5./6.) { // B>R>G
H= 6.*( H-4./6.); *B=sqrt(P*P/(Pb+Pr*H*H)); *R=(*B)*H; *G=0.; }
else { // R>B>G
H= 6.*(-H+6./6.); *R=sqrt(P*P/(Pr+Pb*H*H)); *B=(*R)*H; *G=0.; }}}