From 494945f8eaede2b776089d727e2b77ff05a3c6d2 Mon Sep 17 00:00:00 2001 From: Mirta Date: Mon, 2 Jul 2018 14:09:56 +0300 Subject: In/Out gamut! --- .../Native/Tango.ColorLib/ColorConverter.cpp | 818 +++++++++++++++------ .../Native/Tango.ColorLib/ColorConverter.h | 51 +- .../Native/Tango.ColorLib/Tango.ColorLib.vcxproj | 4 + .../Tango.ColorLib/Tango.ColorLib.vcxproj.filters | 12 + .../Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.cpp | 26 + .../Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.h | 3 +- .../Native/Tango.ColorLib/Utils/ColorConvert.cpp | 41 +- .../Native/Tango.ColorLib/Utils/ColorConvert.h | 10 +- .../Native/Tango.ColorLib/Utils/ColorTransf.cpp | 164 +++-- .../Native/Tango.ColorLib/Utils/GBD.cpp | 311 ++++++++ .../Native/Tango.ColorLib/Utils/GBD.h | 38 + .../Native/Tango.ColorLib/Utils/Interp.h | 2 +- .../Native/Tango.ColorLib/Utils/NumConversions.cpp | 46 ++ .../Native/Tango.ColorLib/Utils/NumConversions.h | 16 + Software/Visual_Studio/Native/Tester/Tester.cpp | 11 +- .../Visual_Studio/Native/Tester/Tester.vcxproj | 1 + 16 files changed, 1250 insertions(+), 304 deletions(-) create mode 100644 Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.cpp create mode 100644 Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.h create mode 100644 Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.cpp create mode 100644 Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.h (limited to 'Software/Visual_Studio') diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.cpp b/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.cpp index b311e0e83..ed95ef95b 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.cpp +++ b/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.cpp @@ -14,9 +14,11 @@ #include "C_RGB_XYZ_Lab.h" #include "ColorConvert.h" #include "ColorTransf.h" +#include "NumConversions.h" #include "Interp.h" #include #include +#include #define dL 2.0 #define dC 2.0 @@ -27,12 +29,19 @@ #define Y_b 20.0 #define eps 1e-06 #define NegValue -1000 +#define WPTol 1.0 +#define dETol 2.0 + Tango::ColorLib::ColorConverter::ColorConverter() :m_A2BTransform(NULL), m_B2ATransform(NULL), -m_CalibCurves(NULL), m_CalibDatasize(NULL), +m_GBD(NULL), m_CalibCurves(NULL), m_CalibDatasize(NULL), m_Conv02(NULL), m_maxNlPerCM(NULL), m_nA2BnSepIn(0), m_nA2BnSepOut(0), m_nB2AnSepIn(0), m_nB2AnSepOut(0), -m_nInks(0), m_nVolumes(0) +m_nInks(0), m_nVolumes(0), m_AdaptWP(false) { + m_whitepointLab.Set(-1, -1, -1); + m_whitepointXYZ_Strip.Set(-1, -1, -1); + m_whitepointXYZ_CT.Set(-1, -1, -1); + } Tango::ColorLib::ColorConverter::~ColorConverter() @@ -47,6 +56,16 @@ Tango::ColorLib::ColorConverter::~ColorConverter() delete m_B2ATransform; m_B2ATransform = NULL; } + if (m_GBD != NULL) + { + delete m_GBD; + m_GBD = NULL; + } + if (m_Conv02 != NULL) + { + delete m_Conv02; + m_Conv02 = NULL; + } if (m_CalibDatasize != NULL) { delete[] m_CalibDatasize; @@ -59,21 +78,18 @@ Tango::ColorLib::ColorConverter::~ColorConverter() } } -void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorXd RGB, VectorXd Volume, int InGamutRegion, MatrixXd &ORGBHive, MatrixXd &OVolumeHive, int nHive, int *&OGamutRegion, int *indDataMax) +void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorXd RGB, VectorXd Volume, int InGamutRegion, + MatrixXd &ORGBHive, MatrixXd &OVolumeHive, int nHive, int *&OGamutRegion, int *indDataMax) { size_t retVal = 0; - //Initialize CIECAM02 transformation - Illum IL = D65; - SURROUND sur = average; - CAM02CS CS = UCS; - ColorConvert *Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS); - VectorXd LabV(3); LabV = Lab; // LabV << Lab[0], Lab[1], Lab[2]; VectorXd Jab(3); - Jab = Conv02->LabToJab(LabV, sur); + SURROUND sur = m_Conv02->getSurround(); + CAM02CS CS = m_Conv02->getCAM02CS(); + Jab = m_Conv02->LabToJab(LabV, sur); //JCH coordinates double hue = 0.0; @@ -99,7 +115,7 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorX Jab1(j1, 1) = Jab(1) + dC2*cos(hue + i*dH12); Jab1(j1, 2) = Jab(2) + dC2*sin(hue + i*dH12); } - for (int i = 0; i < 2; ++i) +/* for (int i = 0; i < 2; ++i) { j1 = i + 18; Jab1(j1, 0) = Jab(0) + (i + 1)*dL; @@ -112,18 +128,22 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorX Jab1(j1, 0) = Jab(0) - (i + 1)*dL; Jab1(j1, 1) = Jab(1); Jab1(j1, 2) = Jab(2); - } + }*/ //convert back to CIELab MatrixXd Lab1(nHive, 3); - MatrixXd RGBTmpVec(nHive + 2, 3); - MatrixXd VolumeHive(nHive + 2, m_nVolumes); + //MatrixXd RGBTmpVec(nHive + 2, 3); + //MatrixXd VolumeHive(nHive + 2, m_nVolumes); + MatrixXd RGBTmpVec(nHive + 1, 3); + MatrixXd VolumeHive(nHive + 1, m_nVolumes); VectorXd xyz(3); VectorXd JabTmp(3); C_RGB_XYZ_Lab xyzVal, LabVal; double *tmpRGB; double *InkOut = new double[m_nInks]; - int *GamutRegion = new int[nHive + 2]; + //int *GamutRegion = new int[nHive + 2]; + int *GamutRegion = new int[nHive + 1]; + double *Lab1P = new double[3]; VectorXd Vol(m_nVolumes); int j = 0; @@ -131,9 +151,9 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorX { //fill data JabTmp << Jab1(i, 0), Jab1(i, 1), Jab1(i, 2); - xyz = Conv02->Jab_2_XYZ(JabTmp, CS); + xyz = m_Conv02->Jab_2_XYZ(JabTmp, CS); xyzVal.Set(xyz / 100.0); - LabVal = Conv02->XYZToLab(xyzVal); + LabVal = m_Conv02->XYZToLab(xyzVal); Lab1(i, 0) = LabVal.Get_x(); Lab1(i, 1) = LabVal.Get_y(); Lab1(i, 2) = LabVal.Get_z(); @@ -142,33 +162,31 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorX Lab1P[j] = Lab1(i, j); m_B2ATransform->evalLab2InkP(Lab1P, InkOut, GamutRegion[i]); //InkOut is in units of 16 bits m_A2BTransform->evalInkP2Lab(InkOut, Lab1P, GamutRegion[i]); - //Check id whitepoints match - //LabOut is under D65 + //Check if whitepoints match + //LabOut is under D65 illumination double * LabInFinal = Lab1P; - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) + //Convert to CT WP + LabInFinal = m_Conv02->ChangeWP(LabInFinal, m_whitepointXYZ_CT, m_WP); //dest, source + if (m_AdaptWP) { - LabInFinal = Conv02->ToAbsoluteLab(LabInFinal, m_WP, m_whitepointXYZ_Strip); - LabInFinal = Conv02->ToAbsoluteLab(LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); - LabInFinal = Conv02->ToAbsoluteLab(LabInFinal, m_whitepointXYZ_CT, m_WP); + //Convert to Strip whitepoint + LabInFinal = m_Conv02->ChangeWP(LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } - Conv02->SetReferenceWhite(D65); + m_Conv02->SetReferenceWhite(D65); //Convert to RGB - tmpRGB = Conv02->LabtoRGB(LabInFinal); + tmpRGB = m_Conv02->LabtoRGB(LabInFinal); for (int j = 0; j < 3; ++j) RGBTmpVec(i, j) = std::min(std::max(tmpRGB[j], 0.0), 255.0); - //Use Lab to convert to Linear Inks - m_B2ATransform->evalLab2InkP(LabInFinal, InkOut, GamutRegion[i]); //InkOut is in units of 16 bits - //convert to [0-100] + VectorXd InkOutV = DoubleToVector(InkOut, m_nInks); ConvertToNLInks(InkOutV, InkOutV); NLInkPToVolume(InkOutV, Vol); for (int j = 0; j < 3; ++j) VolumeHive(i, j) = Vol(j); } - for (int i = 0; i < 2; ++i) - { + //for (int i = 0; i < 2; ++i) + for (int i = 0; i < 1; ++i) + { for (j = 0; j < 3; ++j) { VolumeHive(nHive + i, j) = Volume(j); @@ -178,16 +196,12 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(VectorXd Lab, VectorX } //Organize hive into 5x5 matrix - //Hive Vector follows the ordering 0-(0,0) 1-(0,1) 2-(0,2),...., 22-(4,2), 23-(4,3), 24-(4,4) + //Hive Vector follows the ordering 0-(0,0) 1-(0,1) 2-(0,2),...., + //22-(4,2), 23-(4,3), 24-(4,4) not implemented yet //Some of the matrix elements are empty ArrangeHiveData(RGBTmpVec, VolumeHive, GamutRegion, nHive, ORGBHive, OVolumeHive, OGamutRegion); FindTriplet(Lab, Lab1, nHive, indDataMax); - if (Conv02 != NULL) - { - delete Conv02; - Conv02 = NULL; - } - + if (InkOut != NULL) { delete[]InkOut; @@ -264,12 +278,14 @@ void Tango::ColorLib::ColorConverter::ArrangeHiveData(MatrixXd RGBTmpVec, Matri //Some of the matrix elements are empty //Ordering is by hexagon position in a 5x5 grid. - VectorXd xpos(nHive + 2); - xpos << 1, 1, 1, 2, 3, 2, 1, 0, 0, 0, 1, 2, 3, 3, 4, 3, 3, 2, 5, 5, 5, 5, 5, 2; - VectorXd ypos(nHive + 2); - ypos << 3, 2, 1, 1, 2, 3, 4, 3, 2, 1, 0, 0, 0, 1, 2, 3, 4, 4, 0, 1, 3, 4, 2, 2; + //VectorXd xpos(nHive + 2); + VectorXd xpos(nHive + 1); + xpos << 1, 1, 1, 2, 3, 2, 1, 0, 0, 0, 1, 2, 3, 3, 4, 3, 3, 2, /*, 5, 5, 5, 5, 5,*/ 2; + //VectorXd ypos(nHive + 2); + VectorXd ypos(nHive + 1); + ypos << 3, 2, 1, 1, 2, 3, 4, 3, 2, 1, 0, 0, 0, 1, 2, 3, 4, 4,/* 0, 1, 3, 4, 2,*/ 2; int i, j; - for (i = 0; i <= nHive + 1; ++i) + for (i = 0; i < nHive + 1; ++i) { int index = (int)(xpos(i) * 5 + ypos(i)); for (j = 0; j < 3; ++j) @@ -321,6 +337,7 @@ void Tango::ColorLib::ColorConverter::fillRGB(OutputCoordinates *outputCoords, V outputCoords->blue = (int32_t)std::round(RGBOut(2)); } + void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* conversionInput) { //Read thread white. Thread White is given in CIELab Space @@ -331,128 +348,197 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* ColorConvert CConvert(D65, D65); C_RGB_XYZ_Lab tmpW; tmpW = CConvert.LabToXYZ(m_whitepointLab); - m_whitepointXYZ_Strip.Set(tmpW.Get_x(), tmpW.Get_y(), tmpW.Get_z()); - //***************This is temporary has to be replaced by the table's white point, once the new Color Table Format is set. - m_whitepointXYZ_CT.Set(tmpW.Get_x(), tmpW.Get_y(), tmpW.Get_z()); + m_whitepointXYZ_Strip.Set(tmpW.Get_x(), tmpW.Get_y(), tmpW.Get_z()); } else { throw std::exception("misssing one of the whitepoint components"); return; } - //get ND color inverse LUT - uint8_t *B2ALUT; - long B2ALutsize = 0; - if (conversionInput->has_inversedata) - { - B2ALUT = conversionInput->inversedata.data; - B2ALutsize = (long)(conversionInput->inversedata.len); - m_B2ATransform = new ColorTransf(); - m_B2ATransform->InitData(B2ALUT, B2ALutsize); - SetnB2AnSepIn(m_B2ATransform->GetSeparationsIn()); - if (m_nB2AnSepIn != 3) + //parse Color Tansformations, placed in forward data + int bytesread = 0; + NumConversions conv; + int tag_count = 0; + if (conversionInput->has_forwarddata) + { + //Read Header + CT_Header header = read_header(conversionInput, bytesread); + uint32_t tmp; + uint8_t *buff = conversionInput->forwarddata.data; + tmp = conv.ByteToInt(buff, bytesread); + tag_count = (int)tmp; + bytesread += 4; + //read Tag Table + char **TagNames = new char*[tag_count]; + int **TagSize = new int*[tag_count]; + char *tmpC; + int n = 0; + int i, j; + for ( i = 0; i < tag_count; ++i) { - throw std::exception("Wrong input dimensions in B2A transform"); - return; + TagSize[i] = new int[3]; + tmp =conv.ByteToInt(buff, bytesread); + tmpC = conv.getchar(tmp, n); + TagNames[i] = new char[n]; + for (j = 0; jGetSeparationsOut()); - } - else - { - if ((conversionInput->colorspace == COLOR_SPACE__RGB) || - (conversionInput->colorspace == COLOR_SPACE__LAB) || - (conversionInput->colorspace == COLOR_SPACE__PANTON)) - throw std::exception(" Missing necessary Lab to Ink Transform"); - return; - } - - //get ND color forward LUT - uint8_t *A2BLUT; - long A2BLutsize; + int *TList = new int[tag_count]; + for (int k = 0; k < tag_count; ++k) + { + if (strncmp(TagNames[k], "A2B ",4) ==0) + TList[k] = A2B; + else if (strncmp(TagNames[k], "B2A ",4)==0) + TList[k] = B2A; + else if (strncmp(TagNames[k], "wtpt",4)==0) + TList[k] = wtpt; + else if (strncmp(TagNames[k], "desc",4)==0) + TList[k] = desc; + else if (strncmp(TagNames[k], "gbd ",4)==0) + TList[k] = gbd; + else if (strncmp(TagNames[k], "cprt",2)==0) + TList[k] = cprt; + else + throw std::exception("Unknown Tag in Color Tables"); + } + for (int k = 0; k < tag_count; ++k) + { + switch (TList[k]) + { + case A2B: + { + uint8_t *A2BLUT = &(conversionInput->forwarddata.data[TagSize[k][0]]); + int A2BLutsize = TagSize[k][1]; + m_A2BTransform = new ColorTransf(); + m_A2BTransform->InitData(A2BLUT, A2BLutsize); + break; + } + case B2A: + { + uint8_t *B2ALUT = &(conversionInput->forwarddata.data[TagSize[k][0]]); + int B2ALutsize = TagSize[k][1]; + m_B2ATransform = new ColorTransf(); + m_B2ATransform->InitData(B2ALUT, B2ALutsize); + break; + } + case gbd: + { + uint8_t *GBDList = &(conversionInput->forwarddata.data[TagSize[k][0]]); + m_GBD = new GBD(); + int GBDSize = TagSize[k][1]; + m_GBD->InitData(GBDList, GBDSize); + break; + } + case wtpt: + { + read_xyz_type(TagSize[k][0], TagSize[k][1], &m_whitepointXYZ_CT, conversionInput); + + break; + } + case cprt: + { + std::string textstr; + read_text_type(TagSize[k][0], TagSize[k][1], &textstr, conversionInput); + break; + } + case desc: + { + std::string textdescstr; + read_text_description_type(TagSize[k][0], TagSize[k][1], textdescstr, conversionInput); + break; + } + default: + { + throw std::exception("Unresolved Tag in Color Tables"); + return; + } - if (conversionInput->has_forwarddata) - { - A2BLUT = conversionInput->forwarddata.data; - A2BLutsize = conversionInput->forwarddata.len; - m_A2BTransform = new ColorTransf(); - m_A2BTransform->InitData(A2BLUT, A2BLutsize); - SetnA2BnSepIn(m_A2BTransform->GetSeparationsIn()); - SetnA2BnSepOut(m_A2BTransform->GetSeparationsOut()); - if (m_nA2BnSepOut != 3) + } + } + for (int i = 0; i < tag_count; ++i) { - throw std::exception(" Wrong output dimensions in Ink to Lab transform"); - return; + delete[] TagNames[i]; + delete[] TagSize[i]; } + delete[]TagNames; + delete[] TagSize; + delete[] TList; } - else + + + //Verify all relevant tags had been read + if (m_A2BTransform == NULL) { - if ((conversionInput->has_colorspace == COLOR_SPACE__CMYK) || - (conversionInput->has_colorspace == COLOR_SPACE__LAB) || - (conversionInput->colorspace == COLOR_SPACE__PANTON)) - throw std::exception("Missing necessary Ink to Lab Transform"); - return; + throw std::exception("Missing Forward Transform in Color Tables"); + return; } - if (m_nB2AnSepIn != m_nA2BnSepOut || - m_nA2BnSepIn != m_nB2AnSepOut) + if (m_B2ATransform == NULL) { - throw std::exception("Forward and InverseTables dimensions do not match"); - return; + throw std::exception("Missing Inverse Transform in Color Tables"); + return; } - - if (A2BLUT != NULL) + if (m_GBD == NULL) { - delete[] A2BLUT; - A2BLUT = NULL; + throw std::exception("Missing Gamut Boundary Descriptor in Color Tables"); + return; } - if (B2ALUT != NULL) + if ((m_whitepointXYZ_CT.Get_x() ==-1) && (m_whitepointXYZ_CT.Get_y() == -1) && (m_whitepointXYZ_CT.Get_z() == -1)) { - delete B2ALUT; - B2ALUT = NULL; + throw std::exception("Missing Whitepoint in Color Tables"); + return; } return; // OK } -void Tango::ColorLib::ColorConverter::readCalibrationTables(ConversionInput* conversionInput) -{ - SetNumberofInks((int)(conversionInput->inputcoordinates->n_inputliquids)); - CalibData *CalibCurves = new CalibData[m_nInks]; - m_CalibCurves = new CalibData[m_nInks]; - for (int i = 0; i < m_nInks; ++i) - { - InputLiquid* InkType = conversionInput->inputcoordinates->inputliquids[i]; - //CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype)); - m_CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype)); - //CalibCurves[i].SetMaxNlPerCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter); - m_CalibCurves[i].SetMaxNlPerCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter); - switch (InkType->calibrationdata->liquidtype) - { - case LIQUID_TYPE__Cyan: - case LIQUID_TYPE__Magenta: - case LIQUID_TYPE__Yellow: - case LIQUID_TYPE__Black: + void Tango::ColorLib::ColorConverter::readCalibrationTables(ConversionInput* conversionInput) + { + SetNumberofInks((int)(conversionInput->inputcoordinates->n_inputliquids)); + CalibData *CalibCurves = new CalibData[m_nInks]; + m_CalibCurves = new CalibData[m_nInks]; + for (int i = 0; i < m_nInks; ++i) { - // calibration data. - CalibrationData* calibrationData = InkType->calibrationdata; - SetCalibData(calibrationData, i, &m_CalibCurves[i]); - break; - } - default: - throw std::exception("could not fill all calibration tables"); - return; + InputLiquid* InkType = conversionInput->inputcoordinates->inputliquids[i]; + //CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype)); + m_CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype)); + //CalibCurves[i].SetMaxNlPerCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter); + m_CalibCurves[i].SetMaxNlPerCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter); + switch (InkType->calibrationdata->liquidtype) + { + case LIQUID_TYPE__Cyan: + case LIQUID_TYPE__Magenta: + case LIQUID_TYPE__Yellow: + case LIQUID_TYPE__Black: + { + // calibration data. + CalibrationData* calibrationData = InkType->calibrationdata; + SetCalibData(calibrationData, i, &m_CalibCurves[i]); + break; + } + default: + { + throw std::exception("could not fill all calibration tables"); + return; + } + } } + // m_CalibCurves=CalibCurves; + return; } - // m_CalibCurves=CalibCurves; - return; -} + void Tango::ColorLib::ColorConverter::SetCalibData(CalibrationData *calibrationData, int i, CalibData *tmpCurve) { if (calibrationData->calibrationpoints <= 0) { char msg[100]; - strcpy(msg, "No Calibration points in table "); - char ai[10]; - strcat(msg, itoa(i, ai, 10)); + int n = + strcpy_s (msg, 100, "No Calibration points in table "); + throw std::exception(msg); return; } @@ -483,69 +569,62 @@ void Tango::ColorLib::ColorConverter::SetCalibData(CalibrationData *calibrationD return; } -void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion) +void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, + VectorXd &LabOut, int &GamutRegion, bool &InGamut) { size_t nInks = 0; C_RGB_XYZ_Lab DataLab; - + SURROUND sur = m_Conv02->getSurround(); switch (conversionInput->colorspace) { case (COLOR_SPACE__RGB): { // Basic assumption: if data is given in RGB space, conversion should be in relative colorimetric, //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero - //if Strip whitepoint and Table whitepoint do not match, make the conversion: - // RGB to XYZ (D65) -> Strip Thread (from D65 to Strip) - //Convert from strip to Color table WP - //Convert from Color Table WP to D65 - //Convert to Lab via RGB->Lab transformation - //Convert to ink via B2A table - //Convert to Lab via A2B table returns the actual Lab which maches the Gamut - //Convert to RGB + // and the coverted RGB will refect the color of the thread + //The workflow is a follows: + //1. Convert RGB to Lab (Whitepoint is D65, same as tables) + //2. Convert Lab to Inks (B2A tables), Inks to Volume + //3. Convert Inks to Lab (A2B tables) to get the in/on Gamut Lab + //4. Convert Lab to Absolute colorimetric taking into account the Strip and CT whitepoints + //5. Use the above Lab to obtain RGB + RGBOut(0) = conversionInput->inputcoordinates->red; RGBOut(1) = conversionInput->inputcoordinates->green; RGBOut(2) = conversionInput->inputcoordinates->blue; //convert to Lab ColorConvert CConvertD65(D65, D65); //Destination, source - double *LabIn; + double *LabIn; double *RGBOutP = VectorToDouble(RGBOut); + //RGB to Lab LabIn = CConvertD65.RGBtoLab(RGBOutP); //Values are in Relative Colorimetric, D65 + double *LabInFinal = LabIn; - //check if the thread to be used is the same as the one in the color tables - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) - { - LabInFinal = CConvertD65.ToAbsoluteLab(LabInFinal, m_WP, m_whitepointXYZ_Strip); - LabInFinal = CConvertD65.ToAbsoluteLab(LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); - LabInFinal = CConvertD65.ToAbsoluteLab(LabInFinal, m_whitepointXYZ_CT, m_WP); - } - + //Is In Gamut? + InGamut = IsInGamut(LabIn, sur); //convert to inks int GamutRegion; double *InkOutP = new double[m_nB2AnSepOut]; + //LabInFinal is in Relative Colorimetric, just like the Color Tables m_B2ATransform->evalLab2InkP(LabInFinal, InkOutP, GamutRegion); //InkOut is in units of 16 bits - //convert to Lab to get In-Gamut Lab - double *LabInP = new double[3]; - m_A2BTransform->evalInkP2Lab(InkOutP, LabInP, GamutRegion); InkOut = DoubleToVector(InkOutP, m_nInks); - //Convert to Lab to get effective RGB - //Lab is in D65 - double *LabOutFinal; - LabOutFinal = LabInP; - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) + //Convert to Lab to get the actual in Gamut Lab + double *LabInP = new double[3]; + m_A2BTransform->evalInkP2Lab(InkOutP, LabInP, GamutRegion); //Lab is in Relative Colorimetric + LabOut = DoubleToVector(LabInP, 3); + //Convert to CT thread, LabIn is in Relative Colorimetric Space + LabInFinal = CConvertD65.ChangeWP(LabInP, m_whitepointXYZ_CT, m_WP); + //check if the thread to be used is the same as the one in the color tables + if (m_AdaptWP) { - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_WP, m_whitepointXYZ_CT); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_Strip, m_WP); + //Convert to Strip White Point + LabInFinal = CConvertD65.ChangeWP(LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } - LabOut = DoubleToVector(LabOutFinal,3); + CConvertD65.SetReferenceWhite(D65); //Get the Gamut Mapped RGB Based on Absolute Colorimetric Data - RGBOutP = CConvertD65.LabtoRGB(LabOutFinal); + RGBOutP = CConvertD65.LabtoRGB(LabInFinal); RGBOut = DoubleToVector(RGBOutP, 3); if (LabInP != NULL) { @@ -571,21 +650,28 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* } case (COLOR_SPACE__LAB): { + // Basic assumption: Lab data has the same whitepoint as the STRIP thread. + //The workflow is a follows: + //1. Convert Lab to Relative colorimetric. chack if there is a match between STRIP and Color Tables + //2. Convert Lab to Inks (B2A tables), Inks to Volume + //3. Convert Inks to Lab (A2B tables) to get the in/on Gamut Lab + //4. Convert Lab to Absolute colorimetric taking into account the Strip and CT whitepoints + //5. Use the above Lab to obtain RGB double *LabIn = new double[3]; LabIn[0] = conversionInput->inputcoordinates->l; LabIn[1] = conversionInput->inputcoordinates->a; LabIn[2] = conversionInput->inputcoordinates->b; - //the assumption is that the color space has illumination that matches the whitepoint of the strip + //the assumption is that the color space has illumination that matches the whitepoint of the Strip ColorConvert CConvertD65(D65, D65); //Destination, source double *LabInFinal = LabIn; - //Check if Color Tables and Strip whitepoints are the same, otherwiae convert - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) + // Lab is assumed to match the color of the STRIP, however the tables could have a different WP + //Check if Color Tables and Strip whitepoints are the same, otherwise convert + if (m_AdaptWP) { - LabInFinal = CConvertD65.ToAbsoluteLab(LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); - LabInFinal = CConvertD65.ToAbsoluteLab(LabInFinal, m_whitepointXYZ_Strip, m_WP); + LabInFinal = CConvertD65.ChangeWP(LabInFinal, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables } + LabInFinal = CConvertD65.ChangeWP(LabInFinal, m_WP, m_whitepointXYZ_CT); //to Relative + InGamut = IsInGamut(LabInFinal, sur); //convert to Inks int GamutRegion; double *InkOutP = new double[m_nB2AnSepOut]; @@ -593,13 +679,14 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* //Convert Inks to Lab to get the Gamut Mapped Lab m_A2BTransform->evalInkP2Lab(InkOutP, LabIn, GamutRegion); LabOut = DoubleToVector(LabIn, 3); + InkOut = DoubleToVector(InkOutP, m_nInks); double *LabOutFinal = LabIn; - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) + //LabOutFinal is in Relative Colorimetric + //Reverse the conversion process to bring back Lab to STRIP white point + LabOutFinal = CConvertD65.ChangeWP(LabOutFinal, m_whitepointXYZ_CT, m_WP); + if (m_AdaptWP) { - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_WP, m_whitepointXYZ_CT); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); + LabOutFinal = CConvertD65.ChangeWP(LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT ); } CConvertD65.SetReferenceWhite(D65); //Convert to RGB @@ -607,6 +694,11 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* RGBOutP = CConvertD65.LabtoRGB(LabOutFinal); RGBOut = DoubleToVector(RGBOutP, 3); + if (InkOutP != NULL) + { + delete[] InkOutP; + InkOutP = NULL; + } if (LabIn != NULL) { delete[] LabIn; @@ -617,6 +709,7 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* case(COLOR_SPACE__CMYK): {//no conversion //missing from structure light inks or special colors + // just convert Lab for rgb display double *outData = new double[m_nA2BnSepIn]; size_t CountSep = 0; outData[0] = conversionInput->inputcoordinates->cyan; @@ -645,19 +738,17 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* //LabOut is in relative colorimetric ColorConvert CConvertD65(D65, D65); double *LabOutFinal = LabOutP; + InGamut = true; //Check if white points match - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) - { - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_WP, m_whitepointXYZ_CT); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_Strip, m_WP); + LabOutFinal = CConvertD65.ChangeWP(LabOutFinal, m_whitepointXYZ_CT, m_WP); + if (m_AdaptWP) + {//check if this is needed + LabOutFinal = CConvertD65.ChangeWP(LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } LabOut = DoubleToVector(LabOutFinal, 3); CConvertD65.SetReferenceWhite(D65); //Get RGB - double *RGBOutP; + double *RGBOutP; RGBOutP = CConvertD65.LabtoRGB(LabOutFinal); RGBOut = DoubleToVector(RGBOutP, 3); if (LabOutP != NULL) @@ -665,6 +756,21 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* delete[] LabOutP; LabOutP = NULL; } + if (InkOutP != NULL) + { + delete[] InkOutP; + InkOutP = NULL; + } + if (LabOutFinal != NULL) + { + delete LabOutFinal; + LabOutFinal = NULL; + } + if (RGBOutP != NULL) + { + delete RGBOutP; + RGBOutP = NULL; + } break; } case(COLOR_SPACE__PANTON): @@ -683,9 +789,11 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* } default: + { throw std::exception(" Unsupported Color Space"); return; } + } //all data is now in linear ink format return; } @@ -698,11 +806,12 @@ void Tango::ColorLib::ColorConverter::ConvertToNLInks(VectorXd InkIn, VectorXd for (int i = 0; i < m_nVolumes; ++i) { - xValues = m_CalibCurves[i].getxCoords(); - yValues = m_CalibCurves[i].getyCoords(); + xValues = m_CalibCurves[i].getyCoords(); + yValues = m_CalibCurves[i].getxCoords(); LinInterp.Init(xValues, yValues, m_CalibCurves[i].getSize()); LinInterp.Eval(InkIn(i), InkOut(i)); } + return; } @@ -714,11 +823,12 @@ void Tango::ColorLib::ColorConverter::ConvertToLinearInks(VectorXd InkIn, Vecto for (int i = 0; i < m_nVolumes; ++i) { - xValues = m_CalibCurves[i].getyCoords(); - yValues = m_CalibCurves[i].getxCoords(); - LinInterp.Init(yValues, xValues, m_CalibCurves[i].getSize()); + xValues = m_CalibCurves[i].getxCoords(); + yValues = m_CalibCurves[i].getyCoords(); + LinInterp.Init(xValues, yValues, m_CalibCurves[i].getSize()); LinInterp.Eval(InkIn(i), InkOut(i)); } + return; } @@ -859,19 +969,16 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(ConversionInput* double *LabOutP = new double[m_nA2BnSepOut]; for (int i = 0; i < m_nA2BnSepIn; ++i) InkOutP[i] = InkOut(i); - m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion); + m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion); //LabOut is in Relative Colorimetric ColorConvert CConvertD65(D65, D65); double *LabOutFinal; //= new double[3]; LabOutFinal = LabOutP; - if ((m_whitepointXYZ_Strip.Get_x() != m_whitepointXYZ_CT.Get_x()) || - (m_whitepointXYZ_Strip.Get_y() != m_whitepointXYZ_CT.Get_y()) || - (m_whitepointXYZ_Strip.Get_z() != m_whitepointXYZ_CT.Get_z())) + LabOutFinal = CConvertD65.ChangeWP(LabOutFinal, m_whitepointXYZ_CT, m_WP); + if (m_AdaptWP) { - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_WP, m_whitepointXYZ_Strip); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); - LabOutFinal = CConvertD65.ToAbsoluteLab(LabOutFinal, m_whitepointXYZ_CT, m_WP); + LabOutFinal = CConvertD65.ChangeWP(LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } CConvertD65.SetReferenceWhite(D65); double *RGBOutP; // = new double[3]; @@ -931,12 +1038,26 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i conversion_output__init(conversionOutput); // ConversionOutput conversionOutput = CONVERSION_OUTPUT__INIT; size_t n_elements = 0; - + bool InGamut = false; m_WP.Set(0.9505, 1.00, 1.0888); //D65 //count number if inks int numofInks = CountNumberofInks(conversionInput); readColorTransformations(conversionInput); - // SetNumberOfInks(m_nB2AnSepOut); + + //Initialize CIECAM02 transformation + Illum IL = D65; + SURROUND sur = average; + CAM02CS CS = UCS; + m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS); + + SetnA2BnSepIn(m_A2BTransform->GetSeparationsIn()); + SetnA2BnSepOut(m_A2BTransform->GetSeparationsOut()); + SetnB2AnSepIn(m_B2ATransform->GetSeparationsIn()); + SetnB2AnSepOut(m_B2ATransform->GetSeparationsOut()); + SetNumberOfInks(m_nB2AnSepOut); + // Compare Strip White point to Color Table White Point + CompareWhitePoints(); + readCalibrationTables(conversionInput); if(numofInks != m_nB2AnSepOut) throw std::exception("Number of available inks does not match ink tables"); @@ -956,10 +1077,13 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i int GamutRegion = 0; //Convert input data to linear inks if (conversionInput->colorspace == COLOR_SPACE__Volume) + { ConvertVolumeToRGBDisplay(conversionInput, Volume, RGBOut, LabOut, GamutRegion); + InGamut = true; + } else { - ConvertColorToLinearInks(conversionInput, InkOut, RGBOut, LabOut, GamutRegion); + ConvertColorToLinearInks(conversionInput, InkOut, RGBOut, LabOut, GamutRegion, InGamut); //Convert to Nonlinear Inks ConvertToNLInks(InkOut, NLInkOut); //Convert to [nl/cm] @@ -970,6 +1094,8 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i output_coordinates__init(outputCoords); fillRGB(outputCoords, RGBOut); fillVolume(outputCoords, Volume); + conversionOutput->has_outofgamut = true; + conversionOutput->outofgamut = !(InGamut); conversionOutput->singlecoordinates = outputCoords; @@ -979,8 +1105,8 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i // and variation in L positioned on the side of the beehive. //The set is arrange in a 5x6 matrix, where the 5x5 contains the variation in (Hue, chroma) // and the last 5 contain the variation in L - int nHive = 22; // 18; - int MatHive = 30; //25; + int nHive = 18; //22; // 18; + int MatHive = 25;// 30; //25; MatrixXd RGBHive(MatHive, 3); VectorXd RGBHive1(3); @@ -1043,12 +1169,13 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i conversionOutput->triplecoordinates[i] = TripletData[i]; } - //Clean up - /* if (GamutRegionV != NULL) +/* //Clean up + if (GamutRegionV != NULL) { delete GamutRegionV; GamutRegionV = NULL; } */ + //Pack output... output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput)); @@ -1072,6 +1199,279 @@ int Tango::ColorLib::ColorConverter::CountNumberofInks(ConversionInput* conversi return(numberofInks); } +bool Tango::ColorLib::ColorConverter::IsInGamut(double *InLab, SURROUND sur) +{ + int nInLab = sizeof(InLab); + double *xCoord = new double[nInLab]; + //Convert InLab to CIECam02 coordinates + bool InGamut = true; + double ctr[3]; + C_RGB_XYZ_Lab center = m_GBD->getCenter(); + VectorXd JInLab(3); + JInLab << InLab[0], InLab[1], InLab[2]; + VectorXd JLab = m_Conv02->LabToJab(JInLab, sur); + ctr[0] = -JLab(0) + center.Get_x(); + ctr[1] = -JLab(1) + center.Get_y(); + ctr[2] = -JLab(2) + center.Get_z(); + double *dJLab; + dJLab=VectorToDouble(JLab); + bool intersect = false; + m_GBD->TriangleRayIntersection(dJLab, ctr, intersect, xCoord); + if (intersect) + { + VectorXd V1(3); + VectorXd V2(3); + V1 << JLab[0], JLab[1], JLab[2]; + V1 << xCoord[0], xCoord[1], xCoord[2]; + double dECMC; + m_Conv02->SymmetricaldECMC(V1, V2, dECMC); + if (dECMC < dETol) + InGamut = true; + else + InGamut = false; + } + else + InGamut = true; + if (xCoord != NULL) + { + delete [] xCoord; + xCoord = NULL; + } + return(InGamut); +} + + +Tango::CT_Header Tango::ColorLib::ColorConverter::read_header(ConversionInput* conversionInput, int &bytesread) +{ + CT_Header *Header = new CT_Header; +// unsigned int tmp = (buffer[2 * i + 1] << 8) | buffer[2 * i]; + uint8_t *ColorTable = conversionInput->forwarddata.data; + //File Size + NumConversions Conv; + Header->TblSIze = Conv.ByteToInt(ColorTable, bytesread) ; + bytesread = 4; + uint8_t versionBCT[2]; + versionBCT[0] = (unsigned int)ColorTable[bytesread]; + bytesread +=1; + versionBCT[1] = (unsigned int)ColorTable[bytesread]; + Header->Version[0] = versionBCT[0]; + Header->Version[1] = versionBCT[1] << 4; + Header->Version[2] = versionBCT[1] & 15; + bytesread += 1; + uint32_t tmp = Conv.ByteToInt(ColorTable, bytesread); + int n = 0; + char *tmpC ; + tmpC = Conv.getchar(tmp, n); + Header->ColorSpace = new char[n]; + Header->ColorSpace= tmpC; + bytesread += 4; + tmp = Conv.ByteToInt(ColorTable, bytesread); + tmpC = Conv.getchar(tmp, n); + Header->ConnectionSpace = tmpC; + bytesread += 4; + + bytesread += 12; + tmp = Conv.ByteToInt(ColorTable, bytesread); + tmpC = Conv.getchar(tmp, n); + Header->DeviceManufacturer = tmpC; + bytesread += 4; + //read illuminant + double xyz[3]; + for (int j = 0; j < 3; ++j) + { + tmp = Conv.ByteToInt(ColorTable, bytesread); + xyz[j] = (double)(tmp) / 65536; + bytesread += 4; + } + Header->Illuminant.Set(xyz[0], xyz[1], xyz[2]); + if (bytesread < 128) + { + bytesread = 128; + return(*Header); + } + else + { + throw std::exception("could not read Color table Header"); + } +} + +void Tango::ColorLib::ColorConverter::read_lut_type(int offset, int data_size, ColorTransf *Transf, ConversionInput* conversionInput) +{ + /* + 0 - 3 'prec1', 'prec2' + 4 - 7 reserved, must be 0 + 8 number of input channels, uint8 + 9 number of output channels, uint8 + 10 number of CLUT grid points, uint8 + 11 number of Shift Bits + 12 Number of gamut regions + 13 - n CLUT values, uint16 + + 13 - n output tables, uint8 + */ + if (data_size < 32) + { + throw std::exception(" LUT size missmatch"); + return; + } + int bytesread = 0; + // Check for signature + uint8_t *buff = &conversionInput->forwarddata.data[offset]; + Transf->InitData(buff, data_size); + return; +} + +void Tango::ColorLib::ColorConverter::read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *XYZ, ConversionInput* conversionInput) +{ +// 0 - 3 'XYZ ' +//4 - 7 reserved, must be 0 +// 8 - n array of XYZ numbers + +if (data_size < 8) +{ + throw std::exception("not enough data to read xyz"); +} +uint8_t *buff = &(conversionInput->forwarddata.data[offset]); +NumConversions Conv; +int bytesread = 0; +int tmpxyz = Conv.ByteToInt(buff, bytesread); +char* tmpC; +int n = 0; +tmpC = Conv.getchar(tmpxyz, n); + +char *xyztype = new char[n+1]; +strncpy_s(xyztype, n+1,tmpC, n); +if (strncmp(xyztype, "XYZ ",n) !=0) +{ + throw std::exception("Wrong Tag Type"); + return; +} +delete[] xyztype; +bytesread = 8; +int num_values = (data_size - 8) / 4; +if (floor((double)(num_values) / 3) * 3 != num_values) +{ + throw std::exception("not enough Data to read xyz"); + return; +} +double xyz[3]; +int tmp; +for (int j = 0; j < 3; ++j) +{ + tmp = Conv.ByteToInt(buff, bytesread); + xyz[j] = (double)(tmp) / 65536; + bytesread += 4; +} +XYZ->Set(xyz[0], xyz[1], xyz[2]); +return; +} + +void Tango::ColorLib::ColorConverter::read_text_type(int offset, int data_size, std::string *textstr, + ConversionInput* conversionInput) +{ + // 0 - 3 'text' + //4 - 7 reserved, must be 0 + //8 - string of(data_size - 8) 7 - bit ASCII characters, including NULL + + std::stringstream strstr; + if (data_size < 8) + { + throw std::exception("invalid Tag Name"); + strstr << ""; + *textstr = strstr.str(); + return; + } + + uint8_t *buff = &(conversionInput->forwarddata.data[offset]); + int bytesread = 0; + NumConversions Conv; + int tmp = Conv.ByteToInt(buff, bytesread); + int n = 0; + char *tmpC; + tmpC = Conv.getchar(tmp, n); + char *tagtype = new char[n+1]; + strncpy_s(tagtype,n+1, tmpC, n); + if (strcmp(tagtype, "text") !=0) + { + throw std::exception("invalid Tag Name"); + strstr << ""; + *textstr = strstr.str(); + return; + } + delete[] tagtype; + bytesread += 8; + uint8_t tmp1; + for (int i = bytesread; i < data_size; ++i) + { + tmp1 = buff[i]; + strstr.put( tmp1); + } + *textstr = strstr.str(); + return; +} + + +void Tango::ColorLib::ColorConverter::read_text_description_type(int offset, int data_size, std::string textdescstr, + ConversionInput* conversionInput) +{ + // 0 - 3 'desc' + // 4 - 7 reserved, must be 0 + // 8 - 11 ASCII invariant description count, including terminating NULL + // 12 - ASCII invariant description + + uint8_t *buff = &(conversionInput->forwarddata.data[offset]); + int bytesread = 0; + NumConversions Conv; + int tmp = Conv.ByteToInt(buff, bytesread); + int n = 0; + char *tmpC; + tmpC = Conv.getchar(tmp, n); + char *tagtype = new char[n+1]; + strncpy_s(tagtype, n+1, tmpC, n); + std::stringstream strstr; + if (strcmp(tagtype, "desc") !=0) + { + throw std::exception("invalid Tag Name"); + strstr << ""; + textdescstr = strstr.str(); + return; + } + delete[] tagtype; + bytesread += 8; + int count = Conv.ByteToInt(buff, bytesread); + bytesread += 4; + uint8_t tmp1; + for (int i = 0; i < count - 1; ++i) + { + tmp1 = buff[bytesread + i]; + strstr << tmp1; + } + textdescstr = strstr.str(); + return; +} + +void Tango::ColorLib::ColorConverter::CompareWhitePoints() +{ + ColorConvert ColConv(D65, D65); + C_RGB_XYZ_Lab Lab_CT; + C_RGB_XYZ_Lab Lab_Strip; + Lab_CT = ColConv.XYZToLab(m_whitepointXYZ_CT); + Lab_Strip = ColConv.XYZToLab(m_whitepointXYZ_Strip); + VectorXd VLab_CT(3); + VectorXd VLab_Strip(3); + VLab_CT(0) = Lab_CT.Get_x(); + VLab_CT(1) = Lab_CT.Get_y(); + VLab_CT(2) = Lab_CT.Get_z(); + VLab_Strip(0) = Lab_Strip.Get_x(); + VLab_Strip(1) = Lab_Strip.Get_y(); + VLab_Strip(2) = Lab_Strip.Get_z(); + double dECMC; + ColConv.SymmetricaldECMC(VLab_CT, VLab_Strip, dECMC); + if (dECMC < WPTol) + m_AdaptWP = false; + return; +} + //size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer) //{ // //Unpack conversion input... diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.h b/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.h index 3331199d7..1d61877fd 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.h +++ b/Software/Visual_Studio/Native/Tango.ColorLib/ColorConverter.h @@ -6,6 +6,8 @@ #include "protobuf-c\protobuf-c.h" #include "CalibData.h" #include "ColorTransf.h" +#include "ColorConvert.h" +#include "GBD.h" #include "ConversionOutput.pb-c.h" #include "CalibrationData.pb-c.h" #include "ConversionInput.pb-c.h" @@ -13,15 +15,44 @@ #pragma once namespace Tango { + typedef struct + { + unsigned int TblSIze; + unsigned int Version[3]; + char * ColorSpace; + char * ConnectionSpace; + char * DeviceManufacturer; + C_RGB_XYZ_Lab Illuminant; + } CT_Header; + + typedef enum { + XYZ, + Lab, + CMY, + CMYK + }ColorSpace; + + typedef enum { + A2B, + B2A, + cprt, + gbd, + wtpt, + desc + }TagList; + namespace ColorLib { + + class ColorConverter { public: ColorConverter(); ~ColorConverter(); // size_t Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer); - void ConvertColorToLinearInks(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion); + void ConvertColorToLinearInks(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, + int &GamutRegion, bool &InGamut); void ConvertVolumeToRGBDisplay(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion); size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer); @@ -29,9 +60,12 @@ namespace Tango void ConvertToLinearInks(VectorXd InkIn, VectorXd &InkOut); void VolumeToNLInkP(VectorXd Volume, VectorXd &NLInkP); void NLInkPToVolume(VectorXd NLInkP, VectorXd &Volume); + void SetMaxNLperCM(double maxNlPerCM, int i); private: ColorTransf *m_B2ATransform; ColorTransf *m_A2BTransform; + GBD *m_GBD; + ColorConvert *m_Conv02; C_RGB_XYZ_Lab m_whitepointLab; C_RGB_XYZ_Lab m_whitepointXYZ_Strip; C_RGB_XYZ_Lab m_whitepointXYZ_CT; @@ -39,13 +73,13 @@ namespace Tango int m_nB2AnSepOut; int m_nA2BnSepIn; int m_nA2BnSepOut; + bool m_AdaptWP; CalibData *m_CalibCurves; size_t *m_CalibDatasize; int m_nInks; - VectorXd m_maxNlPerCM; int m_nVolumes; C_RGB_XYZ_Lab m_WP; - + VectorXd m_maxNlPerCM; void SetnB2AnSepIn(int nB2AnSepIn) { m_nB2AnSepIn = nB2AnSepIn; }; void SetnB2AnSepOut(int nB2AnSepOut) { m_nB2AnSepOut = nB2AnSepOut; }; void SetnA2BnSepIn(int nA2BnSepIn) { m_nA2BnSepIn = nA2BnSepIn; }; @@ -54,7 +88,6 @@ namespace Tango void readCalibrationTables(ConversionInput* conversionInput); void SetCalibData(CalibrationData* calibrationData, int i, CalibData *tmpCurve); void SetNumberofInks(int nInks) { m_nInks = nInks; }; - void SetMaxNLperCM(double maxNlPerCM, int i); void SetNumberOfVolumes(int nVol) { m_nVolumes = nVol; }; void SetNumberOfInks(int nInks) { m_nInks = nInks; }; void fillRGB(OutputCoordinates *outputCoords, VectorXd RGBOut); @@ -67,7 +100,15 @@ namespace Tango int CountNumberofInks(ConversionInput* conversionInput); double *VectorToDouble(VectorXd Vec); VectorXd DoubleToVector(double *doub, int nSize); - + void CompareWhitePoints(); + bool IsInGamut(double *InLab, SURROUND sur); + CT_Header read_header(ConversionInput* conversionInput, int &bytesread); + void read_lut_type(int offset, int data_size, ColorTransf *Transf, ConversionInput* conversionInput); + void read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *xyz, ConversionInput* conversionInput); + void read_text_type(int offset, int data_size, std::string *textstr, + ConversionInput* conversionInput); + void read_text_description_type(int offset, int data_size, std::string textdescstr, + ConversionInput* conversionInput); }; } } diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj b/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj index 7fccc42b1..6aacdb863 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj @@ -176,8 +176,10 @@ + + @@ -197,8 +199,10 @@ + + diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj.filters b/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj.filters index bcab0f096..38b89c2f3 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj.filters +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Tango.ColorLib.vcxproj.filters @@ -93,6 +93,12 @@ Header Files + + Utils + + + Utils + @@ -152,5 +158,11 @@ Utils + + Utils + + + Utils + \ No newline at end of file diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.cpp b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.cpp index 211dd0a34..25f035e0c 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.cpp +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.cpp @@ -86,6 +86,30 @@ void C_RGB_XYZ_Lab::Clamp(C_RGB_XYZ_Lab &low, C_RGB_XYZ_Lab &high) m_z = std::min(std::max(m_z, low.Get_z()), high.Get_z());; } +C_RGB_XYZ_Lab C_RGB_XYZ_Lab::labuint16_to_labdouble(uint16_t * LabShort) +{ + double tmp[3]; + C_RGB_XYZ_Lab out; + tmp[0] = (double(LabShort[0]) * (100.0 + (25500.0 / 65280.0))) / 65535.0; + tmp[1] = ((double(LabShort[1]) * (255.0 + (255.0 / 256.0))) / 65535.0) - 128.0; + tmp[2] = ((double(LabShort[2]) * (255.0 + (255.0 / 256.0))) / 65535.0) - 128.0; + out.Set(tmp[0], tmp[1], tmp[2]); + return (out); +} + +C_RGB_XYZ_Lab C_RGB_XYZ_Lab::labdouble_to_labuint16(double* LabDouble) +{ +//Do the scale and offset and cast to uint16 + C_RGB_XYZ_Lab out; + double tmp[3]; +tmp[0]= round(65535 * LabDouble[0] / (100 + (25500 / 65280))); +tmp[1] = round(65535 * ((128 + LabDouble[1]) / (255 + (255 / 256)))); +tmp[2] = round(65535 * ((128 + LabDouble[2]) / (255 + (255 / 256)))); +for (int i = 0; i < 3; ++i) + tmp[0] = std::min(std::max(tmp[0], 0.0), 65535.0); +out.Set((uint16_t)tmp[0], (uint16_t)tmp[1], (uint16_t)tmp[2]); +return (out); +} // add to existing value (rgb += rhs) C_RGB_XYZ_Lab &C_RGB_XYZ_Lab::operator += (C_RGB_XYZ_Lab &rhs) @@ -141,3 +165,5 @@ bool operator != (C_RGB_XYZ_Lab &lhs, C_RGB_XYZ_Lab &rhs) } + + diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.h b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.h index 55062fc6a..875adc84c 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.h +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/C_RGB_XYZ_Lab.h @@ -28,7 +28,8 @@ class C_RGB_XYZ_Lab double Get_z() { return (m_z); }; // Clamp the elements to the range [low, high] void Clamp (C_RGB_XYZ_Lab &low, C_RGB_XYZ_Lab &high); - + C_RGB_XYZ_Lab labuint16_to_labdouble(uint16_t *LabShort); + C_RGB_XYZ_Lab labdouble_to_labuint16(double* LabDouble); C_RGB_XYZ_Lab &operator += (C_RGB_XYZ_Lab &rhs); C_RGB_XYZ_Lab &operator -= (C_RGB_XYZ_Lab &rhs); C_RGB_XYZ_Lab &operator *= (C_RGB_XYZ_Lab &rhs); diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.cpp b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.cpp index 1e4b60950..6014df298 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.cpp +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.cpp @@ -22,6 +22,8 @@ static const C_RGB_XYZ_Lab ZeroVal(0.0, 0.0, 0.0); static bool m_MatricesInitialized = false; static MatrixXd m_RGBtoXYZMatrix = MatrixXd(nXYZ, nRGB); static MatrixXd m_XYZtoRGBMatrix = MatrixXd(nRGB, nXYZ); +C_RGB_XYZ_Lab LowLab(0.0, -128.0, -128.0); +C_RGB_XYZ_Lab HighLab(100.0, 127.0, 127.0); // Default Constructor (defaults to reference white of D50, 2 degree) ColorConvert::ColorConvert (void) @@ -122,6 +124,8 @@ ColorConvert::ColorConvert(C_RGB_XYZ_Lab DDest, C_RGB_XYZ_Lab DSource) ColorConvert::ColorConvert(Illum DDest, Illum DSource, double Y_b, double L_A, SURROUND sur, CAM02CS CS) { + SetCAM02CS(CS); + SetSurround(sur); switch (DDest) { case D50: @@ -160,8 +164,10 @@ ColorConvert::ColorConvert(const ColorConvert &rhs) : m_InvReferenceWhite(rhs.m_InvReferenceWhite), m_SourceWhite(rhs.m_SourceWhite), m_BradfordMatrix(rhs.m_BradfordMatrix), - m_JabParams (rhs.m_JabParams), - m_ParamsCIECam02(rhs.m_ParamsCIECam02) + m_JabParams(rhs.m_JabParams), + m_ParamsCIECam02(rhs.m_ParamsCIECam02), + m_CS(rhs.m_CS), + m_sur(rhs.m_sur) { } @@ -377,8 +383,8 @@ const C_RGB_XYZ_Lab &ColorConvert::GetReferenceWhite(void) const C_RGB_XYZ_Lab ColorConvert::RGBtoLab(C_RGB_XYZ_Lab& RGBVal) { C_RGB_XYZ_Lab DataXYZ; - C_RGB_XYZ_Lab LowLab(0.0, -128.0, -128.0); - C_RGB_XYZ_Lab HighLab(100.0, 127.0, 127.0); + //C_RGB_XYZ_Lab LowLab(0.0, -128.0, -128.0); + // C_RGB_XYZ_Lab HighLab(100.0, 127.0, 127.0); DataXYZ = RGBtoXYZ(RGBVal); C_RGB_XYZ_Lab DataLab; @@ -388,7 +394,7 @@ const C_RGB_XYZ_Lab &ColorConvert::GetReferenceWhite(void) const } - double *ColorConvert::ToAbsoluteLab(double *LabIn, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite) + double *ColorConvert::ChangeWP(double *LabIn, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite) { SetReferenceWhite(SourceWhite); C_RGB_XYZ_Lab Lab; @@ -397,15 +403,21 @@ const C_RGB_XYZ_Lab &ColorConvert::GetReferenceWhite(void) const SetReferenceWhite(DestWhite); C_RGB_XYZ_Lab LabOut1; LabOut1 = XYZToLab(XYZ); - SetReferenceWhite(SourceWhite); - C_RGB_XYZ_Lab LabOut2; - LabOut1 = XYZToLab(XYZ); + LabOut1.Clamp(LowLab, HighLab); + double *LabD = new double[3]; + LabD[0] = LabOut1.Get_x(); + LabD[1] = LabOut1.Get_y(); + LabD[2] = LabOut1.Get_z(); + // SetReferenceWhite(SourceWhite); +/* C_RGB_XYZ_Lab LabOut2; + LabOut2 = XYZToLab(XYZ); double *LabD = new double[3]; double x = 100 - Lab.Get_x(); double f = 100.0 / (100.0 + pow(x, 3) / 100.0); LabD[0] = f*LabOut1.Get_x() + (1-f) *LabOut2.Get_x(); LabD[1] = f*LabOut1.Get_y() + (1 - f) *LabOut2.Get_y(); LabD[2] = f*LabOut1.Get_z() + (1 - f) *LabOut2.Get_z(); + return(LabD); */ return(LabD); } @@ -1004,7 +1016,18 @@ void ColorConvert::Jab_parameters(CAM02CS CS) Jab = JMh_2_Jab(JMh); return(Jab); } - + + double *ColorConvert::LabToJab(double* pColor, SURROUND sur) + { + VectorXd Vec(3); + for (int i = 0; i < 3; ++i) + Vec(i) = pColor[i]; + VectorXd OutVec = LabToJab(Vec, sur); + double Out[3]; + for (int i = 0; i < 3; ++i) + Out[i]= OutVec(i); + return(Out); + } VectorXd ColorConvert::LabToJab(VectorXd pColor, SURROUND sur) { C_RGB_XYZ_Lab Color(pColor); diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.h b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.h index 5c7b125f8..f51ebc7f4 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.h +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorConvert.h @@ -75,7 +75,7 @@ class ColorConvert C_RGB_XYZ_Lab RGBtoXYZ(C_RGB_XYZ_Lab & rgbVal); C_RGB_XYZ_Lab XYZtoRGB(C_RGB_XYZ_Lab& xyzVal); double *LabtoRGB(double*Lab); - double *ToAbsoluteLab(double *LabIn, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite); + double *ChangeWP(double *LabIn, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite); C_RGB_XYZ_Lab LabtoRGB(C_RGB_XYZ_Lab& LabVal); double *RGBtoLab(double*RGB); C_RGB_XYZ_Lab RGBtoLab(C_RGB_XYZ_Lab& RGB); @@ -86,9 +86,13 @@ class ColorConvert VectorXd XYZtoJab(VectorXd pColor, SURROUND sur); VectorXd Jab_2_XYZ(VectorXd Jab, CAM02CS CS); VectorXd LabToJab(VectorXd pColor, SURROUND sur); + double *LabToJab(double* pColor, SURROUND sur); void InitCiecamParams(double Y_b, double L_A, SURROUND sur, CAM02CS CS); void dEcmc(VectorXd refX, VectorXd samX, double &dE); void SymmetricaldECMC(VectorXd refX, VectorXd samX, double &dECMC); + CAM02CS getCAM02CS() { return(m_CS); }; + SURROUND getSurround() { return(m_sur); }; + protected: private: @@ -107,10 +111,14 @@ class ColorConvert C_RGB_XYZ_Lab m_ReferenceWhite; // Reference white C_RGB_XYZ_Lab m_InvReferenceWhite; // 1.0 / Reference white C_RGB_XYZ_Lab m_SourceWhite; // 1.0 / Reference white + CAM02CS m_CS; + SURROUND m_sur; MatrixXd m_BradfordMatrix; double GammaExpand_sRGB(double nonlinear); double GammaCompress_sRGB(double linear); void SetCIECamWhitePoint(C_RGB_XYZ_Lab ReferenceWhite); + void SetCAM02CS(CAM02CS CS) { m_CS = CS; }; + void SetSurround(SURROUND sur) { m_sur = sur; }; }; diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorTransf.cpp b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorTransf.cpp index 63958cf2b..51d0dbd2d 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorTransf.cpp +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/ColorTransf.cpp @@ -3,8 +3,11 @@ #endif #include "ColorTransf.h" +#include "C_RGB_XYZ_Lab.h" #include #include +#include "NumConversions.h" + using namespace std; #define LFactor 100 #define abFactor 255 @@ -37,94 +40,97 @@ using namespace std; } } - void ColorTransf::InitData(unsigned char *colorTransformBuffer, long colorTransformFileSize) + void ColorTransf::InitData(unsigned char *colorTransformBuffer, long colorTransformSize) { - long lSize, lSizeHalf; + /* the whole file is now loaded in the memory buffer. */ + /*Parse data*/ + /*1st Element: Number of Separations In + 2nd Element: Number of Separations Out + 3rd Element: Number of gridpoints + 4th Element: Most Significant bits shift + 5th Element: Number of Gamut Regions N (number between 0 and 3) + */ + //long lSize, lSizeHalf; // obtain file size: - lSize = colorTransformFileSize; - lSizeHalf = lSize / 2; + int lSize = colorTransformSize; + //lSizeHalf = lSize / 2; // allocate memory to contain the whole file: unsigned char *buffer = colorTransformBuffer; if (buffer == NULL) { throw std::exception("Memory Error, ColorTransf::InitData"); } - //convert to usigned short - unsigned short *tmpBuffer = new unsigned short[lSizeHalf]; - for (int i=0; i> (tmp); - if (tmpBuffer[2] != (checkMSB + 1)) + // Skip past reserved padding bytes + bytesread += 4; + + uint8_t num_input_channels = buffer[ bytesread]; + SetSeparationsIn((int)num_input_channels); //Numer of Separations In + bytesread += 1; + uint8_t num_output_channels = buffer[ bytesread]; + SetSeparationsOut((int)num_output_channels); //Numer of Separations Out + bytesread += 1; + uint8_t num_clut_grid_points = buffer[ bytesread]; + SetNGridpoints((int)num_clut_grid_points); //Number of Gridpoints + bytesread += 1; + uint8_t num_Sh4MSB = buffer[ bytesread]; + bytesread += 1; + unsigned short checkMSB = 256 >> (num_Sh4MSB); + if (num_clut_grid_points != (checkMSB + 1)) { throw std::exception("Wrong Number of MSB's, ColorTransf::InitData"); } else - SetMSBShift((int)tmp); //Number of MSB's - unsigned short tmp1; - tmp1 = tmpBuffer[4]; - if (tmp1 > 0) - SetNGamutRegions((int)tmp1); //Number of Gamut Regions + SetMSBShift((int)num_Sh4MSB); //Number of MSB's + uint8_t GReg = buffer[ bytesread]; + bytesread += 1; + if (GReg > 0) + SetNGamutRegions((int)GReg); //Number of Gamut Regions else { throw std::exception("No Gamut Regions in table header, ColorTransf::InitData"); - } - double *GamutLimitsNlperCM = new double[(int)m_NGamutRegions]; - for (int i = 0; i < (int)m_NGamutRegions; ++i) - { - tmp1 = tmpBuffer[5 + i]; - GamutLimitsNlperCM[i] = (double)tmp1; - } - SetGamutLimitsNlperCM(GamutLimitsNlperCM); - /*Sanity check*/ - /*Check size parameters*/ - long tmpSize = (int)(pow((double)m_nGridPoints, (int)m_SeparationsIn))* m_SeparationsOut; - int totHeader = 5 + m_NGamutRegions; - if (tmpSize != lSizeHalf - totHeader) - { - throw std::exception("Wrong Parameters in header's table, ColorTransf::InitData"); } + int clut_size = (int)pow(double(num_clut_grid_points), num_input_channels); + // lut8Type and lut16Type - int lsizeH4 = lSizeHalf - totHeader; + //convert to usigned short + + int lsizeH4 =( lSize - bytesread + 1)/2; +// int lsizeH4 = lSizeHalf - totHeader; m_DataBuffer = new unsigned short[lsizeH4]; int lSizeperSep = lsizeH4 / m_SeparationsOut; - int indReshape = 0; + int indR = 0; for (int i = 0; i < lSizeperSep; ++i) { for (int j = 0; j < m_SeparationsOut; ++j) { - m_DataBuffer[indReshape] = tmpBuffer[j*lSizeperSep + i + totHeader]; - indReshape++; + m_DataBuffer[indR] = Conv.ByteToShort(buffer, bytesread); + bytesread += 2; + indR++; } } // terminate reading data file m_InterpColor.InitData(m_DataBuffer, m_SeparationsIn, m_SeparationsOut, m_nGridPoints, m_MSBShift); - if (tmpBuffer != NULL) - { - delete[] tmpBuffer; - tmpBuffer = NULL; - } - return; } @@ -137,33 +143,34 @@ void ColorTransf::SetGamutLimitsNlperCM(double *GamutLimitsNlperCM) void ColorTransf::evalLab2InkP(double *ColorIn, double *&ColorOut, int &GamutRegion) { - double *tmpColorOut = new double[m_SeparationsOut]; - + //double *tmpColorOut = new double[m_SeparationsOut]; + C_RGB_XYZ_Lab tmpColorOut; + tmpColorOut = tmpColorOut.labdouble_to_labuint16(ColorIn); /*Convert ColorIn to uint16 */ uint16_t *iColorIn = new uint16_t[m_SeparationsIn]; - iColorIn[0] = uint16_t(double(ColorIn[0] /LFactor)*Uint16Factor); - iColorIn[1] = uint16_t(double((ColorIn[1] + abOffset) / abFactor)*Uint16Factor); - iColorIn[2] = uint16_t(double((ColorIn[2] + abOffset) / abFactor)*Uint16Factor); - + iColorIn[0] = uint16_t(tmpColorOut.Get_x()); + iColorIn[1] = uint16_t(tmpColorOut.Get_y()); + iColorIn[2] = uint16_t(tmpColorOut.Get_z()); + double *tmpColor = new double[m_SeparationsIn]; if (m_SeparationsIn == 3) - m_InterpColor.ColorMap3(iColorIn, tmpColorOut); + m_InterpColor.ColorMap3(iColorIn, tmpColor); else if (m_SeparationsIn == 4) - m_InterpColor.ColorMap4(iColorIn, tmpColorOut); + m_InterpColor.ColorMap4(iColorIn, tmpColor); else throw std::exception("Unsupported Number of Separations in ColorTransf::evalLab2Ink"); //tmpColorOut between 0and 255 //normalize to [0-100] for (int i = 0; i < m_SeparationsOut; ++i) - ColorOut[i] = tmpColorOut[i] * InkFactor/ Uint16Factor; + ColorOut[i] = tmpColor[i] * InkFactor/ Uint16Factor; GamutRegion = 0; if(iColorIn !=NULL) { delete[] iColorIn; iColorIn = NULL; } - if (tmpColorOut != NULL) + if (tmpColor != NULL) { - delete[] tmpColorOut; + delete[] tmpColor; tmpColorOut = NULL; } @@ -185,9 +192,14 @@ void ColorTransf::evalInkP2Lab(double *ColorIn, double *&ColorOut, int &GamutReg else throw std::exception("Unsupported Number of Separations in ColorTransf::evalInkP2Lab"); //Normalize to Lab Space - ColorOut[0] = (double)tmpColorOut[0] * LFactor / Uint16Factor; - ColorOut[1] = ((double)tmpColorOut[1] * abFactor) / Uint16Factor - abOffset; - ColorOut[2] = ((double)tmpColorOut[2] * abFactor) / Uint16Factor - abOffset; + C_RGB_XYZ_Lab tmpLabOut; + uint16_t *UInt16ColorOut = new uint16_t[m_SeparationsIn]; + for (int i = 0; i < m_SeparationsIn; ++i) + UInt16ColorOut[i] = (uint16_t)tmpColorOut[i]; + tmpLabOut = tmpLabOut.labuint16_to_labdouble(UInt16ColorOut); + ColorOut[0] = tmpLabOut.Get_x(); + ColorOut[1] = tmpLabOut.Get_y(); + ColorOut[2] = tmpLabOut.Get_z(); GamutRegion = 0; if (iColorIn != NULL) { @@ -199,9 +211,15 @@ void ColorTransf::evalInkP2Lab(double *ColorIn, double *&ColorOut, int &GamutReg delete[] tmpColorOut; tmpColorOut = NULL; } + if (UInt16ColorOut != NULL) + { + delete[] UInt16ColorOut; + UInt16ColorOut = NULL; + } return; } + /* __declspec(dllexport) int ColorTransf::evalCMY2RGB(double *ColorIn, double *ColorOut) { //Assumption: ColorIn is in the interval [0,100] diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.cpp b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.cpp new file mode 100644 index 000000000..0a21d5f25 --- /dev/null +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.cpp @@ -0,0 +1,311 @@ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "GBD.h" +#include +#include +#include "NumConversions.h" +#include "C_RGB_XYZ_Lab.h" + +using namespace std; + +#define eps 1.0e-05 +#define dE_Tol 2.0 +#define LargeNumber 1.0e+10 + +typedef enum { + TwoSided, + OneSided +}RTRI; + +typedef enum { + Line, + Ray, + Segment +}LineType; + +GBD::GBD() : + m_prec(0), m_nPCSChan(0), + m_nDevChan(0), m_CenterLab(0), m_nVertices(0), m_Vertices(NULL) +{ + +} + +GBD::~GBD() +{ +} + +void GBD::TriangleRayIntersection(double *origin, double *direction, bool intersect, double *xCoor) +{ + int i, j; + + RTRI rtri = TwoSided; + LineType lt = Segment; + bool ok = false; + double border = eps; + double t = LargeNumber; + double u = t; + double v = t; + double *edge1 = new double[3]; + double *edge2 = new double[3]; + double *tvec = new double[3]; // vector from vert0 to ray origin + double *pvec = new double[3]; + double *qvec = new double[3]; + double det = 0; + bool angleOK = false; + for (i = 0; i < m_nTriangles; ++i) + { + for (j = 0; j < 3; ++j) + { + edge1[j] = m_vert1[i][j] - m_vert0[i][j]; + edge2[j] = m_vert2[i][j] - m_vert0[i][j]; + tvec[j] = origin[j] - m_vert0[i][j]; + } + crossProduct(direction, edge2, pvec); + det = dotProduct(edge1, pvec); + switch (rtri) + { + case TwoSided: + if (std::abs(det) > eps) + angleOK = true; + break; + case OneSided: + if (det > eps) + angleOK = true; + break; + default: + throw std::exception("Wrong Parameterin Ray-TriageIntersetion"); + } + if (std::abs(det) > eps) + { + u = dotProduct(tvec, pvec) / det; + crossProduct(tvec, edge1, qvec); + v = dotProduct(direction, qvec) / det; + t = dotProduct(edge2, qvec) / det; + ok = (angleOK && (u >= -eps) && (v >= -eps) && ((u + v) <= 1 + eps)); + } + else + ok = false; + + switch (lt) + { + case Line: + intersect = ok; + break; + case Ray: + intersect = ok && (t >= -eps); + break; + case Segment: + intersect = ok && (t >= -eps) && (t <= 1 + eps); + break; + default: + throw std::exception("Wrong Line Type"); + break; + } + if (intersect) + { + for (j = 0; j < 3; ++j) + xCoor[j] = m_vert0[i][j] + edge1[j] * u + edge2[j] * v; + if (edge1 != NULL) + { + delete[]edge1; + edge1 = NULL; + } + if (edge2 != NULL) + { + delete[]edge2; + edge2 = NULL; + } + if (tvec != NULL) + { + delete[]tvec; + tvec = NULL; + } + if (qvec != NULL) + { + delete[]qvec; + qvec = NULL; + } + if (pvec != NULL) + { + delete[]pvec; + pvec = NULL; + } + return; + } + } + if (edge1 != NULL) + { + delete[]edge1; + edge1 = NULL; + } + if (edge2 != NULL) + { + delete[]edge2; + edge2 = NULL; + } + if (tvec != NULL) + { + delete[]tvec; + tvec = NULL; + } + if (qvec != NULL) + { + delete[]qvec; + qvec = NULL; + } + if (pvec != NULL) + { + delete[]pvec; + pvec = NULL; + } + return; +} + +void GBD::InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize) +{ + // 0-3 prec + //4-7 reserved, must be 0 + // 8-9 number of vertices, uint16 + // 10-11 number of triangles, uint16 + // 12 number of PCS Channels, uint8 + // 13 number of device channels (0, no device data) + // prec 2 (16bit) + // 14-n triangle vertices arranged as vert0 -> vert1->vert2 + // each vert is a matrix of size (number of vertices)x3 + // Gamut is stored in Ciecam02 color space + // prec 1 + // 14-n CLUT values, uint8 + + if (colorTransformFileSize < 32) + { + throw std::exception("Init GB, invalid size"); + } + + // Check for signature + unsigned char *buffer = colorTransformBuffer; + if (buffer == NULL) + { + throw std::exception("Memory Error, ColorTransf::InitData"); + } + + int i, j; + NumConversions Conv; + int bytesread = 0; + int tmpB = Conv.ByteToInt(buffer, 0); + bytesread += 4; + char *tmpC; + int n = 0; + tmpC = Conv.getchar(tmpB, n); + char *tableType = new char[n + 1]; + strncpy_s(tableType, n + 1, tmpC, n); + int TablePrecision; + if (strncmp(tableType, "prc1", n) == 0) + TablePrecision = 1; + else if (strncmp(tableType, "prc2", n) == 0) + TablePrecision = 2; + else + { + throw std::exception("Wrong precision in gbd tables"); + return; + } + // Skip past reserved padding bytes + bytesread += 4; + uint16_t num_gbd_points = Conv.ByteToShort(buffer, bytesread); + bytesread += 2; + SetNVertices((int)num_gbd_points); + uint16_t num_triangles = Conv.ByteToShort(buffer, bytesread); + bytesread += 2; + SetNTriangles((int)num_triangles); + uint8_t num_PCSChan = buffer[bytesread]; + bytesread += 1; + SetNPCS_Channels((int)num_PCSChan); + bytesread += 1; + uint8_t num_DevChan = buffer[bytesread]; + SetNDev_Channels((int)num_DevChan); + uint16_t ILab[3]; + for (j = 0; j < 3; ++j) + { + ILab[j] = (uint16_t)Conv.ByteToInt(buffer, bytesread); + bytesread += 4; + } + C_RGB_XYZ_Lab tmpCenter; + m_CenterLab = tmpCenter.labuint16_to_labdouble(ILab); + + // lut8Type and lut16Type + int remsize = colorTransformFileSize - bytesread; + int Bsize = (int)((int)(num_gbd_points) * (int)num_PCSChan); + if (remsize != Bsize * (int)TablePrecision) + { + throw std::exception("GBD size missmatch"); + return; + } + m_vert0 = new double*[m_nTriangles]; + m_vert1 = new double*[m_nTriangles]; + m_vert2 = new double*[m_nTriangles]; + uint16_t tmp[3]; + C_RGB_XYZ_Lab tmp1; + for (i = 0; i < m_nTriangles; ++i) + { + m_vert0[i] = new double[m_nPCSChan]; + for (j = 0; j < m_nPCSChan; ++j) + { + tmp[j] = Conv.ByteToShort(buffer, bytesread); + bytesread += 2; + } + tmp1 = tmp1.labuint16_to_labdouble(tmp); + m_vert0[i][0] = tmp1.Get_x(); + m_vert0[i][1] = tmp1.Get_y(); + m_vert0[i][2] = tmp1.Get_z(); + } + for (i = 0; i < m_nTriangles; ++i) + { + m_vert1[i] = new double[m_nPCSChan]; + for (j = 0; j < m_nPCSChan; ++j) + { + tmp[j] = Conv.ByteToShort(buffer, bytesread); + bytesread += 2; + } + tmp1 = tmp1.labuint16_to_labdouble(tmp); + m_vert1[i][0] = tmp1.Get_x(); + m_vert1[i][1] = tmp1.Get_y(); + m_vert1[i][2] = tmp1.Get_z(); + } + for (i = 0; i < m_nTriangles; ++i) + { + m_vert2[i] = new double[m_nPCSChan]; + for (j = 0; j < m_nPCSChan; ++j) + { + tmp[j] = Conv.ByteToShort(buffer, bytesread); + bytesread += 2; + } + tmp1 = tmp1.labuint16_to_labdouble(tmp); + m_vert2[i][0] = tmp1.Get_x(); + m_vert2[i][1] = tmp1.Get_y(); + m_vert2[i][2] = tmp1.Get_z(); + } +} + + +// dot product of two vectors. +double GBD::dotProduct(double *vect_A, double*vect_B) +{ + int product = 0; + // Loop for calculate dot product + int n = sizeof(vect_A); + for (int i = 0; i < n; i++) + product = product + vect_A[i] * vect_B[i]; + return (product); +} + + +// cross product of two vectors +void GBD::crossProduct(double *vect_A, double* vect_B,double *cross_P) +{ + cross_P[0] = vect_A[1] * vect_B[2] - vect_A[2] * vect_B[1]; + cross_P[1] = vect_A[0] * vect_B[2] - vect_A[2] * vect_B[0]; + cross_P[2] = vect_A[0] * vect_B[1] - vect_A[1] * vect_B[0]; + return; +} + diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.h b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.h new file mode 100644 index 000000000..6ef4d3a51 --- /dev/null +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/GBD.h @@ -0,0 +1,38 @@ +#ifndef _GBD_H_ +#define _GBD_H_ + +#include +#include "C_RGB_XYZ_Lab.h" + +class GBD { +public: + GBD(); + ~GBD(); + int GetNVertices() { return(m_nVertices); }; + int GetNPCS_Channels() { return(m_nPCSChan); }; + int GetDev_Channels() { return(m_nDevChan); }; + int GetNTriangles() { return(m_nTriangles); }; + C_RGB_XYZ_Lab getCenter(){ return(m_CenterLab);}; + void InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize); + void TriangleRayIntersection(double *origin, double *direction, bool intersect, double *xCoor); +private: + int m_prec; + int m_nDevChan; + int m_nPCSChan; + int m_nVertices; + int m_nTriangles; + C_RGB_XYZ_Lab m_CenterLab; + C_RGB_XYZ_Lab *m_Vertices; + double **m_vert0; + double **m_vert1; + double **m_vert2; + void SetNVertices(int nVertices) { m_nVertices = nVertices; }; + void SetNPCS_Channels(int nPCSChan) { m_nPCSChan = nPCSChan; }; + void SetNDev_Channels(int nDevChan) { m_nDevChan = nDevChan; }; + void SetNTriangles(int nTriangles) { m_nTriangles = nTriangles; }; + //void SetCenter( C_RGB_XYZ_Lab CenterLab); + double dotProduct(double *vect_A, double*vect_B); + void crossProduct(double *vect_A, double* vect_B, double *cross_P); +}; + +#endif diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/Interp.h b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/Interp.h index 6c1128b8a..cf733d45e 100644 --- a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/Interp.h +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/Interp.h @@ -15,6 +15,6 @@ class Interp int m_length; }; -#endif // __CALIBDATA_H__ +#endif // __INTERP_H__ diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.cpp b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.cpp new file mode 100644 index 000000000..2ec57149e --- /dev/null +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.cpp @@ -0,0 +1,46 @@ +#include "NumConversions.h" +#include +#include +#include +#include +#include + +NumConversions::NumConversions(void) +{ +} + +NumConversions::NumConversions(const NumConversions &rhs) +{ +} + +int NumConversions::ByteToInt(uint8_t *byteN, int start) +{ +int res; +res = (int)((unsigned int)byteN[start] << 24 | + (unsigned int)byteN[start + 1] << 16 | + (unsigned int)byteN[start + 2] << 8 | + (unsigned int)byteN[start + 3]); + return(res); +} + +uint16_t NumConversions::ByteToShort(uint8_t *byteN, int start) +{ +uint16_t res; +res = (uint16_t)((unsigned short)byteN[start] << 8 | + (unsigned short)byteN[start + 1]) ; + return(res); +} + +char* NumConversions::getchar(uint32_t num,int &nlen) +{ + char *getChar; + getChar = (char*)# + nlen = sizeof(getChar); + //reverse order + char *tmp = new char[nlen]; + for (int i = 0; i < nlen; ++i) + { + tmp[i] = getChar[nlen - 1 - i]; + } + return(tmp); +} diff --git a/Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.h b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.h new file mode 100644 index 000000000..b5e9d28e5 --- /dev/null +++ b/Software/Visual_Studio/Native/Tango.ColorLib/Utils/NumConversions.h @@ -0,0 +1,16 @@ +#ifndef __NUMCONVER_H__ +#define __NUMCONVER_H__ +#include +#include + +class NumConversions +{ + public: + NumConversions(void); + NumConversions(const NumConversions &rhs); + int ByteToInt(uint8_t *byteN, int Start); + uint16_t ByteToShort(uint8_t *byteN, int Start); + char* getchar(uint32_t num, int &nlen); + private: +}; +#endif //__NUMCONVERSIONS_H__ \ No newline at end of file diff --git a/Software/Visual_Studio/Native/Tester/Tester.cpp b/Software/Visual_Studio/Native/Tester/Tester.cpp index 2b1659463..584e40e4b 100644 --- a/Software/Visual_Studio/Native/Tester/Tester.cpp +++ b/Software/Visual_Studio/Native/Tester/Tester.cpp @@ -22,16 +22,16 @@ size_t InitData(uint8_t *&input_buffer, long &buffersize, char *ForwardName, cha ConversionInput *conversionInput = (ConversionInput*)malloc(sizeof(ConversionInput)); conversion_input__init(conversionInput);//CONVERSION_INPUT__INIT; //fill conversionInput - conversionInput->colorspace = COLOR_SPACE__Volume; + conversionInput->colorspace = COLOR_SPACE__RGB; conversionInput->has_colorspace = true; conversionInput->has_forwarddata = true; conversionInput->has_inversedata = true; conversionInput->has_threadl = true; conversionInput->has_threada = true; conversionInput->has_threadb = true; - conversionInput->threadl = 92.1815; - conversionInput->threada = 2.2555;; - conversionInput->threadb = -10.9325; + conversionInput->threadl = 90.5055; + conversionInput->threada = 2.8998;; + conversionInput->threadb = -11.4028; conversionInput->segmentlength = 10; uint8_t *buffer = NULL; long lsize; @@ -254,7 +254,8 @@ size_t ReadCalData(char *name, double **&CalData, long &nCalData) int main() { char *ForwardName = new char[256]; - strcpy_s(ForwardName, 256, "..\\..\\..\\ColorData\\CCT\\A2B_Lin.cct"); + strcpy_s(ForwardName, 256, "..\\..\\..\\ColorData\\CCT\\test.cct"); + char *InverseName = new char[256]; strcpy_s(InverseName, 256, "..\\..\\..\\ColorData\\CCT\\B2A_Lin.cct"); diff --git a/Software/Visual_Studio/Native/Tester/Tester.vcxproj b/Software/Visual_Studio/Native/Tester/Tester.vcxproj index 5b967f733..5cbed97c2 100644 --- a/Software/Visual_Studio/Native/Tester/Tester.vcxproj +++ b/Software/Visual_Studio/Native/Tester/Tester.vcxproj @@ -131,6 +131,7 @@ true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\Tango.ColorLib\EigenDir;..\Tango.ColorLib\EigenDir\Eigen;$(ProjectDir)protobuf-c;$(ProjectDir)PMR\ColorLab;..\Tango.ColorLib\Utils;..\Tango.ColorLib;%(AdditionalIncludeDirectories) Console -- cgit v1.3.1