Also made some floating-point math more explicittags/v1.8.0
@@ -65,9 +65,9 @@ Satellite number | |||||
For temperature calibration | For temperature calibration | ||||
Default: "19" | Default: "19" | ||||
-e [c|t] | |||||
-e [c|t|h] | |||||
Enhancements | Enhancements | ||||
Contrast (c) or Crop Telemetry (t) | |||||
Contrast calibration (c), Histogram equalise (h), Crop Telemetry (t) | |||||
Defaults: "ct" | Defaults: "ct" | ||||
-c <file> | -c <file> | ||||
@@ -77,7 +77,7 @@ Default: Internal defaults | |||||
## Output | ## Output | ||||
Generated images are outputted in PNG, 8 bit greyscale for raw and channel A|B images, 24 bit RGB for false color. | |||||
Generated images are outputted in PNG, 8 bit greyscale for raw and channel A|B images, palleted images for temperature and GVI false color, 24 bit RGB for false color. | |||||
Image names are `audiofile-x.png`, where `x` is: | Image names are `audiofile-x.png`, where `x` is: | ||||
@@ -87,10 +87,11 @@ Image names are `audiofile-x.png`, where `x` is: | |||||
- `t` for temperature calibrated images | - `t` for temperature calibrated images | ||||
- `l` for layered images | - `l` for layered images | ||||
Currently there are 2 available enchancements: | |||||
Currently there are 3 available enhancements: | |||||
- `c` for contrast equalise, on by default | - `c` for contrast equalise, on by default | ||||
- `t` for crop telemetry, on by default, only has effects on raw images | - `t` for crop telemetry, on by default, only has effects on raw images | ||||
- `h` for histogram equalise, make the darkest color black and the brightest white | |||||
## Example | ## Example | ||||
@@ -213,7 +213,7 @@ int getpixelrow(float *pixelv) { | |||||
static float pixels[PixelLine + SyncFilterLen]; | static float pixels[PixelLine + SyncFilterLen]; | ||||
static int npv; | static int npv; | ||||
static int synced = 0; | static int synced = 0; | ||||
static double max = 0; | |||||
static double max = 0.0; | |||||
double corr, ecorr, lcorr; | double corr, ecorr, lcorr; | ||||
int res; | int res; | ||||
@@ -83,7 +83,7 @@ rgba composite(rgba top, rgba bottom){ | |||||
void falsecolor(float vis, float temp, float *r, float *g, float *b){ | void falsecolor(float vis, float temp, float *r, float *g, float *b){ | ||||
rgba buffer; | rgba buffer; | ||||
fcinfo.Land.a = 0; fcinfo.Sea.a = 0; | |||||
fcinfo.Land.a = 0.0f; fcinfo.Sea.a = 0.0f; | |||||
// Calculate intensity of sea and land | // Calculate intensity of sea and land | ||||
fcinfo.Sea.a = CLIP(vis, 0, 20)/fcinfo.Seaintensity + fcinfo.Seaoffset; | fcinfo.Sea.a = CLIP(vis, 0, 20)/fcinfo.Seaintensity + fcinfo.Seaoffset; | ||||
@@ -91,7 +91,7 @@ void falsecolor(float vis, float temp, float *r, float *g, float *b){ | |||||
// Composite land on top of sea | // Composite land on top of sea | ||||
buffer = composite(fcinfo.Land, fcinfo.Sea); | buffer = composite(fcinfo.Land, fcinfo.Sea); | ||||
buffer.a = 1; | |||||
buffer.a = 1.0f; | |||||
// Composite clouds on top | // Composite clouds on top | ||||
fcinfo.Cloud.a = CLIP(temp-fcinfo.Cloudthreshold, 0, fcinfo.Cloudintensity)/fcinfo.Cloudintensity; | fcinfo.Cloud.a = CLIP(temp-fcinfo.Cloudthreshold, 0, fcinfo.Cloudintensity)/fcinfo.Cloudintensity; | ||||
@@ -56,6 +56,33 @@ static double tele[16]; | |||||
static double Cs; | static double Cs; | ||||
static int nbtele; | static int nbtele; | ||||
void histogramEqualise(float **prow, int nrow, int offset, int width){ | |||||
// Plot histogram | |||||
int histogram[256] = { 0 }; | |||||
for(int y = 0; y < nrow; y++) | |||||
for(int x = 0; x < width; x++) | |||||
histogram[(int)floor(prow[y][x+offset])]++; | |||||
// Find min/max points | |||||
int min = -1, max = -1; | |||||
for(int i = 5; i < 250; i++){ | |||||
if(histogram[i]/width/(nrow/255.0) > 1.0){ | |||||
if(min == -1) min = i; | |||||
max = i; | |||||
} | |||||
} | |||||
//printf("Min Value: %i, Max Value %i\n", min, max); | |||||
// Spread values to avoid overshoot | |||||
min -= 5; max += 5; | |||||
// Stretch the brightness into the new range | |||||
for(int y = 0; y < nrow; y++) | |||||
for(int x = 0; x < width; x++) | |||||
prow[y][x+offset] = (prow[y][x+offset]-min) / (max-min) * 255; | |||||
} | |||||
// Brightness equalise, including telemetry | // Brightness equalise, including telemetry | ||||
void equalise(float **prow, int nrow, int offset, int width, int telestart, rgparam regr[30]){ | void equalise(float **prow, int nrow, int offset, int width, int telestart, rgparam regr[30]){ | ||||
offset -= SYNC_WIDTH+SPC_WIDTH; | offset -= SYNC_WIDTH+SPC_WIDTH; | ||||
@@ -100,7 +127,7 @@ void equalise(float **prow, int nrow, int offset, int width, int telestart, rgpa | |||||
// Get telemetry data for thermal calibration/equalization | // Get telemetry data for thermal calibration/equalization | ||||
int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise) { | int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise) { | ||||
double teleline[3000]; | |||||
double teleline[3000] = { 0.0 }; | |||||
double wedge[16]; | double wedge[16]; | ||||
rgparam regr[30]; | rgparam regr[30]; | ||||
int n, k; | int n, k; | ||||
@@ -112,7 +139,6 @@ int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualis | |||||
float *pixelv = prow[n]; | float *pixelv = prow[n]; | ||||
// Average the center 40px | // Average the center 40px | ||||
teleline[n] = 0.0; | |||||
for (int i = 3; i < 43; i++) teleline[n] += pixelv[i + offset + width]; | for (int i = 3; i < 43; i++) teleline[n] += pixelv[i + offset + width]; | ||||
teleline[n] /= 40.0; | teleline[n] /= 40.0; | ||||
} | } | ||||
@@ -127,7 +153,7 @@ int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualis | |||||
* difference in brightness, this will always be in the center of | * difference in brightness, this will always be in the center of | ||||
* the frame and can thus be used to find the start of the frame | * the frame and can thus be used to find the start of the frame | ||||
*/ | */ | ||||
float max = 0; | |||||
double max = 0.0; | |||||
for (n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) { | for (n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) { | ||||
float df; | float df; | ||||
@@ -177,9 +177,9 @@ static int ImageOut(char *filename, char *chid, float **prow, int nrow, int widt | |||||
}else if(effects == 3){ | }else if(effects == 3){ | ||||
// Layered image, overlay clouds in channel B over channel A | // Layered image, overlay clouds in channel B over channel A | ||||
float cloud = CLIP(pixelv[i+CHB_OFFSET]-141, 0, 255)/114; | float cloud = CLIP(pixelv[i+CHB_OFFSET]-141, 0, 255)/114; | ||||
pixel[i] = MCOMPOSITE(255, cloud, pixelv[i+CHA_OFFSET], 1); | |||||
pixel[i] = MCOMPOSITE(240, cloud, pixelv[i+CHA_OFFSET], 1); | |||||
}else{ | }else{ | ||||
pixel[i] = pixelv[i + offset + f]; | |||||
pixel[i] = CLIP(pixelv[i + offset + f], 0, 255); | |||||
} | } | ||||
} | } | ||||
@@ -228,6 +228,7 @@ static void distrib(char *filename, float **prow, int nrow) { | |||||
} | } | ||||
extern int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise); | extern int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise); | ||||
extern void histogramEqualise(float **prow, int nrow, int offset, int width); | |||||
extern void temperature(float **prow, int nrow, int ch, int offset); | extern void temperature(float **prow, int nrow, int ch, int offset); | ||||
extern int Ngvi(float **prow, int nrow); | extern int Ngvi(float **prow, int nrow); | ||||
extern void readfcconf(char *file); | extern void readfcconf(char *file); | ||||
@@ -243,6 +244,7 @@ static void usage(void) { | |||||
" -e [c|t] Enhancements\n" | " -e [c|t] Enhancements\n" | ||||
" c: Contrast equalise\n" | " c: Contrast equalise\n" | ||||
" t: Crop telemetry\n" | " t: Crop telemetry\n" | ||||
" h: Histogram equalise\n" | |||||
" -i [r|a|b|c|t] Output image type\n" | " -i [r|a|b|c|t] Output image type\n" | ||||
" r: Raw\n" | " r: Raw\n" | ||||
" a: Channel A\n" | " a: Channel A\n" | ||||
@@ -350,7 +352,6 @@ int main(int argc, char **argv) { | |||||
if (getpixelrow(prow[nrow]) == 0) | if (getpixelrow(prow[nrow]) == 0) | ||||
break; | break; | ||||
printf("Row: %d\r", nrow); | printf("Row: %d\r", nrow); | ||||
fflush(stdout); | fflush(stdout); | ||||
} | } | ||||
@@ -358,9 +359,6 @@ int main(int argc, char **argv) { | |||||
sf_close(inwav); | sf_close(inwav); | ||||
// Layered & false color images both need brightness equalization | |||||
int contrastEqualise = CONTAINS(enchancements, 'c') || CONTAINS(imgopt, 'l') || CONTAINS(imgopt, 'c'); | |||||
chA = calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH, 0); | chA = calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH, 0); | ||||
chB = calibrate(prow, nrow, CHB_OFFSET, CH_WIDTH, 0); | chB = calibrate(prow, nrow, CHB_OFFSET, CH_WIDTH, 0); | ||||
printf("Channel A: %s (%s)\n", ch.id[chA], ch.name[chA]); | printf("Channel A: %s (%s)\n", ch.id[chA], ch.name[chA]); | ||||
@@ -374,9 +372,15 @@ int main(int argc, char **argv) { | |||||
} | } | ||||
// Run the contrast equalise here because the temperature calibration requires raw data | // Run the contrast equalise here because the temperature calibration requires raw data | ||||
if(contrastEqualise) | |||||
// Also layered & false color images both need brightness equalization | |||||
if(CONTAINS(enchancements, 'c') || CONTAINS(enchancements, 'h') || CONTAINS(imgopt, 'l') || CONTAINS(imgopt, 'c')) | |||||
calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH+TELE_WIDTH+SYNC_WIDTH+SPC_WIDTH+CH_WIDTH, 1); | calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH+TELE_WIDTH+SYNC_WIDTH+SPC_WIDTH+CH_WIDTH, 1); | ||||
if(CONTAINS(enchancements, 'h')){ | |||||
histogramEqualise(prow, nrow, CHA_OFFSET, CH_WIDTH); | |||||
histogramEqualise(prow, nrow, CHB_OFFSET, CH_WIDTH); | |||||
} | |||||
// Layered | // Layered | ||||
if (CONTAINS(imgopt, 'l')){ | if (CONTAINS(imgopt, 'l')){ | ||||
if(chA == 1){ | if(chA == 1){ | ||||