|
23 | 23 | */
|
24 | 24 | #include "Simd/SimdBgrToLab.h"
|
25 | 25 | #include "Simd/SimdBase.h"
|
| 26 | +#include "Simd/SimdMath.h" |
26 | 27 |
|
27 | 28 | namespace Simd
|
28 | 29 | {
|
29 | 30 | namespace Base
|
30 | 31 | {
|
| 32 | + namespace LabV1 |
| 33 | + { |
| 34 | + inline double FromRaw(uint64_t raw) |
| 35 | + { |
| 36 | + return *((double*)&raw); |
| 37 | + } |
| 38 | + |
| 39 | +#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n)) |
| 40 | + const int xyz_shift = 12; |
| 41 | + |
| 42 | + //const double D65[3] = { 0.950456, 1., 1.088754 }; |
| 43 | + const double D65[3] = { FromRaw(0x3fee6a22b3892ee8), |
| 44 | + 1.0 , |
| 45 | + FromRaw(0x3ff16b8950763a19) }; |
| 46 | + |
| 47 | + //static const double sRGB2XYZ_D65[] = |
| 48 | + //{ |
| 49 | + // 0.412453, 0.357580, 0.180423, |
| 50 | + // 0.212671, 0.715160, 0.072169, |
| 51 | + // 0.019334, 0.119193, 0.950227 |
| 52 | + //}; |
| 53 | + |
| 54 | + const double sRGB2XYZ_D65[] = |
| 55 | + { |
| 56 | + FromRaw(0x3fda65a14488c60d), |
| 57 | + FromRaw(0x3fd6e297396d0918), |
| 58 | + FromRaw(0x3fc71819d2391d58), |
| 59 | + FromRaw(0x3fcb38cda6e75ff6), |
| 60 | + FromRaw(0x3fe6e297396d0918), |
| 61 | + FromRaw(0x3fb279aae6c8f755), |
| 62 | + FromRaw(0x3f93cc4ac6cdaf4b), |
| 63 | + FromRaw(0x3fbe836eb4e98138), |
| 64 | + FromRaw(0x3fee68427418d691) |
| 65 | + }; |
| 66 | + |
| 67 | + enum { LAB_CBRT_TAB_SIZE = 1024, GAMMA_TAB_SIZE = 1024 }; |
| 68 | + static const float LabCbrtTabScale = float(LAB_CBRT_TAB_SIZE * 2) / float(3); |
| 69 | + |
| 70 | + static const float GammaTabScale((int)GAMMA_TAB_SIZE); |
| 71 | + |
| 72 | + static uint16_t sRGBGammaTab_b[256]; |
| 73 | + |
| 74 | +#undef lab_shift |
| 75 | +#define lab_shift xyz_shift |
| 76 | +#define gamma_shift 3 |
| 77 | +#define lab_shift2 (lab_shift + gamma_shift) |
| 78 | +#define LAB_CBRT_TAB_SIZE_B (256*3/2*(1<<gamma_shift)) |
| 79 | + static uint16_t LabCbrtTab_b[LAB_CBRT_TAB_SIZE_B]; |
| 80 | + |
| 81 | +//all constants should be presented through integers to keep bit-exactness |
| 82 | + static const double gammaThreshold = double(809) / double(20000); // 0.04045 |
| 83 | + static const double gammaInvThreshold = double(7827) / double(2500000); // 0.0031308 |
| 84 | + static const double gammaLowScale = double(323) / double(25); // 12.92 |
| 85 | + static const double gammaPower = double(12) / double(5); // 2.4 |
| 86 | + static const double gammaXshift = double(11) / double(200); // 0.055 |
| 87 | + |
| 88 | + static const float lthresh = float(216) / float(24389); // 0.008856f = (6/29)^3 |
| 89 | + static const float lscale = float(841) / float(108); // 7.787f = (29/3)^3/(29*4) |
| 90 | + static const float lbias = float(16) / float(116); |
| 91 | + //static const softfloat f255(255); |
| 92 | + |
| 93 | + |
| 94 | + static inline float applyGamma(float x) |
| 95 | + { |
| 96 | + //return x <= 0.04045f ? x*(1.f/12.92f) : (float)std::pow((double)(x + 0.055)*(1./1.055), 2.4); |
| 97 | + |
| 98 | + double xd = x; |
| 99 | + return (xd <= gammaThreshold ? |
| 100 | + xd / gammaLowScale : |
| 101 | + pow((xd + gammaXshift) / (1.0 + gammaXshift), gammaPower)); |
| 102 | + } |
| 103 | + |
| 104 | + static void initLabTabs() |
| 105 | + { |
| 106 | + static bool initialized = false; |
| 107 | + if (!initialized) |
| 108 | + { |
| 109 | + float scale = 1.0f / float(GammaTabScale); |
| 110 | + static const float intScale(255 * (1 << gamma_shift)); |
| 111 | + for (int i = 0; i < 256; i++) |
| 112 | + { |
| 113 | + float x = float(i) / 255.0f; |
| 114 | + sRGBGammaTab_b[i] = (uint16_t)(Round(intScale * applyGamma(x))); |
| 115 | + } |
| 116 | + |
| 117 | + static const float cbTabScale(1.0 / (255.0 * (1 << gamma_shift))); |
| 118 | + static const float lshift2(1 << lab_shift2); |
| 119 | + for (int i = 0; i < LAB_CBRT_TAB_SIZE_B; i++) |
| 120 | + { |
| 121 | + float x = cbTabScale * float(i); |
| 122 | + LabCbrtTab_b[i] = (uint16_t)(Round(lshift2 * (x < lthresh ? (x * lscale + lbias) : cbrt(x)))); |
| 123 | + } |
| 124 | + |
| 125 | + initialized = true; |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + struct RGB2Lab_b |
| 130 | + { |
| 131 | + typedef uint8_t channel_type; |
| 132 | + |
| 133 | + RGB2Lab_b(int _srccn, int blueIdx) |
| 134 | + : srccn(_srccn) |
| 135 | + { |
| 136 | + initLabTabs(); |
| 137 | + |
| 138 | + double whitePt[3]; |
| 139 | + for (int i = 0; i < 3; i++) |
| 140 | + whitePt[i] = D65[i]; |
| 141 | + |
| 142 | + const double lshift(1 << lab_shift); |
| 143 | + for (int i = 0; i < 3; i++) |
| 144 | + { |
| 145 | + double c[3]; |
| 146 | + for (int j = 0; j < 3; j++) |
| 147 | + c[j] = sRGB2XYZ_D65[i * 3 + j]; |
| 148 | + coeffs[i * 3 + (blueIdx ^ 2)] = Round(lshift * c[0] / whitePt[i]); |
| 149 | + coeffs[i * 3 + 1] = Round(lshift * c[1] / whitePt[i]); |
| 150 | + coeffs[i * 3 + blueIdx] = Round(lshift * c[2] / whitePt[i]); |
| 151 | + |
| 152 | + assert(coeffs[i * 3] >= 0 && coeffs[i * 3 + 1] >= 0 && coeffs[i * 3 + 2] >= 0 && |
| 153 | + coeffs[i * 3] + coeffs[i * 3 + 1] + coeffs[i * 3 + 2] < 2 * (1 << lab_shift)); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + void operator()(const uint8_t* src, uint8_t* dst, int n) const |
| 158 | + { |
| 159 | + const int Lscale = (116 * 255 + 50) / 100; |
| 160 | + const int Lshift = -((16 * 255 * (1 << lab_shift2) + 50) / 100); |
| 161 | + const uint16_t* tab = sRGBGammaTab_b; |
| 162 | + int i, scn = srccn; |
| 163 | + int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], |
| 164 | + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], |
| 165 | + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; |
| 166 | + |
| 167 | + for (int i = 0; i < n; i++, src += scn, dst += 3) |
| 168 | + { |
| 169 | + int R = tab[src[0]], G = tab[src[1]], B = tab[src[2]]; |
| 170 | + int fX = LabCbrtTab_b[CV_DESCALE(R * C0 + G * C1 + B * C2, lab_shift)]; |
| 171 | + int fY = LabCbrtTab_b[CV_DESCALE(R * C3 + G * C4 + B * C5, lab_shift)]; |
| 172 | + int fZ = LabCbrtTab_b[CV_DESCALE(R * C6 + G * C7 + B * C8, lab_shift)]; |
| 173 | + |
| 174 | + int L = CV_DESCALE(Lscale * fY + Lshift, lab_shift2); |
| 175 | + int a = CV_DESCALE(500 * (fX - fY) + 128 * (1 << lab_shift2), lab_shift2); |
| 176 | + int b = CV_DESCALE(200 * (fY - fZ) + 128 * (1 << lab_shift2), lab_shift2); |
| 177 | + |
| 178 | + dst[0] = Base::RestrictRange(L); |
| 179 | + dst[1] = Base::RestrictRange(a); |
| 180 | + dst[2] = Base::RestrictRange(b); |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + int srccn; |
| 185 | + int coeffs[9]; |
| 186 | + }; |
| 187 | + } |
| 188 | + |
31 | 189 | void BgrToLab(const uint8_t* bgr, size_t bgrStride, size_t width, size_t height, uint8_t* lab, size_t labStride)
|
32 | 190 | {
|
| 191 | +#if 1 |
| 192 | + LabV1::RGB2Lab_b _lab(3, 0); |
| 193 | + for (size_t row = 0; row < height; ++row) |
| 194 | + { |
| 195 | + const uint8_t* pBgr = bgr + row * bgrStride; |
| 196 | + uint8_t* pLab = lab + row * labStride; |
| 197 | + _lab(pBgr, pLab, width); |
| 198 | + } |
| 199 | + |
| 200 | +#else |
33 | 201 | for (size_t row = 0; row < height; ++row)
|
34 | 202 | {
|
35 | 203 | const uint8_t* pBgr = bgr + row * bgrStride;
|
36 | 204 | uint8_t* pLab = lab + row * labStride;
|
37 | 205 | for (const uint8_t* pBgrEnd = pBgr + width * 3; pBgr < pBgrEnd; pBgr += 3, pLab += 3)
|
38 | 206 | BgrToLab(pBgr[0], pBgr[1], pBgr[2], pLab);
|
39 | 207 | }
|
| 208 | +#endif |
40 | 209 | }
|
41 | 210 | }
|
42 | 211 | }
|
|
0 commit comments