From f7795278335f0bb5d58e8a5915a2e60b80377a0b Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 7 Aug 2020 17:26:22 -0700 Subject: [PATCH] Clip H-C vectorscope according to color profile --- rtengine/improccoordinator.cc | 12 +++- rtengine/improcfun.cc | 124 ++++++++++++++++++++++++++++++++++ rtengine/improcfun.h | 1 + 3 files changed, 135 insertions(+), 2 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index a1648aeb4..82527d530 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1853,6 +1853,13 @@ void ImProcCoordinator::updateVectorscope() constexpr int size = HistogramListener::vectorscope_size; memset(vectorscope, 0, size * size * sizeof(vectorscope[0][0])); + const int lab_img_size = (hListener->vectorscopeType() == 1) ? (x2 - x1) * (y2 - y1) : 0; + float L[lab_img_size], a[lab_img_size], b[lab_img_size]; + if (lab_img_size) { + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L, a, b, params->icm); + } + + int ofs_lab = 0; for (int i = y1; i < y2; i++) { int ofs = (i * pW + x1) * 3; @@ -1875,12 +1882,13 @@ void ImProcCoordinator::updateVectorscope() case 1: { // CH - const int col = (size / 96000.0) * nprevl->a[i][j] + size / 2; - const int row = (size / 96000.0) * nprevl->b[i][j] + size / 2; + const int col = (size / 96000.0) * a[ofs_lab] + size / 2; + const int row = (size / 96000.0) * b[ofs_lab] + size / 2; if (col >= 0 && col < size && row >= 0 && row < size) { vectorscope[row][col]++; } + ofs_lab++; break; } } diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 6051b6b0b..7e13fd214 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5716,6 +5716,130 @@ void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib:: } } +void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings) const +{ // Adapted from ImProcFunctions::lab2rgb + const int src_width = src.getWidth(); + const int src_height = src.getHeight(); + + if (x < 0) { + x = 0; + } + + if (y < 0) { + y = 0; + } + + if (x + w > src_width) { + w = src_width - x; + } + + if (y + h > src_height) { + h = src_height - y; + } + + Glib::ustring profile; + + bool standard_gamma; + + if (settings->HistogramWorking && consider_histogram_settings) { + profile = icm.workingProfile; + standard_gamma = true; + } else { + profile = icm.outputProfile; + + if (icm.outputProfile.empty() || icm.outputProfile == ColorManagementParams::NoICMString) { + profile = "sRGB"; + } + + standard_gamma = false; + } + + cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(profile); + + if (oprof) { + cmsHPROFILE oprofG = oprof; + + if (standard_gamma) { + oprofG = ICCStore::makeStdGammaProfile(oprof); + } + + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + lcmsMutex->lock(); + cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); + cmsHTRANSFORM hTransform = cmsCreateTransform (oprofG, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); // NOCACHE is important for thread safety + cmsCloseProfile(LabIProf); + lcmsMutex->unlock(); + + // cmsDoTransform is relatively expensive +#ifdef _OPENMP + #pragma omp parallel +#endif + { + AlignedBuffer oBuf(3 * w); + float *outbuffer = oBuf.data; + int condition = y + h; + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int i = y; i < condition; i++) { + const int ix = 3 * (x + i * src_width); + int iy = 0; + float* rL = L + (i - y) * w; + float* ra = a + (i - y) * w; + float* rb = b + (i - y) * w; + + cmsDoTransform (hTransform, src.data + ix, outbuffer, w); + + for (int j = 0; j < w; j++) { + rL[j] = outbuffer[iy++] * 327.68f; + ra[j] = outbuffer[iy++] * 327.68f; + rb[j] = outbuffer[iy++] * 327.68f; + } + } + } // End of parallelization + + cmsDeleteTransform(hTransform); + + if (oprofG != oprof) { + cmsCloseProfile(oprofG); + } + } else { + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(profile); + const float wp[3][3] = { + {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, + {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, + {static_cast(wprof[2][0]), static_cast(wprof[2][1]), static_cast(wprof[2][2])} + }; + + const int x2 = x + w; + const int y2 = y + h; + constexpr float rgb_factor = 65355.f / 255.f; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + + for (int i = y; i < y2; i++) { + int offset = (i - y) * w; + for (int j = x; j < x2; j++) { + float X, Y, Z; + // lab2rgb uses gamma2curve, which is gammatab_srgb. + const auto& igamma = Color::igammatab_srgb; + Color::rgbxyz(igamma[rgb_factor * src.r(i, j)], igamma[rgb_factor * src.g(i, j)], igamma[rgb_factor * src.b(i, j)], X, Y, Z, wp); + Color::XYZ2Lab(X, Y, Z, L[offset], a[offset], b[offset]); + offset++; + } + } + } +} + void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) { TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(workingSpace); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 113667262..48f2cbc92 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -449,6 +449,7 @@ public: void labColorCorrectionRegions(LabImage *lab); Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true); + void rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true) const; Imagefloat* lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); // CieImage *ciec; void workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, cmsHTRANSFORM &transform, bool normalizeIn = true, bool normalizeOut = true, bool keepTransForm = false) const;