satdump/src-core/common/image/composite.cpp

279 lines
10 KiB
C++
Raw Permalink Normal View History

2024-04-22 12:17:41 +02:00
#define DEFINE_COMPOSITE_UTILS 1
#include "composite.h"
#include "libs/muparser/muParser.h"
#include "logger.h"
#include "image.h"
2023-01-09 15:13:25 +01:00
#include "libs/sol2/sol.hpp"
#include "common/lua/lua_utils.h"
#include "common/projection/sat_proj/sat_proj.h"
#include "resources.h"
2024-05-09 01:16:08 +02:00
#include "io.h"
#include <codecvt>
#include <locale>
namespace image
{
2023-01-09 15:13:25 +01:00
// Generate a composite from channels and an equation
2024-05-09 01:16:08 +02:00
Image generate_composite_from_equ(std::vector<Image> &inputChannels, std::vector<std::string> channelNumbers, std::string equation, nlohmann::json offsets_cfg, float *progress)
2023-01-09 15:13:25 +01:00
{
// Equation parsing stuff
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; //TODOUWP
2023-01-09 15:13:25 +01:00
mu::Parser rgbParser;
int outValsCnt = 0;
compo_cfg_t f = get_compo_cfg(inputChannels, channelNumbers, offsets_cfg);
2023-01-09 15:13:25 +01:00
// Compute channel variable names
double *channelValues = new double[inputChannels.size()];
for (int i = 0; i < (int)inputChannels.size(); i++)
{
channelValues[i] = 0;
rgbParser.DefineVar(converter.from_bytes(channelNumbers[i]), &channelValues[i]); //TODOUWP
2023-01-09 15:13:25 +01:00
}
try
{
// Set expression
rgbParser.SetExpr(converter.from_bytes(equation)); //TODOUWP
2023-01-09 15:13:25 +01:00
rgbParser.Eval(outValsCnt); // Eval once for channel output count
}
catch (mu::ParserError &e)
{
logger->error(converter.to_bytes(e.GetMsg()));
2024-05-09 01:16:08 +02:00
return Image();
2023-01-09 15:13:25 +01:00
}
size_t img_fullch = f.img_width * f.img_height;
// Output image
bool isRgb = outValsCnt == 3;
2023-11-07 10:29:12 +01:00
bool isRgbA = outValsCnt == 4;
2024-05-09 01:16:08 +02:00
Image rgb_output(f.img_depth, f.img_width, f.img_height, isRgbA ? 4 : (isRgb ? 3 : 1));
// Utils
double R = 0;
double G = 0;
double B = 0;
2023-11-07 10:29:12 +01:00
double A = 0;
// Run though the entire image
2023-01-09 15:13:25 +01:00
for (size_t line = 0; line < (size_t)f.img_height; line++)
{
2023-01-09 15:13:25 +01:00
for (size_t pixel = 0; pixel < (size_t)f.img_width; pixel++)
2021-11-05 15:09:19 +01:00
{
get_channel_vals(channelValues, inputChannels, f, line, pixel);
2022-03-20 20:56:32 +01:00
// Do the math
double *rgbOut = rgbParser.Eval(outValsCnt);
2024-05-09 01:16:08 +02:00
// Get output
R = rgbOut[0];
2023-11-07 10:29:12 +01:00
if (isRgb || isRgbA)
2022-03-20 20:56:32 +01:00
{
2024-05-09 01:16:08 +02:00
G = rgbOut[1];
B = rgbOut[2];
2022-03-20 20:56:32 +01:00
}
2023-11-07 10:29:12 +01:00
if (isRgbA)
2024-05-09 01:16:08 +02:00
A = rgbOut[3];
2022-03-20 20:56:32 +01:00
// Write output
2024-05-09 01:16:08 +02:00
rgb_output.setf(img_fullch * 0 + line * f.img_width + pixel, rgb_output.clampf(R));
2023-11-07 10:29:12 +01:00
if (isRgb || isRgbA)
2022-03-20 20:56:32 +01:00
{
2024-05-09 01:16:08 +02:00
rgb_output.setf(img_fullch * 1 + line * f.img_width + pixel, rgb_output.clampf(G));
rgb_output.setf(img_fullch * 2 + line * f.img_width + pixel, rgb_output.clampf(B));
2022-03-20 20:56:32 +01:00
}
2023-11-07 10:29:12 +01:00
if (isRgbA)
2024-05-09 01:16:08 +02:00
rgb_output.setf(img_fullch * 3 + line * f.img_width + pixel, rgb_output.clampf(A));
}
if (progress != nullptr)
2023-01-09 15:13:25 +01:00
*progress = (float)line / (float)f.img_height;
}
delete[] channelValues;
return rgb_output;
}
2022-06-04 00:48:51 +02:00
// Generate a composite from channels and a LUT
2024-05-09 01:16:08 +02:00
Image generate_composite_from_lut(std::vector<Image> &inputChannels, std::vector<std::string> channelNumbers, std::string lut_path, nlohmann::json offsets_cfg, float *progress)
2022-06-04 00:48:51 +02:00
{
2024-05-09 01:16:08 +02:00
Image lut;
load_png(lut, lut_path);
2022-06-04 00:48:51 +02:00
compo_cfg_t f = get_compo_cfg(inputChannels, channelNumbers, offsets_cfg);
2022-06-04 00:48:51 +02:00
// Compute channel variable names
double *channelValues = new double[inputChannels.size()];
for (int i = 0; i < (int)inputChannels.size(); i++)
channelValues[i] = 0;
// Output image
Image rgb_output(lut.depth(), f.img_width, f.img_height, lut.channels());
2022-06-04 00:48:51 +02:00
2024-05-10 22:31:23 -04:00
// Run though the entire image - One-channel
if (inputChannels.size() == 1)
2022-06-04 00:48:51 +02:00
{
2024-05-10 22:31:23 -04:00
for (size_t line = 0; line < (size_t)f.img_height; line++)
2022-06-04 00:48:51 +02:00
{
2024-05-10 22:31:23 -04:00
for (size_t pixel = 0; pixel < (size_t)f.img_width; pixel++)
2022-06-04 00:48:51 +02:00
{
2024-05-10 22:31:23 -04:00
get_channel_vals(channelValues, inputChannels, f, line, pixel);
2022-06-04 00:48:51 +02:00
2024-05-10 22:31:23 -04:00
// Apply the LUT
int position = channelValues[0] * lut.width();
2022-08-15 17:18:22 +02:00
if (position >= (int)lut.width())
position = (int)lut.width() - 1;
2022-06-04 00:48:51 +02:00
for (int c = 0; c < lut.channels(); c++)
2024-05-09 01:16:08 +02:00
rgb_output.set(c, pixel, line, lut.get(c, position));
2022-06-04 00:48:51 +02:00
}
2024-05-10 22:31:23 -04:00
if (progress != nullptr)
*progress = (float)line / (float)f.img_height;
}
}
// Run though the entire image - Two-channel
else if (inputChannels.size() == 2)
{
for (size_t line = 0; line < (size_t)f.img_height; line++)
{
for (size_t pixel = 0; pixel < (size_t)f.img_width; pixel++)
2022-06-04 00:48:51 +02:00
{
2024-05-10 22:31:23 -04:00
get_channel_vals(channelValues, inputChannels, f, line, pixel);
// Apply the LUT
2022-06-04 00:48:51 +02:00
int position_x = channelValues[0] * lut.width();
int position_y = channelValues[1] * lut.height();
2022-08-15 17:18:22 +02:00
if (position_x >= (int)lut.width())
position_x = (int)lut.width() - 1;
2022-06-04 00:48:51 +02:00
2022-08-15 17:18:22 +02:00
if (position_y >= (int)lut.height())
position_y = (int)lut.height() - 1;
2022-06-04 00:48:51 +02:00
for (int c = 0; c < lut.channels(); c++)
2024-05-09 01:16:08 +02:00
rgb_output.set(c, pixel, line, lut.get(c, position_x, position_y));
2022-06-04 00:48:51 +02:00
2023-05-08 23:08:34 +02:00
// logger->critical("%d, %d, %d", rgb_output.channel(0)[line * img_width + pixel], rgb_output.channel(1)[line * img_width + pixel], rgb_output.channel(2)[line * img_width + pixel]);
2022-06-04 00:48:51 +02:00
}
2024-05-10 22:31:23 -04:00
if (progress != nullptr)
*progress = (float)line / (float)f.img_height;
}
2022-06-04 00:48:51 +02:00
}
delete[] channelValues;
return rgb_output;
}
2023-01-09 15:13:25 +01:00
void bindCompoCfgType(sol::state &lua)
{
sol::usertype<compo_cfg_t> type = lua.new_usertype<compo_cfg_t>("compo_cfg_t");
type["hasOffsets"] = &compo_cfg_t::hasOffsets;
type["offsets"] = &compo_cfg_t::offsets;
type["maxWidth"] = &compo_cfg_t::maxWidth;
type["maxHeight"] = &compo_cfg_t::maxHeight;
type["image_scales"] = &compo_cfg_t::image_scales;
type["img_width"] = &compo_cfg_t::img_width;
type["img_height"] = &compo_cfg_t::img_height;
}
// Generate a composite from channels and a Lua script
2024-05-09 01:16:08 +02:00
Image generate_composite_from_lua(satdump::ImageProducts *img_pro, std::vector<Image> &inputChannels, std::vector<std::string> channelNumbers, std::string lua_path, nlohmann::json lua_vars, nlohmann::json offsets_cfg, std::vector<double> *final_timestamps, float *progress)
2023-01-09 15:13:25 +01:00
{
compo_cfg_t f = get_compo_cfg(inputChannels, channelNumbers, offsets_cfg);
2023-01-09 15:13:25 +01:00
// Compute channel variable names
double *channelValues = new double[inputChannels.size()];
for (int i = 0; i < (int)inputChannels.size(); i++)
channelValues[i] = 0;
// Output image
2024-05-09 01:16:08 +02:00
Image rgb_output; //(f.img_width, f.img_height, 3);
2023-01-09 15:13:25 +01:00
try
{
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.open_libraries(sol::lib::string);
lua.open_libraries(sol::lib::math);
2023-12-08 18:37:13 +01:00
lua_utils::bindLogger(lua);
2023-01-09 15:13:25 +01:00
lua_utils::bindImageTypes(lua);
lua_utils::bindGeoTypes(lua);
lua_utils::bindSatProjType(lua);
lua_utils::bindEquProjType(lua);
lua["has_sat_proj"] = [img_pro]()
{ return img_pro->has_proj_cfg() /*&& img_pro->has_tle() && img_pro->has_timestamps*/; };
2023-11-27 16:05:30 +01:00
if (final_timestamps != nullptr)
lua["get_sat_proj"] = [img_pro, &final_timestamps]()
2024-04-23 22:41:14 +02:00
{ return satdump::get_sat_proj(img_pro->get_proj_cfg(), img_pro->get_tle(), *final_timestamps, true); };
2023-01-09 15:13:25 +01:00
lua["get_resource_path"] = resources::getResourcePath;
lua.script_file(lua_path);
lua["lua_vars"] = lua_utils::mapJsonToLua(lua, lua_vars);
int n_ch = lua["init"]().get<int>();
if (n_ch == 0)
return rgb_output;
2023-01-09 15:13:25 +01:00
2024-05-09 01:16:08 +02:00
rgb_output.init(f.img_depth, f.img_width, f.img_height, n_ch);
2023-01-09 15:13:25 +01:00
lua["rgb_output"] = rgb_output;
lua["compo_cfg"] = f;
lua["set_img_out"] = [&rgb_output](int c, size_t x, size_t y, double v)
{
if (y >= rgb_output.height())
return;
if (x >= rgb_output.width())
return;
2024-05-09 21:01:14 -04:00
rgb_output.setf(c, x, y, rgb_output.clampf(v));
2023-01-09 15:13:25 +01:00
};
lua["get_channel_value"] = [channelValues](int x)
{ return channelValues[x]; };
lua["get_channel_values"] = [channelValues, &inputChannels, &channelNumbers, &f](size_t x, size_t y)
{ get_channel_vals(channelValues, inputChannels, f, y, x); };
2024-02-22 09:09:20 -05:00
lua["get_channel_image"] = [&inputChannels](int ch)
{ return inputChannels[ch]; };
lua["get_calibrated_image"] = [img_pro](int ch, std::string type, float min, float max)
{
2023-09-21 16:58:04 +02:00
satdump::ImageProducts::calib_vtype_t ctype = satdump::ImageProducts::CALIB_VTYPE_AUTO;
if(type == "auto")
ctype = satdump::ImageProducts::CALIB_VTYPE_AUTO;
else if(type == "albedo")
ctype = satdump::ImageProducts::CALIB_VTYPE_ALBEDO;
else if(type == "radiance")
ctype = satdump::ImageProducts::CALIB_VTYPE_RADIANCE;
else if(type == "temperature")
ctype = satdump::ImageProducts::CALIB_VTYPE_TEMPERATURE;
return img_pro->get_calibrated_image(ch, nullptr, ctype, {min, max}); };
lua["get_calibrated_value"] = [img_pro](int ch, int x, int y, bool temp = false)
{ return img_pro->get_calibrated_value(ch, x, y, temp); };
2023-01-09 15:13:25 +01:00
lua["set_progress"] = [&progress](float x, float y)
{ if(progress != nullptr) *progress = x / y; };
lua["process"]();
}
catch (std::exception &e)
{
2023-05-08 23:08:34 +02:00
logger->error("Error generating composite! %s", e.what());
2023-01-09 15:13:25 +01:00
}
delete[] channelValues;
return rgb_output;
}
}