25 std::vector<float> bwv(2, 0);
32 std::vector<uint> UUIDs;
33 for (
int inpr = 0; inpr < boardsidesize.
x; inpr += 1) {
34 for (
int inpc = 0; inpc < boardsidesize.
y; inpc += 1) {
35 if ((inpr % 2 == 0 & inpc % 2 == 0) | (inpr % 2 != 0 & inpc % 2 != 0)) {
42 float xp = 0 - patchsize * (float(boardsidesize.
x) - 1) / 2 + patchsize *
float(inpr);
43 float yp = 0 - patchsize * (float(boardsidesize.
y) - 1) / 2 + patchsize *
float(inpc);
48 UUIDs_white.push_back(UUID);
51 UUIDs_black.push_back(UUID);
57 UUIDs.push_back(UUID);
60 std::vector<helios::vec2> whitespectra(2200);
61 for (
int i = 0; i < whitespectra.size(); i++) {
62 whitespectra.at(i).x = 301 + i;
63 whitespectra.at(i).y = 1;
82 const std::vector<std::vector<std::string>> &spectrumassignment) {
86 if (!colorassignment.empty()) {
87 Nrow = colorassignment.size();
88 Ncol = colorassignment.back().size();
89 }
else if (!spectrumassignment.empty()) {
90 Nrow = spectrumassignment.size();
91 Ncol = spectrumassignment.back().size();
93 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): No color or spectrum assignment provided.");
96 std::vector<uint> UUIDs;
99 for (
int irow = 0; irow < Nrow; irow++) {
100 for (
int icolumn = 0; icolumn < Ncol; icolumn++) {
102 float xp = centrelocation.
x - patchsize * (float(Ncol) - 1) / 2.f + patchsize *
float(icolumn);
103 float yp = centrelocation.
y + patchsize * (float(Nrow) - 1) / 2.f - patchsize *
float(irow);
105 if (!colorassignment.empty()) {
106 if (irow >= colorassignment.size() || icolumn >= colorassignment.at(irow).size()) {
107 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): Dimensions of color assignment array are not consistent. This should be a square matrix.");
114 UUIDs.push_back(UUID);
116 if (!spectrumassignment.empty()) {
117 if (irow >= spectrumassignment.size() || icolumn >= spectrumassignment.at(irow).size()) {
118 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): Dimensions of spectrum assignment array are not consistent. This should be a square matrix.");
119 }
else if (!context->
doesGlobalDataExist(spectrumassignment.at(irow).at(icolumn).c_str())) {
122 spectrumassignment.at(irow).at(icolumn) +
124 " does not exist in global data.");
126 context->
setPrimitiveData(UUID,
"reflectivity_spectrum", spectrumassignment.at(irow).at(icolumn));
136 UUIDs_colorboard = UUIDs;
141 const std::vector<std::vector<std::string>> &spectrumassignment,
const std::string &colorboard_type) {
143 uint Nrow = colorassignment.size();
144 uint Ncol = colorassignment.back().size();
146 if (spectrumassignment.size() != Nrow || spectrumassignment.back().size() != Ncol) {
147 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): Color and spectrum assignment dimensions must match.");
150 std::vector<uint> UUIDs;
153 for (
int irow = 0; irow < Nrow; irow++) {
154 for (
int icolumn = 0; icolumn < Ncol; icolumn++) {
156 float xp = centrelocation.
x - patchsize * (float(Ncol) - 1) / 2.f + patchsize *
float(icolumn);
157 float yp = centrelocation.
y + patchsize * (float(Nrow) - 1) / 2.f - patchsize *
float(irow);
159 if (irow >= colorassignment.size() || icolumn >= colorassignment.at(irow).size()) {
160 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): Dimensions of color assignment array are not consistent. This should be a square matrix.");
164 UUIDs.push_back(UUID);
166 if (irow >= spectrumassignment.size() || icolumn >= spectrumassignment.at(irow).size()) {
167 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): Dimensions of spectrum assignment array are not consistent. This should be a square matrix.");
168 }
else if (!context->
doesGlobalDataExist(spectrumassignment.at(irow).at(icolumn).c_str())) {
169 helios_runtime_error(
"ERROR (CameraCalibration::addColorboard): Spectrum assignment label of " + spectrumassignment.at(irow).at(icolumn) +
" does not exist in global data.");
171 context->
setPrimitiveData(UUID,
"reflectivity_spectrum", spectrumassignment.at(irow).at(icolumn));
174 std::string colorboard_label =
"colorboard_" + colorboard_type;
184 UUIDs_colorboard = UUIDs;
299float CameraCalibration::GradientDescent(std::vector<std::vector<float>> *expandedcameraspectra,
const std::vector<std::vector<float>> &expandedconstinput,
const float &learningrate,
const std::vector<std::vector<float>> &truevalues) {
301 size_t boardnumber = expandedconstinput.size();
302 size_t wavelengthnumber = expandedconstinput.at(0).size();
303 size_t bandnumber = expandedcameraspectra->size();
306 for (
int iband = 0; iband < expandedcameraspectra->size(); iband++) {
309 std::vector<float> output(boardnumber, 0);
310 std::vector<float> errors(boardnumber);
311 for (
int iboardn = 0; iboardn < boardnumber; ++iboardn) {
312 for (
int ispecn = 0; ispecn < wavelengthnumber; ++ispecn) {
313 output.at(iboardn) += expandedcameraspectra->at(iband).at(ispecn) * expandedconstinput.at(iboardn).at(ispecn);
315 errors.at(iboardn) = truevalues.at(iband).at(iboardn) - output.at(iboardn);
318 iloss += (errors.at(iboardn) * errors.at(iboardn)) /
float(boardnumber) / float(bandnumber);
322 std::vector<float> despectrum(wavelengthnumber);
323 for (
int ispecn = 0; ispecn < wavelengthnumber; ++ispecn) {
324 for (
int iboardn = 0; iboardn < boardnumber; ++iboardn) {
325 despectrum.at(ispecn) += errors.at(iboardn) * expandedconstinput.at(iboardn).at(ispecn);
327 expandedcameraspectra->at(iband).at(ispecn) += learningrate * despectrum.at(ispecn);
330 if (expandedcameraspectra->at(iband).at(ispecn) < 0) {
331 expandedcameraspectra->at(iband).at(ispecn) -= learningrate * despectrum.at(ispecn);
373 const std::vector<std::vector<float>> &truevalues) {
375 float learningrate = responseupdateparameters.learningrate;
376 int maxiteration = responseupdateparameters.maxiteration;
377 float minloss = responseupdateparameters.minloss;
378 std::vector<float> camerarescales = responseupdateparameters.camerarescales;
380 std::vector<std::vector<helios::vec2>> cameraresponsespectra;
381 for (std::string cameraresponselabel: camerareponselabels) {
382 std::vector<vec2> cameraresponsespectrum;
383 context->
getGlobalData(cameraresponselabel.c_str(), cameraresponsespectrum);
384 cameraresponsespectra.push_back(cameraresponsespectrum);
388 float normvalue = normalizevalue(cameraresponsespectra, simulatedinputspectra);
390 std::vector<std::vector<float>> expandedcameraspectra;
391 uint bandsnumber = cameraresponsespectra.size();
392 for (
const auto &cameraspectrum: cameraresponsespectra) {
393 expandedcameraspectra.push_back(CameraCalibration::expandSpectrum(cameraspectrum, normvalue));
396 std::vector<std::vector<float>> expandedinputspectra;
397 expandedinputspectra.reserve(simulatedinputspectra.size());
398 for (
const auto &inputspectrum: simulatedinputspectra) {
399 expandedinputspectra.push_back(CameraCalibration::expandSpectrum(inputspectrum.second));
403 std::vector<float> loss;
405 loss.reserve(maxiteration);
406 float stopiteration = maxiteration;
407 for (
int iloop = 0; iloop < maxiteration; ++iloop) {
409 loss.push_back(iloss);
410 if (iloss < minloss) {
411 stopiteration = iloop;
417 }
else if (iloss > 0.5 * initialloss) {
418 learningrate = learningrate * 2;
424 for (
int iband = 0; iband < camerareponselabels.size(); iband++) {
425 calibratedcameraspectra[camerareponselabels.at(iband)] = cameraresponsespectra.at(iband);
426 for (
int ispec = 0; ispec < cameraresponsespectra.at(iband).size() - 1; ispec++) {
427 calibratedcameraspectra[camerareponselabels.at(iband)].at(ispec).y = expandedcameraspectra.at(iband).at(ispec) * camerarescales.at(iband);
429 calibratedcameraspectra[camerareponselabels.at(iband)].back().y = expandedcameraspectra.at(iband).back() * camerarescales.at(iband);
430 std::string calibratedlabel = label +
"_" + camerareponselabels.at(iband);
431 context->
setGlobalData(calibratedlabel.c_str(), calibratedcameraspectra.at(camerareponselabels.at(iband)));
436 std::cout <<
"The final loss after " << stopiteration <<
" iteration is: " << iloss << std::endl;
437 loss.push_back(iloss);
460 int cols = cameraresolution.
x;
461 int rows = cameraresolution.
y;
467 int cols_dif = (cols - camerareoslutionR.
x) / 2;
468 int rows_dif = (rows - camerareoslutionR.
y) / 2;
470 for (
int ib = 0; ib < bandlabels.size(); ib++) {
471 std::string global_data_label =
"camera_" + cameralabel +
"_" + bandlabels.at(ib);
472 std::vector<float> cameradata;
474 context->
getGlobalData(global_data_label.c_str(), cameradata);
476 std::vector<float> distorted_cameradata(camerareoslutionR.
x * camerareoslutionR.
y, 0);
479 for (
int j = 0; j < rows; j++) {
480 for (
int i = 0; i < cols; i++) {
482 double x = (i - cols / 2) / focalxy.
x;
483 double y = (j - rows / 2) / focalxy.
y;
485 double r2 = x * x + y * y;
486 double xDistorted = x * (1 + distCoeffs[0] * r2 + distCoeffs[1] * r2 * r2) + 2 * distCoeffs[2] * x * y + distCoeffs[3] * (r2 + 2 * x * x);
487 double yDistorted = y * (1 + distCoeffs[0] * r2 + distCoeffs[1] * r2 * r2) + 2 * distCoeffs[3] * x * y + distCoeffs[2] * (r2 + 2 * y * y);
490 int xPixel = int(round(xDistorted * focalxy.
x + cols / 2));
491 int yPixel = int(round(yDistorted * focalxy.
y + rows / 2));
494 if (xPixel >= cols_dif && xPixel < cols - cols_dif && yPixel >= rows_dif && yPixel < rows - rows_dif) {
495 int xPos = xPixel - cols_dif;
496 int yPos = yPixel - rows_dif;
497 if (yPos * camerareoslutionR.
x + xPos < distorted_cameradata.size()) {
498 distorted_cameradata.at(yPos * camerareoslutionR.
x + xPos) = cameradata.at(j * cameraresolution.
x + i);
503 context->
setGlobalData(global_data_label.c_str(), distorted_cameradata);
546void CameraCalibration::preprocessSpectra(
const std::vector<std::string> &sourcelabels,
const std::vector<std::string> &cameralabels, std::vector<std::string> &objectlabels,
vec2 &wavelengthrange,
const std::string &targetlabel) {
548 std::map<std::string, std::map<std::string, std::vector<vec2>>> allspectra;
551 std::map<std::string, std::vector<vec2>> Source_spectra;
552 for (
const std::string &sourcelable: sourcelabels) {
554 std::vector<vec2> Source_spectrum;
555 context->
getGlobalData(sourcelable.c_str(), Source_spectrum);
556 Source_spectra.emplace(sourcelable, Source_spectrum);
557 wavelengthboundary(wavelengthrange.
x, wavelengthrange.
y, Source_spectrum);
559 std::cout <<
"WARNING: Source (" << sourcelable <<
") does not exist in global data" << std::endl;
562 allspectra.emplace(
"source", Source_spectra);
565 std::map<std::string, std::vector<vec2>> Camera_spectra;
566 for (
const std::string &cameralabel: cameralabels) {
568 std::vector<vec2> Camera_spectrum;
569 context->
getGlobalData(cameralabel.c_str(), Camera_spectrum);
570 Camera_spectra.emplace(cameralabel, Camera_spectrum);
571 wavelengthboundary(wavelengthrange.
x, wavelengthrange.
y, Camera_spectrum);
573 std::cout <<
"WARNING: Camera (" << cameralabel <<
") does not exist in global data" << std::endl;
576 allspectra.emplace(
"camera", Camera_spectra);
579 std::map<std::string, std::vector<vec2>> Object_spectra;
580 if (!objectlabels.empty()) {
581 for (
const std::string &objectlable: objectlabels) {
583 std::vector<vec2> Object_spectrum;
584 context->
getGlobalData(objectlable.c_str(), Object_spectrum);
585 Object_spectra.emplace(objectlable, Object_spectrum);
586 wavelengthboundary(wavelengthrange.
x, wavelengthrange.
y, Object_spectrum);
588 std::cout <<
"WARNING: Object (" << objectlable <<
") does not exist in global data" << std::endl;
594 std::vector<uint> exist_UUIDs = context->
getAllUUIDs();
595 for (
uint UUID: exist_UUIDs) {
597 std::string spectralreflectivitylabel;
598 context->
getPrimitiveData(UUID,
"reflectivity_spectrum", spectralreflectivitylabel);
600 if (std::find(objectlabels.begin(), objectlabels.end(), spectralreflectivitylabel) == objectlabels.end()) {
601 objectlabels.push_back(spectralreflectivitylabel);
603 std::vector<vec2> Object_spectrum;
604 context->
getGlobalData(spectralreflectivitylabel.c_str(), Object_spectrum);
605 Object_spectra.emplace(spectralreflectivitylabel, Object_spectrum);
606 wavelengthboundary(wavelengthrange.
x, wavelengthrange.
y, Object_spectrum);
612 std::string spectraltransmissivitylabel;
613 context->
getPrimitiveData(UUID,
"transmissivity_spectrum", spectraltransmissivitylabel);
615 if (std::find(objectlabels.begin(), objectlabels.end(), spectraltransmissivitylabel) == objectlabels.end()) {
616 objectlabels.push_back(spectraltransmissivitylabel);
617 std::cout <<
"WARNING: Spectrum (" << spectraltransmissivitylabel <<
") has been added to UUID (" << UUID <<
") but is not in the provided object labels" << std::endl;
618 std::vector<vec2> Object_spectrum;
619 context->
getGlobalData(spectraltransmissivitylabel.c_str(), Object_spectrum);
620 Object_spectra.emplace(spectraltransmissivitylabel, Object_spectrum);
621 wavelengthboundary(wavelengthrange.
x, wavelengthrange.
y, Object_spectrum);
626 allspectra.emplace(
"object", Object_spectra);
630 std::vector<vec2> target_spectrum;
631 if (targetlabel.empty()) {
632 target_spectrum = allspectra.at(
"object").at(objectlabels.at(0));
633 }
else if (std::find(objectlabels.begin(), objectlabels.end(), targetlabel) == objectlabels.end()) {
634 std::cout <<
"WARNING (CameraCalibration::preprocessSpectra()): target label (" << targetlabel <<
") is not a member of object labels" << std::endl;
635 target_spectrum = allspectra.at(
"object").at(objectlabels.at(0));
637 target_spectrum = allspectra.at(
"object").at(targetlabel);
640 for (
const auto &spectralgrouppair: allspectra) {
641 for (
const auto &spectrumpair: spectralgrouppair.second) {
642 std::vector<vec2> cal_spectrum;
643 for (
auto ispectralvalue: target_spectrum) {
644 if (ispectralvalue.x > wavelengthrange.
y) {
645 context->
setGlobalData(spectrumpair.first.c_str(), cal_spectrum);
648 if (ispectralvalue.x >= wavelengthrange.
x) {
649 cal_spectrum.push_back(
make_vec2(ispectralvalue.x,
interp1(spectrumpair.second, ispectralvalue.x)));
652 allspectra[spectralgrouppair.first][spectrumpair.first] = cal_spectrum;
655 processedspectra = allspectra;
658 std::vector<float> wavelengths;
659 for (
auto ispectralvalue: target_spectrum) {
660 if (ispectralvalue.x > wavelengthrange.
y || ispectralvalue.x == target_spectrum.back().x) {
664 if (ispectralvalue.x >= wavelengthrange.
x) {
665 wavelengths.push_back(ispectralvalue.x);
672 std::vector<uint> camera_UUIDs;
673 std::string global_UUID_label =
"camera_" + cameralabel +
"_pixel_UUID";
674 context->
getGlobalData(global_UUID_label.c_str(), camera_UUIDs);
676 float dotsimreal = 0;
678 for (
int ib = 0; ib < bandlabels.size(); ib++) {
680 std::vector<float> camera_data;
681 std::string global_data_label =
"camera_" + cameralabel +
"_" + bandlabels.at(ib);
682 context->
getGlobalData(global_data_label.c_str(), camera_data);
684 for (
int icu = 0; icu < UUIDs_colorboard.size(); icu++) {
688 for (
uint j = 0; j < cameraresolution.
y; j++) {
689 for (
uint i = 0; i < cameraresolution.
x; i++) {
690 uint UUID = camera_UUIDs.at(j * cameraresolution.
x + i) - 1;
691 if (UUID == UUIDs_colorboard.at(icu)) {
692 float value = camera_data.at(j * cameraresolution.
x + i);
699 float sim_cv =
sum / count;
700 float real_cv = truevalues.at(ib).at(icu);
701 dotsimreal += (sim_cv * real_cv);
702 dotsimsim += (sim_cv * sim_cv);
705 float fluxscale = dotsimreal / dotsimsim;
710 std::filesystem::path file_path = context->
resolveFilePath(
"plugins/radiation/spectral_data/external_data/HET01_UNI_scene.def");
711 std::ifstream inputFile(file_path);
712 std::vector<uint> iCUUIDs;
715 while (!inputFile.eof()) {
716 std::vector<float> poslf;
717 std::vector<float> rotatelf_cos;
718 std::vector<float> rotatelf_sc(2);
719 auto widthlengthlf = float(sqrt(0.01f *
M_PI));
720 for (
int i = 0; i < 7; i++) {
723 if (i > 0 && i < 4) {
724 poslf.push_back(idata);
726 rotatelf_cos.push_back(idata);
730 rotatelf_sc.at(0) = float(asin(rotatelf_cos.at(2)));
731 rotatelf_sc.at(1) = float(atan2(rotatelf_cos.at(1), rotatelf_cos.at(0)));
732 if (rotatelf_sc.at(1) < 0) {
733 rotatelf_sc.at(1) += 2 *
M_PI;
735 vec3 iposlf =
make_vec3(poslf.at(0), poslf.at(1), poslf.at(2));
935 float fy = (lab.L + 16.0f) / 116.0f;
936 float fx = lab.a / 500.0f + fy;
937 float fz = fy - lab.b / 200.0f;
940 auto f_reverse = [](
float t) {
941 float t3 = t * t * t;
942 return (t3 > 0.008856f) ? t3 : (t - 16.0f / 116.0f) / 7.787f;
945 float X = f_reverse(fx);
946 float Y = f_reverse(fy);
947 float Z = f_reverse(fz);
950 const float Xn = 0.95047f;
951 const float Yn = 1.00000f;
952 const float Zn = 1.08883f;
960 float r_linear = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z;
961 float g_linear = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z;
962 float b_linear = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z;
965 auto gamma_uncorrect = [](
float c) {
return (c <= 0.0031308f) ? 12.92f * c : 1.055f * powf(c, 1.0f / 2.4f) - 0.055f; };
967 float r = gamma_uncorrect(r_linear);
968 float g = gamma_uncorrect(g_linear);
969 float b = gamma_uncorrect(b_linear);
972 r = std::max(0.0f, std::min(1.0f, r));
973 g = std::max(0.0f, std::min(1.0f, g));
974 b = std::max(0.0f, std::min(1.0f, b));
992 const double kL = 1.0;
993 const double kC = 1.0;
994 const double kH = 1.0;
996 double L1 = lab1.L, a1 = lab1.a, b1 = lab1.b;
997 double L2 = lab2.L, a2 = lab2.a, b2 = lab2.b;
1000 double C1 = sqrt(a1 * a1 + b1 * b1);
1001 double C2 = sqrt(a2 * a2 + b2 * b2);
1002 double C_bar = (C1 + C2) / 2.0;
1005 double G = 0.5 * (1.0 - sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25.0, 7))));
1008 double a1_prime = a1 * (1.0 + G);
1009 double a2_prime = a2 * (1.0 + G);
1012 double C1_prime = sqrt(a1_prime * a1_prime + b1 * b1);
1013 double C2_prime = sqrt(a2_prime * a2_prime + b2 * b2);
1016 double h1_prime = 0, h2_prime = 0;
1018 h1_prime = atan2(b1, a1_prime) * 180.0 /
M_PI;
1023 h2_prime = atan2(b2, a2_prime) * 180.0 /
M_PI;
1029 double delta_L_prime = L2 - L1;
1030 double delta_C_prime = C2_prime - C1_prime;
1032 double delta_h_prime = 0;
1033 if (C1_prime * C2_prime > 0) {
1034 double diff = h2_prime - h1_prime;
1035 if (abs(diff) <= 180) {
1036 delta_h_prime = diff;
1037 }
else if (diff > 180) {
1038 delta_h_prime = diff - 360;
1040 delta_h_prime = diff + 360;
1044 double delta_H_prime = 2.0 * sqrt(C1_prime * C2_prime) * sin(delta_h_prime *
M_PI / 360.0);
1047 double L_bar_prime = (L1 + L2) / 2.0;
1048 double C_bar_prime = (C1_prime + C2_prime) / 2.0;
1050 double h_bar_prime = 0;
1051 if (C1_prime * C2_prime > 0) {
1052 double sum = h1_prime + h2_prime;
1053 double diff = abs(h1_prime - h2_prime);
1055 h_bar_prime =
sum / 2.0;
1056 }
else if (
sum < 360) {
1057 h_bar_prime = (
sum + 360) / 2.0;
1059 h_bar_prime = (
sum - 360) / 2.0;
1064 double T = 1.0 - 0.17 * cos((h_bar_prime - 30) *
M_PI / 180.0) + 0.24 * cos(2 * h_bar_prime *
M_PI / 180.0) + 0.32 * cos((3 * h_bar_prime + 6) *
M_PI / 180.0) - 0.20 * cos((4 * h_bar_prime - 63) *
M_PI / 180.0);
1067 double delta_theta = 30.0 * exp(-pow((h_bar_prime - 275) / 25.0, 2));
1070 double RC = 2.0 * sqrt(pow(C_bar_prime, 7) / (pow(C_bar_prime, 7) + pow(25.0, 7)));
1073 double SL = 1.0 + (0.015 * pow(L_bar_prime - 50, 2)) / sqrt(20 + pow(L_bar_prime - 50, 2));
1074 double SC = 1.0 + 0.045 * C_bar_prime;
1075 double SH = 1.0 + 0.015 * C_bar_prime * T;
1078 double RT = -sin(2 * delta_theta *
M_PI / 180.0) * RC;
1081 double term1 = delta_L_prime / (kL * SL);
1082 double term2 = delta_C_prime / (kC * SC);
1083 double term3 = delta_H_prime / (kH * SH);
1084 double term4 = RT * term2 * term3;
1086 return sqrt(term1 * term1 + term2 * term2 + term3 * term3 + term4);