ImageHDR.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  1. // This file is part of HDRip.
  2. //
  3. // HDRip is free software: you can redistribute it and/or modify it
  4. // under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // HDRip is distributed in the hope that it will be useful, but
  9. // WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with HDRip. If not, see <https://www.gnu.org/licenses/>.
  15. //
  16. // HDRip project
  17. // Author : Rémi Synave
  18. // Contact : remi.synave@univ-littoral.fr
  19. #include "pch.h"
  20. #include "ImageHDR.hpp"
  21. #include "MT_exposure.hpp"
  22. #include "MT_contrast.hpp"
  23. #include "MT_histogram_regularization.hpp"
  24. #include "MT_lightnessMask.hpp"
  25. #include "MT_saturation.hpp"
  26. #include "MT_colorEditor.hpp"
  27. #include "Conversion.hpp"
  28. #include "YCurve.hpp"
  29. #include "Utils.hpp"
  30. #include <cmath>
  31. #include <thread>
  32. #include <iostream>
  33. #include <vector>
  34. #include <ctime>
  35. #include <cstdlib>
  36. /* Member methods*/
  37. ImageHDR::ImageHDR(float* d, unsigned int w, unsigned int h)
  38. {
  39. width = w;
  40. height = h;
  41. this->min_intensity = d[0];
  42. this->max_intensity = d[0];
  43. data = new float[width * height * 3];
  44. for (unsigned int i = 0; i < width * height * 3; i++) {
  45. data[i] = d[i];
  46. if (this->min_intensity > data[i])
  47. this->min_intensity = data[i];
  48. if (this->max_intensity < data[i])
  49. this->max_intensity = data[i];
  50. }
  51. linear = true;
  52. colorspace = Colorspace::RGB;
  53. }
  54. void ImageHDR::display_pixel(unsigned int i) const
  55. {
  56. if (linear)
  57. std::cout << "LINEAIRE - ";
  58. else
  59. std::cout << "NON LINEAIRE - ";
  60. std::cout << "Pixel : ( " << data[i * 3] << " " << data[i * 3 + 1] << " " << data[i * 3 + 2] << " )" << std::endl;
  61. }
  62. void ImageHDR::display_pixel(unsigned int i, unsigned int j) const
  63. {
  64. display_pixel(j * width + i);
  65. }
  66. /****************************************/
  67. /**************** LINEAR ****************/
  68. /****************************************/
  69. void ImageHDR::linear_to_non_linear()
  70. {
  71. float* non_linear = Conversion::linear_to_non_linear(data, width * height * 3);
  72. delete[](data);
  73. data = non_linear;
  74. }
  75. void ImageHDR::non_linear_to_linear()
  76. {
  77. float* linear = Conversion::non_linear_to_linear(data, width * height * 3);
  78. delete[](data);
  79. data = linear;
  80. }
  81. /****************************************/
  82. /*************** EXPOSURE ***************/
  83. /****************************************/
  84. #ifdef _MT_
  85. void* exposure_MT(void* arg)
  86. {
  87. MT_exposure* a = (MT_exposure*)arg;
  88. float* data = a->data;
  89. for (unsigned int i = 0; i < a->length; i++)
  90. data[i] *= a->coeff;
  91. return arg;
  92. }
  93. void ImageHDR::exposure(const float ev)
  94. {
  95. float coeff = powf(2, ev);
  96. if (!linear)
  97. {
  98. non_linear_to_linear();
  99. linear = true;
  100. }
  101. std::thread tab_t[_MT_];
  102. MT_exposure tab_a[_MT_];
  103. unsigned int id;
  104. unsigned int tab_length = width * height * 3;
  105. unsigned int block_size = tab_length / _MT_;
  106. for (id = 0; id < _MT_; id++) {
  107. tab_a[id].data = data + (id * block_size);
  108. tab_a[id].length = block_size;
  109. tab_a[id].coeff = coeff;
  110. if (id == (_MT_ - 1))
  111. tab_a[id].length = tab_length - ((_MT_ - 1) * block_size);
  112. tab_t[id] = std::thread(exposure_MT, (void*)(tab_a + id));
  113. }
  114. for (id = 0; id < _MT_; id++) {
  115. tab_t[id].join();
  116. }
  117. }
  118. #else
  119. void ImageHDR::exposure(const float ev)
  120. {
  121. float coef = powf(2, ev);
  122. if (!linear)
  123. {
  124. non_linear_to_linear();
  125. linear = true;
  126. }
  127. for (unsigned int i = 0; i < width * height * 3; i++)
  128. data[i] *= coef;
  129. }
  130. #endif
  131. /****************************************/
  132. /*************** CONTRAST ***************/
  133. /****************************************/
  134. #ifdef _MT_
  135. void* contrast_MT(void* arg)
  136. {
  137. MT_contrast* a = (MT_contrast*)arg;
  138. float* data = a->data;
  139. for (unsigned int i = 0; i < a->length; i++)
  140. data[i] = a->coeff * (data[i] - 0.5f) + 0.5f;
  141. return arg;
  142. }
  143. void ImageHDR::contrast(const float c)
  144. {
  145. float max_contrast_factor = 2.0f, scaling_factor = 1.0f, contrast_value = c;
  146. if (contrast_value != 0.0f)
  147. {
  148. if (linear)
  149. {
  150. linear_to_non_linear();
  151. linear = false;
  152. }
  153. contrast_value = contrast_value / 100.0f;
  154. if (contrast_value > 0.0f)
  155. {
  156. scaling_factor = 1 * (1 - contrast_value) + max_contrast_factor * contrast_value;
  157. }
  158. else
  159. {
  160. contrast_value = -contrast_value;
  161. scaling_factor = 1 * (1 - contrast_value) + max_contrast_factor * contrast_value;
  162. scaling_factor = 1 / scaling_factor;
  163. }
  164. }
  165. std::thread tab_t[_MT_];
  166. MT_contrast tab_a[_MT_];
  167. unsigned int id;
  168. unsigned int tab_length = width * height * 3;
  169. unsigned int block_size = tab_length / _MT_;
  170. for (id = 0; id < _MT_; id++)
  171. {
  172. tab_a[id].data = data + (id * block_size);
  173. tab_a[id].length = block_size;
  174. tab_a[id].coeff = scaling_factor;
  175. if (id == (_MT_ - 1))
  176. tab_a[id].length = tab_length - ((_MT_ - 1) * block_size);
  177. tab_t[id] = std::thread(contrast_MT, (void*)(tab_a + id));
  178. }
  179. for (id = 0; id < _MT_; id++) {
  180. tab_t[id].join();
  181. }
  182. }
  183. #else
  184. void ImageHDR::contrast(const float c)
  185. {
  186. float max_contrast_factor = 2.0f, scaling_factor = 1.0f, contrast_value = c;
  187. if (linear)
  188. {
  189. linear_to_non_linear();
  190. linear = false;
  191. }
  192. if (contrast_value != 0.0f)
  193. {
  194. contrast_value = contrast_value / 100.0f;
  195. if (contrast_value > 0.0f)
  196. {
  197. scaling_factor = 1 * (1 - contrast_value) + max_contrast_factor * contrast_value;
  198. }
  199. else
  200. {
  201. contrast_value = -contrast_value;
  202. scaling_factor = 1 * (1 - contrast_value) + max_contrast_factor * contrast_value;
  203. scaling_factor = 1 / scaling_factor;
  204. }
  205. }
  206. for (unsigned int i = 0; i < width * height * 3; i++)
  207. data[i] = scaling_factor * (data[i] - 0.5f) + 0.5f;
  208. }
  209. #endif
  210. /****************************************/
  211. /**************** YCURVE ****************/
  212. /****************************************/
  213. #ifdef _MT_
  214. void* histogram_regularization_MT(void* arg)
  215. {
  216. MT_histogram_regularization* a = (MT_histogram_regularization*)arg;
  217. float* data = a->data;
  218. float* colorDataY = a->colorDataY;
  219. float* colorDataFY = a->colorDataFY;
  220. for (unsigned int i = 0; i < a->length; i++)
  221. {
  222. data[i * 3] = data[i * 3] * colorDataFY[i] / colorDataY[i];
  223. data[i * 3 + 1] = data[i * 3 + 1] * colorDataFY[i] / colorDataY[i];
  224. data[i * 3 + 2] = data[i * 3 + 2] * colorDataFY[i] / colorDataY[i];
  225. }
  226. return arg;
  227. }
  228. void ImageHDR::ycurve_histogram_regularization(float* colorDataY, float* colorDataFY)
  229. {
  230. float yMin = colorDataY[0];
  231. unsigned int i = 1;
  232. while (yMin == 0)
  233. yMin = colorDataY[i++];
  234. for (unsigned int i = 0; i < width * height; i++)
  235. if (colorDataY[i] != 0 && colorDataY[i] < yMin)
  236. yMin = colorDataY[i];
  237. for (unsigned int i = 0; i < width * height; i++)
  238. if (colorDataY[i] == 0)
  239. colorDataY[i] = yMin;
  240. std::thread tab_t[_MT_];
  241. MT_histogram_regularization tab_a[_MT_];
  242. unsigned int id;
  243. unsigned int tab_length = width * height;
  244. unsigned int block_size = tab_length / _MT_;
  245. for (id = 0; id < _MT_; id++) {
  246. tab_a[id].data = data + (id * block_size * 3);
  247. tab_a[id].length = block_size;
  248. tab_a[id].colorDataY = colorDataY + (id * block_size);
  249. tab_a[id].colorDataFY = colorDataFY + (id * block_size);
  250. if (id == (_MT_ - 1))
  251. tab_a[id].length = tab_length - ((_MT_ - 1) * block_size);
  252. tab_t[id] = std::thread(histogram_regularization_MT, (void*)(tab_a + id));
  253. }
  254. for (id = 0; id < _MT_; id++) {
  255. tab_t[id].join();
  256. }
  257. }
  258. void ImageHDR::yCurve(float s, float b, float m, float w, float h)
  259. {
  260. if (linear)
  261. {
  262. linear_to_non_linear();
  263. linear = false;
  264. }
  265. float* colorDataY = Conversion::sRGB_to_Y_of_XYZ(data, width * height);
  266. YCurve yc(s, b, m, w, h, 200);
  267. Eigen::MatrixXf* points = yc.evalpts(100);
  268. std::cout << *points << std::endl;
  269. Eigen::RowVectorXf y = (*points).col(0) / 100;
  270. Eigen::RowVectorXf fy = (*points).col(1) / 100;
  271. delete(points);
  272. // TODO - try to optimize ?!
  273. // The index of the search method in utils.cpp could be calculated or determined ?
  274. float* colorDataFY = Utils::interp(colorDataY, width * height, y, fy);
  275. ycurve_histogram_regularization(colorDataY, colorDataFY);
  276. delete[](colorDataY);
  277. delete[](colorDataFY);
  278. }
  279. #else
  280. void ImageHDR::ycurve_histogram_regularization(float* colorDataY, float* colorDataFY)
  281. {
  282. float yMin = colorDataY[0];
  283. unsigned int i = 1;
  284. while (yMin == 0)
  285. yMin = colorDataY[i++];
  286. for (unsigned int i = 0; i < width * height; i++)
  287. if (colorDataY[i] != 0 && colorDataY[i] < yMin)
  288. yMin = colorDataY[i];
  289. for (unsigned int i = 0; i < width * height; i++)
  290. if (colorDataY[i] == 0)
  291. colorDataY[i] = yMin;
  292. for (unsigned int i = 0; i < width * height; i++)
  293. {
  294. data[i * 3] = data[i * 3] * colorDataFY[i] / colorDataY[i];
  295. data[i * 3 + 1] = data[i * 3 + 1] * colorDataFY[i] / colorDataY[i];
  296. data[i * 3 + 2] = data[i * 3 + 2] * colorDataFY[i] / colorDataY[i];
  297. }
  298. }
  299. void ImageHDR::yCurve(float s, float b, float m, float w, float h)
  300. {
  301. if (linear)
  302. {
  303. linear_to_non_linear();
  304. linear = false;
  305. }
  306. float* colorDataY = Conversion::sRGB_to_Y_of_XYZ(data, width * height);
  307. YCurve yc(s, b, m, w, h, 200);
  308. Eigen::MatrixXf* points = yc.evalpts(100);
  309. Eigen::RowVectorXf y = (*points).col(0) / 100;
  310. Eigen::RowVectorXf fy = (*points).col(1) / 100;
  311. delete(points);
  312. float* colorDataFY = Utils::interp(colorDataY, width * height, y, fy);
  313. ycurve_histogram_regularization(colorDataY, colorDataFY);
  314. delete[](colorDataY);
  315. delete[](colorDataFY);
  316. }
  317. #endif
  318. /****************************************/
  319. /************** LIGHTNESSMASK ***********/
  320. /****************************************/
  321. #ifdef _MT_
  322. void* lightness_MT(void* arg)
  323. {
  324. MT_lightnessMask* a = (MT_lightnessMask*)arg;
  325. float* data = a->data;
  326. float* colorDataY = a->colorDataY;
  327. bool* mask = a->mask;
  328. float rangeMask[5][2] =
  329. {
  330. {0.0f, 0.2f},
  331. {0.2f, 0.4f},
  332. {0.4f, 0.6f},
  333. {0.6f, 0.8f},
  334. {0.8f, 1.0f}
  335. };
  336. unsigned int maskColor[5][3] =
  337. {
  338. {0, 0, 1},
  339. {0, 1, 1},
  340. {0, 1, 0},
  341. {1, 1, 0},
  342. {1, 0, 0}
  343. };
  344. for (unsigned int i = 0; i < a->length; i++)
  345. {
  346. for (unsigned int j = 0; j < 5; j++)
  347. if (mask[j])
  348. if (colorDataY[i] >= rangeMask[j][0] && colorDataY[i] <= rangeMask[j][1])
  349. {
  350. data[i * 3] = (float)(maskColor[j][0]);
  351. data[i * 3 + 1] = (float)(maskColor[j][1]);
  352. data[i * 3 + 2] = (float)(maskColor[j][2]);
  353. }
  354. }
  355. return arg;
  356. }
  357. void ImageHDR::lightnessMask(bool s, bool b, bool m, bool w, bool h)
  358. {
  359. bool mask[5] = { s, b, m, w, h };
  360. if (linear)
  361. {
  362. linear_to_non_linear();
  363. linear = false;
  364. }
  365. float* colorDataY = Conversion::sRGB_to_Y_of_XYZ(data, width * height);
  366. std::thread tab_t[_MT_];
  367. MT_lightnessMask tab_a[_MT_];
  368. unsigned int id;
  369. unsigned int tab_length = width * height;
  370. unsigned int block_size = tab_length / _MT_;
  371. for (id = 0; id < _MT_; id++) {
  372. tab_a[id].data = data + (id * block_size * 3);
  373. tab_a[id].length = block_size;
  374. tab_a[id].colorDataY = colorDataY + (id * block_size);
  375. tab_a[id].mask = mask;
  376. if (id == (_MT_ - 1))
  377. tab_a[id].length = tab_length - ((_MT_ - 1) * block_size);
  378. tab_t[id] = std::thread(lightness_MT, (void*)(tab_a + id));
  379. }
  380. for (id = 0; id < _MT_; id++) {
  381. tab_t[id].join();
  382. }
  383. delete[](colorDataY);
  384. }
  385. #else
  386. void ImageHDR::lightnessMask(bool s, bool b, bool m, bool w, bool h)
  387. {
  388. bool mask[5] = { s, b, m, w, h };
  389. float rangeMask[5][2] =
  390. {
  391. {0.0f, 0.2f},
  392. {0.2f, 0.4f},
  393. {0.4f, 0.6f},
  394. {0.6f, 0.8f},
  395. {0.8f, 1.0f}
  396. };
  397. unsigned int maskColor[5][3] =
  398. {
  399. {0, 0, 1},
  400. {0, 1, 1},
  401. {0, 1, 0},
  402. {1, 1, 0},
  403. {1, 0, 0}
  404. };
  405. if (linear)
  406. {
  407. linear_to_non_linear();
  408. linear = false;
  409. }
  410. float* colorDataY = Conversion::sRGB_to_Y_of_XYZ(data, width * height);
  411. for (unsigned int i = 0; i < width * height; i++)
  412. {
  413. for (unsigned int j = 0; j < 5; j++)
  414. if (mask[j])
  415. if (colorDataY[i] >= rangeMask[j][0] && colorDataY[i] <= rangeMask[j][1])
  416. {
  417. data[i * 3] = (float)(maskColor[j][0]);
  418. data[i * 3 + 1] = (float)(maskColor[j][1]);
  419. data[i * 3 + 2] = (float)(maskColor[j][2]);
  420. }
  421. }
  422. delete[](colorDataY);
  423. }
  424. #endif
  425. /****************************************/
  426. /************** SATURATION **************/
  427. /****************************************/
  428. #ifdef _MT_
  429. void* saturation_MT(void* arg)
  430. {
  431. MT_saturation* a = (MT_saturation*)arg;
  432. float* dataLab = a->dataLab;
  433. for (unsigned int i = 0; i < a->length; i++)
  434. {
  435. float a_of_Lab = dataLab[i * 3 + 1];
  436. float b_of_Lab = dataLab[i * 3 + 2];
  437. dataLab[i * 3 + 1] = Conversion::Lab_to_C_of_LCH(a_of_Lab, b_of_Lab);
  438. // Application de la saturation
  439. dataLab[i * 3 + 1] = powf(dataLab[i * 3 + 1] / 100.0f, a->gamma) * 100.0f;
  440. dataLab[i * 3 + 2] = Conversion::Lab_to_H_of_LCH(a_of_Lab, b_of_Lab);
  441. }
  442. return arg;
  443. }
  444. void ImageHDR::saturation(float s)
  445. {
  446. float gamma = 1.0f / ((s / 25.0f) + 1.0f);
  447. if (s < 0)
  448. gamma = (-s / 25.0f) + 1.0f;
  449. if (!linear)
  450. {
  451. non_linear_to_linear();
  452. linear = false;
  453. }
  454. float* dataLab = Conversion::sRGB_to_Lab(data, width * height);
  455. std::thread tab_t[_MT_];
  456. MT_saturation tab_a[_MT_];
  457. unsigned int id;
  458. unsigned int tab_length = width * height;
  459. unsigned int block_size = tab_length / _MT_;
  460. for (id = 0; id < _MT_; id++) {
  461. tab_a[id].dataLab = dataLab + (id * block_size * 3);
  462. tab_a[id].length = block_size;
  463. tab_a[id].gamma = gamma;
  464. if (id == (_MT_ - 1))
  465. tab_a[id].length = tab_length - ((_MT_ - 1) * block_size);
  466. tab_t[id] = std::thread(saturation_MT, (void*)(tab_a + id));
  467. }
  468. for (id = 0; id < _MT_; id++) {
  469. tab_t[id].join();
  470. }
  471. delete[](data);
  472. data = dataLab;
  473. linear = false;
  474. colorspace = Colorspace::LCH;
  475. }
  476. #else
  477. void ImageHDR::saturation(float s)
  478. {
  479. float gamma = 1.0f / ((s / 25.0f) + 1.0f);
  480. if (s < 0)
  481. gamma = (-s / 25.0f) + 1.0f;
  482. if (!linear)
  483. {
  484. non_linear_to_linear();
  485. linear = false;
  486. }
  487. float* dataLab = Conversion::sRGB_to_Lab(data, width * height);
  488. for (unsigned int i = 0; i < width * height; i++)
  489. {
  490. float a = dataLab[i * 3 + 1];
  491. float b = dataLab[i * 3 + 2];
  492. dataLab[i * 3 + 1] = Conversion::Lab_to_C_of_LCH(a, b);
  493. // Application de la saturation
  494. dataLab[i * 3 + 1] = powf(dataLab[i * 3 + 1] / 100.0f, gamma) * 100.0f;
  495. dataLab[i * 3 + 2] = Conversion::Lab_to_H_of_LCH(a, b);
  496. }
  497. delete[](data);
  498. data = dataLab;
  499. linear = false;
  500. colorspace = Colorspace::LCH;
  501. }
  502. #endif
  503. /*************************************/
  504. /************ COLOREDITOR ************/
  505. /*************************************/
  506. #ifdef _MT_
  507. void* colorEditor_MT(void* arg)
  508. {
  509. MT_colorEditor* a = (MT_colorEditor*)arg;
  510. float* data = a->data;
  511. unsigned int length = a->length;
  512. unsigned int colorspace = a->colorspace;
  513. bool linear = a->linear;
  514. float lMin = a->lMin, lMax = a->lMax;
  515. float cMin = a->cMin, cMax = a->cMax;
  516. float hMin = a->hMin, hMax = a->hMax;
  517. float tolerance = a->tolerance;
  518. float edit_hue = a->edit_hue;
  519. float edit_exposure = a->edit_exposure;
  520. float edit_contrast = a->edit_contrast;
  521. float edit_saturation = a->edit_saturation;
  522. float hueTolerance = tolerance * 360.0f;
  523. float chromaTolerance = tolerance * 100.0f;
  524. float lightTolerance = tolerance * 100.0f;
  525. bool mask = a->mask;
  526. float* dataLCH = NULL;
  527. float* minMask = NULL;
  528. float* compMask = NULL;
  529. // not the default parameter
  530. if (!(lMin == 0.0f && lMax == 100.0f
  531. && cMin == 0.0f && cMax == 100.0f
  532. && hMin == 0.0f && hMax == 360.0f
  533. && tolerance == 0.1f
  534. && edit_hue == 0.0f
  535. && edit_exposure == 0.0f
  536. && edit_contrast == 0.0f
  537. && edit_saturation == 0.0f
  538. && mask == false))
  539. {
  540. if (colorspace == Colorspace::RGB)
  541. {
  542. if (!linear)
  543. {
  544. data = Conversion::non_linear_to_linear(data, length * 3);
  545. linear = true;
  546. }
  547. dataLCH = Conversion::sRGB_to_Lab(data, length);
  548. for (unsigned int i = 0; i < length; i++)
  549. {
  550. float a = dataLCH[i * 3 + 1];
  551. float b = dataLCH[i * 3 + 2];
  552. dataLCH[i * 3 + 1] = Conversion::Lab_to_C_of_LCH(a, b);
  553. dataLCH[i * 3 + 2] = Conversion::Lab_to_H_of_LCH(a, b);
  554. }
  555. }
  556. else
  557. dataLCH = data;
  558. float* lChannel = new float[length];
  559. float* cChannel = new float[length];
  560. float* hChannel = new float[length];
  561. for (unsigned int i = 0; i < length; i++)
  562. {
  563. lChannel[i] = dataLCH[i * 3];
  564. cChannel[i] = dataLCH[i * 3 + 1];
  565. hChannel[i] = dataLCH[i * 3 + 2];
  566. }
  567. // Récupération du max du canal L et C
  568. float lMaxChannel = dataLCH[0];
  569. float cMaxChannel = dataLCH[1];
  570. for (unsigned int i = 1; i < length; i++)
  571. {
  572. if (dataLCH[i * 3] > lMaxChannel)
  573. lMaxChannel = dataLCH[i * 3];
  574. if (dataLCH[i * 3 + 1] > cMaxChannel)
  575. cMaxChannel = dataLCH[i * 3 + 1];
  576. }
  577. if (lMaxChannel < 100.0f)
  578. lMaxChannel = 100.0f;
  579. if (cMaxChannel < 100.0f)
  580. cMaxChannel = 100.0f;
  581. lMax = lMax * lMaxChannel / 100.0f;
  582. cMax = cMax * cMaxChannel / 100.0f;
  583. float* lightnessMask = Utils::NPlinearWeightMask(lChannel, length, lMin, lMax, lightTolerance);
  584. float* chromaMask = Utils::NPlinearWeightMask(cChannel, length, cMin, cMax, chromaTolerance);
  585. float* hueMask = Utils::NPlinearWeightMask(hChannel, length, hMin, hMax, hueTolerance);
  586. minMask = new float[length];
  587. compMask = new float[length];
  588. for (unsigned int i = 0; i < length; i++)
  589. {
  590. minMask[i] = lightnessMask[i];
  591. if (chromaMask[i] < minMask[i])
  592. minMask[i] = chromaMask[i];
  593. if (hueMask[i] < minMask[i])
  594. minMask[i] = hueMask[i];
  595. compMask[i] = 1.0f - minMask[i];
  596. }
  597. delete[](lightnessMask);
  598. delete[](chromaMask);
  599. delete[](hueMask);
  600. float hueShift = edit_hue;
  601. for (unsigned int i = 0; i < length; i++) {
  602. float oldValue = hChannel[i];
  603. hChannel[i] = oldValue + hueShift;
  604. while (hChannel[i] < 0.0f)
  605. hChannel[i] += 360.0f;
  606. while (hChannel[i] >= 360.0f)
  607. hChannel[i] -= 360.0f;
  608. hChannel[i] = hChannel[i] * minMask[i] + oldValue * compMask[i];
  609. }
  610. float saturation = edit_saturation;
  611. float gamma = 1.0f / ((saturation / 25.0f) + 1.0f);
  612. if (saturation < 0)
  613. gamma = (-saturation / 25.0f) + 1.0f;
  614. for (unsigned int i = 0; i < length; i++) {
  615. cChannel[i] = powf(cChannel[i] / 100.0f, gamma) * 100 * minMask[i] + cChannel[i] * compMask[i];
  616. }
  617. float* colorLCH = new float[length * 3];
  618. for (unsigned int i = 0; i < length; i++)
  619. {
  620. colorLCH[i * 3] = lChannel[i];
  621. colorLCH[i * 3 + 1] = cChannel[i];
  622. colorLCH[i * 3 + 2] = hChannel[i];
  623. }
  624. delete[](lChannel);
  625. delete[](cChannel);
  626. delete[](hChannel);
  627. float ev = edit_exposure;
  628. float* colorRGB = NULL;
  629. if (ev != 0)
  630. {
  631. colorRGB = Conversion::LCH_to_sRGB(colorLCH, length);
  632. float* colorRGBev = new float[length * 3];
  633. float coeff = powf(2, ev);
  634. for (unsigned int i = 0; i < length; i++)
  635. {
  636. colorRGBev[i * 3] = colorRGB[i * 3] * coeff * minMask[i];
  637. colorRGBev[i * 3 + 1] = colorRGB[i * 3 + 1] * coeff * minMask[i];
  638. colorRGBev[i * 3 + 2] = colorRGB[i * 3 + 2] * coeff * minMask[i];
  639. colorRGB[i * 3] = colorRGB[i * 3] * compMask[i] + colorRGBev[i * 3];
  640. colorRGB[i * 3 + 1] = colorRGB[i * 3 + 1] * compMask[i] + colorRGBev[i * 3 + 1];
  641. colorRGB[i * 3 + 2] = colorRGB[i * 3 + 2] * compMask[i] + colorRGBev[i * 3 + 2];
  642. }
  643. delete[](colorRGBev);
  644. }
  645. if (edit_contrast != 0)
  646. {
  647. float contrast = edit_contrast / 100.0f;
  648. float maxContrastFactor = 2.0f;
  649. float scalingFactor = (1.0f - contrast) + maxContrastFactor * contrast;
  650. if (contrast < 0.0f)
  651. {
  652. contrast = -contrast;
  653. scalingFactor = 1.0f / scalingFactor;
  654. }
  655. float pivot = powf(2, ev) * (lMin + lMax) / 2.0f / 100.0f;
  656. if (colorRGB == NULL)
  657. colorRGB = Conversion::LCH_to_sRGB(colorLCH, length);
  658. float* colorRGB2 = Conversion::linear_to_non_linear(colorRGB, length * 3);
  659. delete[](colorRGB);
  660. colorRGB = colorRGB2;
  661. float* colorRGBcon = new float[length * 3];
  662. for (unsigned int i = 0; i < length; i++)
  663. {
  664. colorRGBcon[i * 3] = (colorRGB[i * 3] - pivot) * scalingFactor + pivot;
  665. colorRGBcon[i * 3 + 1] = (colorRGB[i * 3 + 1] - pivot) * scalingFactor + pivot;
  666. colorRGBcon[i * 3 + 2] = (colorRGB[i * 3 + 2] - pivot) * scalingFactor + pivot;
  667. colorRGB[i * 3] = colorRGBcon[i * 3] * minMask[i] + colorRGB[i * 3] * compMask[i];
  668. colorRGB[i * 3 + 1] = colorRGBcon[i * 3 + 1] * minMask[i] + colorRGB[i * 3 + 1] * compMask[i];
  669. colorRGB[i * 3 + 2] = colorRGBcon[i * 3 + 2] * minMask[i] + colorRGB[i * 3 + 2] * compMask[i];
  670. }
  671. delete[](colorRGBcon);
  672. colorRGB2 = Conversion::non_linear_to_linear(colorRGB, length * 3);
  673. delete[](colorRGB);
  674. colorRGB = colorRGB2;
  675. }
  676. if (colorRGB == NULL)
  677. colorRGB = Conversion::LCH_to_sRGB(colorLCH, length);
  678. for (unsigned int i = 0; i < length * 3; i++)
  679. {
  680. data[i] = colorRGB[i];
  681. }
  682. delete[](colorRGB);
  683. delete[](colorLCH);
  684. colorspace = Colorspace::RGB;
  685. linear = true;
  686. }
  687. else
  688. {
  689. //TODO - To test for memory leak ?
  690. if (colorspace == Colorspace::LCH)
  691. {
  692. float* colorRGB = Conversion::LCH_to_sRGB(data, length);
  693. for (unsigned int i = 0; i < length * 3; i++)
  694. {
  695. data[i] = colorRGB[i];
  696. }
  697. delete[](colorRGB);
  698. colorspace = Colorspace::RGB;
  699. linear = true;
  700. }
  701. }
  702. if (mask)
  703. {
  704. for (unsigned int i = 0; i < length; i++)
  705. {
  706. data[i * 3] = minMask[i];
  707. data[i * 3 + 1] = minMask[i];
  708. data[i * 3 + 2] = minMask[i];
  709. }
  710. colorspace = Colorspace::RGB;
  711. linear = false;
  712. }
  713. delete[](minMask);
  714. delete[](compMask);
  715. return arg;
  716. }
  717. void ImageHDR::colorEditor(float* selection_lightness, float* selection_chroma, float* selection_hue, float tolerance, float edit_hue, float edit_exposure, float edit_contrast, float edit_saturation, bool mask)
  718. {
  719. float lMin = selection_lightness[0], lMax = selection_lightness[1];
  720. float cMin = selection_chroma[0], cMax = selection_chroma[1];
  721. float hMin = selection_hue[0], hMax = selection_hue[1];
  722. std::thread tab_t[_MT_];
  723. MT_colorEditor tab_a[_MT_];
  724. unsigned int id;
  725. unsigned int length = width * height;
  726. unsigned int block_size = length / _MT_;
  727. for (id = 0; id < _MT_; id++) {
  728. tab_a[id].data = data + (id * block_size * 3);
  729. tab_a[id].length = block_size;
  730. tab_a[id].colorspace = colorspace;
  731. tab_a[id].linear = linear;
  732. tab_a[id].lMin = lMin;
  733. tab_a[id].lMax = lMax;
  734. tab_a[id].cMin = cMin;
  735. tab_a[id].cMax = cMax;
  736. tab_a[id].hMin = hMin;
  737. tab_a[id].hMax = hMax;
  738. tab_a[id].tolerance = tolerance;
  739. tab_a[id].edit_hue = edit_hue;
  740. tab_a[id].edit_exposure = edit_exposure;
  741. tab_a[id].edit_contrast = edit_contrast;
  742. tab_a[id].edit_saturation = edit_saturation;
  743. tab_a[id].mask = mask;
  744. if (id == (_MT_ - 1))
  745. tab_a[id].length = length - ((_MT_ - 1) * block_size);
  746. tab_t[id] = std::thread(colorEditor_MT, (void*)(tab_a + id));
  747. }
  748. for (id = 0; id < _MT_; id++) {
  749. tab_t[id].join();
  750. }
  751. colorspace = Colorspace::RGB;
  752. linear = true;
  753. }
  754. #else
  755. void ImageHDR::colorEditor(float* selection_lightness, float* selection_chroma, float* selection_hue, float tolerance, float edit_hue, float edit_exposure, float edit_contrast, float edit_saturation, bool mask)
  756. {
  757. float lMin = selection_lightness[0], lMax = selection_lightness[1];
  758. float cMin = selection_chroma[0], cMax = selection_chroma[1];
  759. float hMin = selection_hue[0], hMax = selection_hue[1];
  760. float hueTolerance = tolerance * 360.0f;
  761. float chromaTolerance = tolerance * 100.0f;
  762. float lightTolerance = tolerance * 100.0f;
  763. float* dataLCH = NULL;
  764. float* minMask = NULL;
  765. float* compMask = NULL;
  766. // not the default parameter
  767. if (!(selection_lightness[0] == 0.0f && selection_lightness[1] == 100.0f
  768. && selection_chroma[0] == 0.0f && selection_chroma[1] == 100.0f
  769. && selection_hue[0] == 0.0f && selection_hue[1] == 360.0f
  770. && tolerance == 0.1f
  771. && edit_hue == 0.0f
  772. && edit_exposure == 0.0f
  773. && edit_contrast == 0.0f
  774. && edit_saturation == 0.0f
  775. && mask == false))
  776. {
  777. if (colorspace == Colorspace::RGB)
  778. {
  779. if (!linear)
  780. {
  781. non_linear_to_linear();
  782. linear = true;
  783. }
  784. dataLCH = Conversion::sRGB_to_Lab(data, width * height);
  785. for (unsigned int i = 0; i < width * height; i++)
  786. {
  787. float a = dataLCH[i * 3 + 1];
  788. float b = dataLCH[i * 3 + 2];
  789. dataLCH[i * 3 + 1] = Conversion::Lab_to_C_of_LCH(a, b);
  790. dataLCH[i * 3 + 2] = Conversion::Lab_to_H_of_LCH(a, b);
  791. }
  792. }
  793. else
  794. dataLCH = data;
  795. float* lChannel = new float[width * height];
  796. float* cChannel = new float[width * height];
  797. float* hChannel = new float[width * height];
  798. for (unsigned int i = 0; i < width * height; i++)
  799. {
  800. lChannel[i] = dataLCH[i * 3];
  801. cChannel[i] = dataLCH[i * 3 + 1];
  802. hChannel[i] = dataLCH[i * 3 + 2];
  803. }
  804. // Récupération du max du canal L et C
  805. float lMaxChannel = dataLCH[0];
  806. float cMaxChannel = dataLCH[1];
  807. for (unsigned int i = 1; i < width * height; i++)
  808. {
  809. if (dataLCH[i * 3] > lMaxChannel)
  810. lMaxChannel = dataLCH[i * 3];
  811. if (dataLCH[i * 3 + 1] > cMaxChannel)
  812. cMaxChannel = dataLCH[i * 3 + 1];
  813. }
  814. if (lMaxChannel < 100.0f)
  815. lMaxChannel = 100.0f;
  816. if (cMaxChannel < 100.0f)
  817. cMaxChannel = 100.0f;
  818. lMax = lMax * lMaxChannel / 100.0f;
  819. cMax = cMax * cMaxChannel / 100.0f;
  820. float* lightnessMask = Utils::NPlinearWeightMask(lChannel, width * height, lMin, lMax, lightTolerance);
  821. float* chromaMask = Utils::NPlinearWeightMask(cChannel, width * height, cMin, cMax, chromaTolerance);
  822. float* hueMask = Utils::NPlinearWeightMask(hChannel, width * height, hMin, hMax, hueTolerance);
  823. minMask = new float[width * height];
  824. compMask = new float[width * height];
  825. for (unsigned int i = 0; i < width * height; i++)
  826. {
  827. minMask[i] = lightnessMask[i];
  828. if (chromaMask[i] < minMask[i])
  829. minMask[i] = chromaMask[i];
  830. if (hueMask[i] < minMask[i])
  831. minMask[i] = hueMask[i];
  832. compMask[i] = 1.0f - minMask[i];
  833. }
  834. delete[](lightnessMask);
  835. delete[](chromaMask);
  836. delete[](hueMask);
  837. float hueShift = edit_hue;
  838. for (unsigned int i = 0; i < width * height; i++) {
  839. float oldValue = hChannel[i];
  840. hChannel[i] = oldValue + hueShift;
  841. while (hChannel[i] < 0.0f)
  842. hChannel[i] += 360.0f;
  843. while (hChannel[i] >= 360.0f)
  844. hChannel[i] -= 360.0f;
  845. hChannel[i] = hChannel[i] * minMask[i] + oldValue * compMask[i];
  846. }
  847. float saturation = edit_saturation;
  848. float gamma = 1.0f / ((saturation / 25.0f) + 1.0f);
  849. if (saturation < 0)
  850. gamma = (-saturation / 25.0f) + 1.0f;
  851. for (unsigned int i = 0; i < width * height; i++) {
  852. cChannel[i] = powf(cChannel[i] / 100.0f, gamma) * 100 * minMask[i] + cChannel[i] * compMask[i];
  853. }
  854. float* colorLCH = new float[width * height * 3];
  855. for (unsigned int i = 0; i < width * height; i++)
  856. {
  857. colorLCH[i * 3] = lChannel[i];
  858. colorLCH[i * 3 + 1] = cChannel[i];
  859. colorLCH[i * 3 + 2] = hChannel[i];
  860. }
  861. delete[](lChannel);
  862. delete[](cChannel);
  863. delete[](hChannel);
  864. float ev = edit_exposure;
  865. float* colorRGB = NULL;
  866. if (ev != 0)
  867. {
  868. colorRGB = Conversion::LCH_to_sRGB(colorLCH, width * height);
  869. float* colorRGBev = new float[width * height * 3];
  870. float coeff = powf(2, ev);
  871. for (unsigned int i = 0; i < width * height; i++)
  872. {
  873. colorRGBev[i * 3] = colorRGB[i * 3] * coeff * minMask[i];
  874. colorRGBev[i * 3 + 1] = colorRGB[i * 3 + 1] * coeff * minMask[i];
  875. colorRGBev[i * 3 + 2] = colorRGB[i * 3 + 2] * coeff * minMask[i];
  876. colorRGB[i * 3] = colorRGB[i * 3] * compMask[i] + colorRGBev[i * 3];
  877. colorRGB[i * 3 + 1] = colorRGB[i * 3 + 1] * compMask[i] + colorRGBev[i * 3 + 1];
  878. colorRGB[i * 3 + 2] = colorRGB[i * 3 + 2] * compMask[i] + colorRGBev[i * 3 + 2];
  879. }
  880. delete[](colorRGBev);
  881. }
  882. if (edit_contrast != 0)
  883. {
  884. float contrast = edit_contrast / 100.0f;
  885. float maxContrastFactor = 2.0f;
  886. float scalingFactor = (1.0f - contrast) + maxContrastFactor * contrast;
  887. if (contrast < 0.0f)
  888. {
  889. contrast = -contrast;
  890. scalingFactor = 1.0f / scalingFactor;
  891. }
  892. float pivot = powf(2, ev) * (lMin + lMax) / 2.0f / 100.0f;
  893. if (colorRGB == NULL)
  894. colorRGB = Conversion::LCH_to_sRGB(colorLCH, width * height);
  895. float* colorRGB2 = Conversion::linear_to_non_linear(colorRGB, width * height * 3);
  896. delete[](colorRGB);
  897. colorRGB = colorRGB2;
  898. float* colorRGBcon = new float[width * height * 3];
  899. for (unsigned int i = 0; i < width * height; i++)
  900. {
  901. colorRGBcon[i * 3] = (colorRGB[i * 3] - pivot) * scalingFactor + pivot;
  902. colorRGBcon[i * 3 + 1] = (colorRGB[i * 3 + 1] - pivot) * scalingFactor + pivot;
  903. colorRGBcon[i * 3 + 2] = (colorRGB[i * 3 + 2] - pivot) * scalingFactor + pivot;
  904. colorRGB[i * 3] = colorRGBcon[i * 3] * minMask[i] + colorRGB[i * 3] * compMask[i];
  905. colorRGB[i * 3 + 1] = colorRGBcon[i * 3 + 1] * minMask[i] + colorRGB[i * 3 + 1] * compMask[i];
  906. colorRGB[i * 3 + 2] = colorRGBcon[i * 3 + 2] * minMask[i] + colorRGB[i * 3 + 2] * compMask[i];
  907. }
  908. delete[](colorRGBcon);
  909. colorRGB2 = Conversion::non_linear_to_linear(colorRGB, width * height * 3);
  910. delete[](colorRGB);
  911. colorRGB = colorRGB2;
  912. }
  913. if (colorRGB == NULL)
  914. colorRGB = Conversion::LCH_to_sRGB(colorLCH, width * height);
  915. for (unsigned int i = 0; i < width * height * 3; i++)
  916. {
  917. data[i] = colorRGB[i];
  918. }
  919. delete[](colorRGB);
  920. delete[](colorLCH);
  921. colorspace = Colorspace::RGB;
  922. linear = true;
  923. }
  924. else
  925. {
  926. if (colorspace == Colorspace::LCH)
  927. {
  928. float* colorRGB = Conversion::LCH_to_sRGB(data, width * height);
  929. for (unsigned int i = 0; i < width * height * 3; i++)
  930. {
  931. data[i] = colorRGB[i];
  932. }
  933. delete[](colorRGB);
  934. colorspace = Colorspace::RGB;
  935. linear = true;
  936. }
  937. }
  938. if (mask)
  939. {
  940. for (unsigned int i = 0; i < width * height; i++)
  941. {
  942. data[i * 3] = minMask[i];
  943. data[i * 3 + 1] = minMask[i];
  944. data[i * 3 + 2] = minMask[i];
  945. }
  946. colorspace = Colorspace::RGB;
  947. linear = false;
  948. }
  949. delete[](minMask);
  950. delete[](compMask);
  951. }
  952. #endif
  953. /* Private methods */
  954. Eigen::VectorXf ImageHDR::to_EigenVector() const
  955. {
  956. Eigen::VectorXf v(width * height * 3);
  957. for (unsigned int i = 0; i < width; i++)
  958. v(i) = data[i];
  959. return v;
  960. }