2022-03-05 12:44:19 +01:00
# include "core/plugin.h"
2021-10-17 15:21:40 +02:00
# include "logger.h"
# include "settings.h"
# include "resources.h"
# include <iostream>
# include <fstream>
# include <vector>
# include <iomanip>
# include "libs/predict/predict.h"
2022-02-21 23:32:11 +01:00
# include "goes/gvar/module_gvar_image_decoder.h"
2022-07-07 15:36:19 +02:00
//#include "common/tracking/tle.h"
//#include "common/geodetic/projection/geo_projection.h"
//#include "common/map/map_drawer.h"
2021-10-17 15:21:40 +02:00
# define FIXED_FLOAT(x) std::fixed << std::setprecision(3) << (x)
2022-07-07 15:36:19 +02:00
// geodetic::projection::GEOSProjection proj_geos;
2021-10-18 16:58:32 +02:00
2021-10-17 15:21:40 +02:00
class GVARExtended : public satdump : : Plugin
{
private :
static std : : string misc_preview_text ;
2021-10-18 16:58:32 +02:00
static std : : vector < std : : array < float , 3 > > points ;
2021-10-17 15:21:40 +02:00
static std : : vector < std : : string > names ;
static void satdumpStartedHandler ( const satdump : : SatDumpStartedEvent & )
{
2022-07-07 15:36:19 +02:00
/*
2021-10-17 15:21:40 +02:00
if ( global_cfg . contains ( " gvar_extended " ) )
{
if ( global_cfg [ " gvar_extended " ] . contains ( " preview_misc_text " ) )
misc_preview_text = global_cfg [ " gvar_extended " ] [ " preview_misc_text " ] . get < std : : string > ( ) ;
else
misc_preview_text = " SatDump | GVAR " ;
if ( global_cfg [ " gvar_extended " ] . contains ( " temperature_points " ) )
{
points . clear ( ) ;
for ( int i = 0 ; i < ( int ) global_cfg [ " gvar_extended " ] [ " temperature_points " ] . size ( ) ; i + + )
{
2021-10-18 16:58:32 +02:00
points . push_back ( { global_cfg [ " gvar_extended " ] [ " temperature_points " ] [ i ] [ " lat " ] . get < float > ( ) ,
global_cfg [ " gvar_extended " ] [ " temperature_points " ] [ i ] [ " lon " ] . get < float > ( ) ,
global_cfg [ " gvar_extended " ] [ " temperature_points " ] [ i ] [ " radius " ] . get < float > ( ) } ) ;
2021-10-17 15:21:40 +02:00
names . push_back ( global_cfg [ " gvar_extended " ] [ " temperature_points " ] [ i ] [ " name " ] . get < std : : string > ( ) ) ;
}
}
2022-07-07 15:36:19 +02:00
} */
2021-10-17 15:21:40 +02:00
}
static void gvarSaveChannelImagesHandler ( const goes : : gvar : : events : : GVARSaveChannelImagesEvent & evt )
{
2023-08-02 23:03:18 -04:00
logger - > info ( " Preview... " ) ;
2022-01-01 03:04:37 +01:00
image : : Image < uint8_t > preview ( 1300 , 948 , 1 ) ;
image : : Image < uint8_t > previewImage ;
2021-10-17 15:21:40 +02:00
// Preview generation
{
2022-01-01 03:04:37 +01:00
image : : Image < uint8_t > channel1_8bit ( 1040 , 948 , 1 ) ;
image : : Image < uint8_t > channel2_8bit ( 260 , 237 , 1 ) ;
image : : Image < uint8_t > channel3_8bit ( 260 , 237 , 1 ) ;
image : : Image < uint8_t > channel4_8bit ( 260 , 237 , 1 ) ;
image : : Image < uint8_t > channel5_8bit ( 260 , 237 , 1 ) ;
2021-10-17 15:21:40 +02:00
2022-01-01 03:04:37 +01:00
image : : Image < uint16_t > resized5 = evt . images . image5 ;
2021-10-17 15:21:40 +02:00
resized5 . resize ( 1040 , 948 ) ;
for ( int i = 0 ; i < ( int ) channel1_8bit . size ( ) ; i + + )
{
channel1_8bit [ i ] = resized5 [ i ] / 256 ;
}
2022-01-01 03:04:37 +01:00
image : : Image < uint16_t > buff2 = evt . images . image1 ,
2022-07-07 15:36:19 +02:00
buff3 = evt . images . image2 ,
buff4 = evt . images . image3 ,
buff5 = evt . images . image4 ;
2021-10-17 15:21:40 +02:00
buff2 . resize ( 260 , 237 ) ;
buff3 . resize ( 260 , 237 ) ;
buff4 . resize ( 260 , 237 ) ;
buff5 . resize ( 260 , 237 ) ;
for ( int i = 0 ; i < ( int ) channel2_8bit . size ( ) ; i + + )
{
channel2_8bit [ i ] = buff2 [ i ] / 256 ;
channel3_8bit [ i ] = buff3 [ i ] / 256 ;
channel4_8bit [ i ] = buff4 [ i ] / 256 ;
channel5_8bit [ i ] = buff5 [ i ] / 256 ;
}
2022-07-07 15:36:19 +02:00
2022-01-01 03:04:37 +01:00
channel1_8bit . simple_despeckle ( ) ;
channel2_8bit . simple_despeckle ( ) ;
channel3_8bit . simple_despeckle ( ) ;
channel4_8bit . simple_despeckle ( ) ;
channel5_8bit . simple_despeckle ( ) ;
preview . draw_image ( 0 , channel1_8bit , 0 , 0 ) ;
preview . draw_image ( 0 , channel2_8bit , 1040 , 0 ) ;
preview . draw_image ( 0 , channel3_8bit , 1040 , 237 ) ;
preview . draw_image ( 0 , channel4_8bit , 1040 , 474 ) ;
preview . draw_image ( 0 , channel5_8bit , 1040 , 711 ) ;
2021-10-17 15:21:40 +02:00
}
// Overlay the preview
{
std : : string sat_name = evt . images . sat_number = = 13 ? " EWS-G1 / GOES-13 " : ( " GOES- " + std : : to_string ( evt . images . sat_number ) ) ;
std : : string date_time = ( evt . timeReadable - > tm_mday > 9 ? std : : to_string ( evt . timeReadable - > tm_mday ) : " 0 " + std : : to_string ( evt . timeReadable - > tm_mday ) ) + ' / ' +
( evt . timeReadable - > tm_mon + 1 > 9 ? std : : to_string ( evt . timeReadable - > tm_mon + 1 ) : " 0 " + std : : to_string ( evt . timeReadable - > tm_mon + 1 ) ) + ' / ' +
std : : to_string ( evt . timeReadable - > tm_year + 1900 ) + ' ' +
( evt . timeReadable - > tm_hour > 9 ? std : : to_string ( evt . timeReadable - > tm_hour ) : " 0 " + std : : to_string ( evt . timeReadable - > tm_hour ) ) + ' : ' +
( evt . timeReadable - > tm_min > 9 ? std : : to_string ( evt . timeReadable - > tm_min ) : " 0 " + std : : to_string ( evt . timeReadable - > tm_min ) ) + " UTC " ;
int offsetX , offsetY , bar_height ;
2022-07-07 15:36:19 +02:00
// set ratios for calculating bar size
2021-10-17 15:21:40 +02:00
float bar_ratio = 0.02 ;
2022-01-28 11:51:04 +01:00
2021-10-17 15:21:40 +02:00
bar_height = preview . width ( ) * bar_ratio ;
2022-07-07 15:36:19 +02:00
offsetX = 5 ; // preview.width() * offsetXratio;
offsetY = 1 ; // preview.width() * offsetYratio;
2021-10-17 15:21:40 +02:00
unsigned char color = 255 ;
2022-07-07 15:36:19 +02:00
image : : Image < uint8_t > imgtext = image : : generate_text_image ( sat_name . c_str ( ) , & color , bar_height , offsetX , offsetY ) ;
image : : Image < uint8_t > imgtext1 = image : : generate_text_image ( date_time . c_str ( ) , & color , bar_height , offsetX , offsetY ) ;
image : : Image < uint8_t > imgtext2 = image : : generate_text_image ( misc_preview_text . c_str ( ) , & color , bar_height , offsetX , offsetY ) ;
2022-01-01 03:04:37 +01:00
2022-01-27 16:37:38 +01:00
previewImage = image : : Image < uint8_t > ( preview . width ( ) , preview . height ( ) + 2 * bar_height , 1 ) ;
2021-10-17 15:21:40 +02:00
previewImage . fill ( 0 ) ;
2022-01-01 03:04:37 +01:00
2022-01-27 16:37:38 +01:00
previewImage . draw_image ( 0 , imgtext , 0 , 0 ) ;
previewImage . draw_image ( 0 , imgtext1 , previewImage . width ( ) - imgtext1 . width ( ) , 0 ) ;
previewImage . draw_image ( 0 , imgtext2 , 0 , bar_height + preview . height ( ) ) ;
2022-01-01 03:04:37 +01:00
previewImage . draw_image ( 0 , preview , 0 , bar_height ) ;
2021-10-17 15:21:40 +02:00
}
2023-08-02 23:03:18 -04:00
previewImage . save_img ( std : : string ( evt . directory + " /preview " ) . c_str ( ) ) ;
2021-10-17 15:21:40 +02:00
2022-07-07 15:36:19 +02:00
/*
// calibrated temperature measurement based on NOAA LUTs (https://www.ospo.noaa.gov/Operations/GOES/calibration/gvar-conversion.html)
if ( evt . images . image1 . width ( ) = = 5206 | | evt . images . image1 . width ( ) = = 5209 )
{
std : : string filename = " goes/gvar/goes " + std : : to_string ( evt . images . sat_number ) + " _gvar_lut.txt " ;
if ( resources : : resourceExists ( filename ) & & points . size ( ) > 0 )
{
std : : ifstream input ( resources : : getResourcePath ( filename ) . c_str ( ) ) ;
std : : array < std : : array < float , 1024 > , 4 > LUTs = readLUTValues ( input ) ;
input . close ( ) ;
std : : ofstream output ( evt . directory + " /temperatures.txt " ) ;
logger - > info ( " Temperatures... temperatures.txt " ) ;
image : : Image < uint16_t > im1 = cropIR ( evt . images . image1 ) ;
image : : Image < uint16_t > im2 = cropIR ( evt . images . image2 ) ;
image : : Image < uint16_t > im3 = cropIR ( evt . images . image3 ) ;
image : : Image < uint16_t > im4 = cropIR ( evt . images . image4 ) ;
std : : array < image : : Image < uint16_t > , 4 > channels = { im1 , im2 , im3 , im4 } ;
geodetic : : projection : : GEOProjector proj ( 61.5 , 35782.466981 , 18990 , 18956 , 1.1737 , 1.1753 , 0 , - 40 , 1 ) ;
for ( int j = 0 ; j < ( int ) points . size ( ) ; j + + )
{
int x , y ;
proj . forward ( points [ j ] [ 1 ] , points [ j ] [ 0 ] , x , y ) ;
x / = 4 ;
y / = 4 ;
output < < " Temperature measurements for point [ " + std : : to_string ( x ) + " , " + std : : to_string ( y ) + " ] ( " + names [ j ] + " ) with r = " + std : : to_string ( points [ j ] [ 2 ] ) < < ' \n '
< < ' \n ' ;
logger - > info ( " Temperature measurements for point [ " + std : : to_string ( x ) + " , " + std : : to_string ( y ) + " ] ( " + names [ j ] + " ) with r = " + std : : to_string ( points [ j ] [ 2 ] ) ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
output < < " Channel " + std : : to_string ( i + 2 ) + " : " < < FIXED_FLOAT ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] )
< < " K ( " ;
if ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 < 10 )
{
if ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 < = - 10 )
{
output < < FIXED_FLOAT ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 ) ;
}
else if ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 > 0 )
{
output < < " " < < FIXED_FLOAT ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 ) ;
}
else
{
output < < " " < < FIXED_FLOAT ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 ) ;
}
}
else
{
output < < " " < < FIXED_FLOAT ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 ) ;
}
output < < " °C) " ;
output < < ' \n ' ;
logger - > info ( " channel " + std : : to_string ( i + 2 ) + " : " +
std : : to_string ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] ) +
" K ( " + std : : to_string ( LUTs [ i ] [ getAVG ( channels [ i ] , x , y , points [ j ] [ 2 ] ) > > 6 ] - 273.15 ) + " °C) " ) ;
}
output < < ' \n '
< < ' \n ' ;
}
output . close ( ) ;
}
else
{
logger - > warn ( " goes/gvar/goes " + std : : to_string ( evt . images . sat_number ) + " _gvar_lut.txt LUT is missing! Temperature measurement will not be performed. " ) ;
}
}
else
{
logger - > info ( " Image is not a FD, temperature measurement will not be performed. " ) ;
}
logger - > info ( " Generating mapped crops.. " ) ;
// mapped crops of europe. IR and VIS
image : : Image < uint16_t > mapProj = cropIR ( evt . images . image3 ) ;
drawMapOverlay ( evt . images . sat_number , evt . timeUTC , mapProj ) ;
mapProj . crop ( 500 , 50 , 500 + 1560 , 50 + 890 ) ;
2023-08-02 23:03:18 -04:00
logger - > info ( " Europe IR crop.. " ) ;
mapProj . to8bits ( ) . save_img ( std : : string ( evt . directory + " /europe_IR " ) . c_str ( ) ) ;
2022-07-07 15:36:19 +02:00
mapProj = cropVIS ( evt . images . image5 ) ;
drawMapOverlay ( evt . images . sat_number , evt . timeUTC , mapProj ) ;
mapProj . crop ( 1348 , 240 , 1348 + 5928 , 240 + 4120 ) ;
2023-08-02 23:03:18 -04:00
logger - > info ( " Europe VIS crop.. europe_VIS " ) ;
mapProj . to8bits ( ) . save_img ( std : : string ( evt . directory + " /europe_VIS " ) . c_str ( ) ) ;
2022-07-07 15:36:19 +02:00
mapProj . clear ( ) ;
*/
2021-10-17 15:21:40 +02:00
}
static void gvarSaveFalceColorHandler ( const goes : : gvar : : events : : GVARSaveFCImageEvent & evt )
{
if ( evt . sat_number = = 13 )
{
2023-08-02 23:03:18 -04:00
logger - > info ( " Europe crop... " ) ;
2022-01-01 03:04:37 +01:00
image : : Image < uint8_t > crop = evt . false_color_image ;
2021-10-17 15:21:40 +02:00
if ( crop . width ( ) = = 20836 )
crop . crop ( 3198 , 240 , 3198 + 5928 , 240 + 4120 ) ;
else
crop . crop ( 1348 , 240 , 1348 + 5928 , 240 + 4120 ) ;
2023-08-02 23:03:18 -04:00
crop . save_img ( std : : string ( evt . directory + " /europe " ) . c_str ( ) ) ;
2021-10-17 15:21:40 +02:00
}
}
static std : : array < std : : array < float , 1024 > , 4 > readLUTValues ( std : : ifstream & LUT )
{
std : : array < std : : array < float , 1024 > , 4 > values ;
std : : string tmp ;
2022-07-07 15:36:19 +02:00
// skip first 7 lines
2021-10-17 15:21:40 +02:00
for ( int i = 0 ; i < 7 ; i + + )
{
std : : getline ( LUT , tmp ) ;
}
2022-07-07 15:36:19 +02:00
// read LUTs
2021-10-17 15:21:40 +02:00
for ( int i = 0 ; i < 4 ; i + + )
{
for ( int j = 0 ; j < 1024 ; j + + )
{
std : : getline ( LUT , tmp ) ;
values [ i ] [ j ] = std : : stof ( tmp . substr ( 39 , 7 ) ) ;
}
if ( i ! = 3 )
{
2022-07-07 15:36:19 +02:00
// skip det2 for first 3 channels (no det2 for ch6)
2021-10-17 15:21:40 +02:00
for ( int j = 0 ; j < 1030 ; j + + )
{
std : : getline ( LUT , tmp ) ;
}
}
}
return values ;
}
2022-01-01 03:04:37 +01:00
static unsigned short getAVG ( image : : Image < uint16_t > & image , int x , int y , int r )
2021-10-17 15:21:40 +02:00
{
uint64_t sum = 0 ;
for ( int i = 0 ; i < std : : pow ( r * 2 + 1 , 2 ) ; i + + )
{
2022-07-07 15:36:19 +02:00
sum + = image [ ( y - r + i / ( 2 * r + 1 ) ) * image . width ( ) + ( x - r + i % ( 2 * r + 1 ) ) ] ;
2021-10-17 15:21:40 +02:00
}
return sum / std : : pow ( r * 2 + 1 , 2 ) ;
}
2022-07-07 15:36:19 +02:00
static image : : Image < uint16_t > cropIR ( image : : Image < uint16_t > input )
2021-10-17 15:21:40 +02:00
{
2022-02-01 14:04:05 +01:00
image : : Image < uint16_t > output ( 4749 , input . height ( ) , 1 ) ;
2021-10-17 15:21:40 +02:00
if ( input . width ( ) = = 5206 )
{
2022-02-01 14:04:05 +01:00
output . draw_image ( 0 , input , 0 , 0 ) ;
2021-10-17 15:21:40 +02:00
}
else if ( input . width ( ) = = 5209 )
{
2022-02-01 14:04:05 +01:00
output . draw_image ( 0 , input , - 463 , 0 ) ;
2021-10-17 15:21:40 +02:00
}
else
{
logger - > warn ( " Wrong IR image size ( " + std : : to_string ( input . width ( ) ) + " ), it will not be cropped " ) ;
}
return output ;
}
2022-01-01 03:04:37 +01:00
static image : : Image < uint16_t > cropVIS ( image : : Image < uint16_t > input )
2021-10-17 15:21:40 +02:00
{
2022-02-01 14:04:05 +01:00
image : : Image < uint16_t > output ( 18990 , input . height ( ) , 1 ) ;
2021-10-17 15:21:40 +02:00
if ( input . width ( ) = = 20824 )
{
2022-02-01 14:04:05 +01:00
output . draw_image ( 0 , input , 0 , 0 ) ;
2021-10-17 15:21:40 +02:00
}
else if ( input . width ( ) = = 20836 )
{
2022-02-01 14:04:05 +01:00
output . draw_image ( 0 , input , - 1852 , 0 ) ;
2021-10-17 15:21:40 +02:00
}
else
{
logger - > warn ( " Wrong VIS image size ( " + std : : to_string ( input . width ( ) ) + " ), it will not be cropped " ) ;
}
return output ;
}
static int getNORADFromSatNumber ( int number )
{
if ( number = = 13 )
return 29155 ;
else if ( number = = 14 )
return 35491 ;
else if ( number = = 15 )
return 36411 ;
else
return 0 ;
} ;
static predict_position getSatellitePosition ( int number , time_t time )
{
2022-07-07 15:36:19 +02:00
// tle::TLE goes_tle = tle::getTLEfromNORAD(getNORADFromSatNumber(number));
// predict_orbital_elements_t *goes_object = predict_parse_tle(goes_tle.line1.c_str(), goes_tle.line2.c_str());
2021-10-17 15:21:40 +02:00
predict_position goes_position ;
2022-07-07 15:36:19 +02:00
// predict_orbit(goes_object, &goes_position, predict_to_julian(time));
// predict_destroy_orbital_elements(goes_object);
2021-10-17 15:21:40 +02:00
return goes_position ;
}
// Expect cropped IR
2022-01-01 03:04:37 +01:00
static void drawMapOverlay ( int number , time_t time , image : : Image < uint16_t > & image )
2021-10-17 15:21:40 +02:00
{
2022-07-07 15:36:19 +02:00
/*geodetic::projection::GEOProjector proj(61.5, 35782.466981, 18990, 18956, 1.1737, 1.1753, 0, -40, 1);
2021-10-17 15:21:40 +02:00
unsigned short color [ 3 ] = { 65535 , 65535 , 65535 } ;
2021-10-18 16:58:32 +02:00
map : : drawProjectedMapShapefile ( { resources : : getResourcePath ( " maps/ne_10m_admin_0_countries.shp " ) } , image , color , [ & proj , & image ] ( float lat , float lon , int map_height , int map_width ) - > std : : pair < int , int >
2021-10-17 15:21:40 +02:00
{
int image_x , image_y ;
2021-10-18 16:58:32 +02:00
proj . forward ( lon , lat , image_x , image_y ) ;
if ( image . width ( ) = = 18990 )
{
return { image_x , image_y } ;
}
else
{
if ( image_x = = - 1 & & image_y = = - 1 )
{
return { - 1 , - 1 } ;
}
else
{
return { image_x / 4 , image_y / 4 } ;
}
2022-07-07 15:36:19 +02:00
} } ) ; */
2021-10-17 15:21:40 +02:00
}
public :
std : : string getID ( )
{
return " gvar_extended " ;
}
void init ( )
{
satdump : : eventBus - > register_handler < satdump : : SatDumpStartedEvent > ( satdumpStartedHandler ) ;
satdump : : eventBus - > register_handler < goes : : gvar : : events : : GVARSaveChannelImagesEvent > ( gvarSaveChannelImagesHandler ) ;
satdump : : eventBus - > register_handler < goes : : gvar : : events : : GVARSaveFCImageEvent > ( gvarSaveFalceColorHandler ) ;
}
} ;
std : : string GVARExtended : : misc_preview_text = " SatDump | GVAR " ;
2021-10-18 16:58:32 +02:00
std : : vector < std : : array < float , 3 > > GVARExtended : : points = { { } } ;
2021-10-17 15:21:40 +02:00
std : : vector < std : : string > GVARExtended : : names = { } ;
PLUGIN_LOADER ( GVARExtended )