ROPO
Loading...
Searching...
No Matches
fmi_radar_image.c
1
22#include <stdio.h>
23#include <math.h>
24#include <limits.h>
25#include <stdlib.h>
26#include "fmi_util.h"
27#include "fmi_image.h"
28#include "fmi_image_arith.h"
29#include "fmi_image_filter.h"
30#include "fmi_image_filter_morpho.h"
31#include "fmi_image_filter_line.h"
32#include "fmi_image_histogram.h"
33#include "fmi_image_filter_speck.h"
34#include "fmi_meteosat.h"
35#include "fmi_radar_image.h"
36#include "rave_alloc.h"
37
38
39float fmi_radar_sweep_angles[FMI_RADAR_SWEEP_COUNT]={0.5, 1.5, 2.5, 3.5, 4.5, 6.0, 8.0, 11.0, 20.0, 45.0};
40float fmi_radar_bin_depth = 0.0;
41
42#define RGBCOUNT 14
43int dbz_rgb[RGBCOUNT][4]={
44 {-30, 0, 0, 0},
45 {-20, 0, 0,128},
46 {-10, 0, 0,192},
47 { -5, 0, 96,255},
48 { 0, 0,160, 92},
49 { 10, 64,255, 0},
50 { 20, 192,192, 0},
51 { 30, 224,160, 0},
52 { 40, 255,128, 0},
53 { 50, 255, 64, 0},
54 { 60, 255, 32, 64},
55 { 70, 255, 0,128},
56 { 80, 255, 0,192},
57 { 90, 255, 0,255}
58};
59
60void
61setup_context(FmiImage * source)
62{
63 fmi_radar_bin_depth = source->bin_depth;
64}
65
66int abs_dbz_to_byte(Dbz dbz){
67 int g;
68 g=dbz*2+64;
69 if (g<0) g=0;
70 if (g>255) g=255;
71 return (g);
72}
73
74int rel_dbz_to_byte(Dbz dbz){
75 int g;
76 g=dbz*2;
77 if (g<0) g=0;
78 if (g>255) g=255;
79 return g;
80}
81
82int abs_dbz_to_int(Dbz dbz){
83 return(dbz*2+64);
84}
85
86int rel_dbz_to_int(Dbz dbz){
87 return(dbz*2);
88}
89
90
91
92int byte_to_abs_dbz(Byte byte){
93 return ((byte-64)/2);
94}
95
96int byte_to_rel_dbz(Byte byte){
97 return (byte/2);
98}
99
100float radians_to_degree(float radians){ return (radians*360.0/(2.0*PI));}
101float degrees_to_radian(float degrees){ return (degrees*2.0*PI/360.0);}
102
103int bin_to_metre(int bin){
104 return ((1+2*bin) * fmi_radar_bin_depth/2);
105 /* = (0.5+bin) * fmi_radar_bin_depth */
106}
107
108int metre_to_bin(int metre){
109 return(metre/fmi_radar_bin_depth);
110}
111
112int bin_to_altitude(int sweep_bin,float sweep_angle){
113 /* const float b=(0.5+(float)sweep_bin)*fmi_radar_bin_depth; */
114 const float b=bin_to_metre(sweep_bin);
115 const float a=EARTH_RADIUS43;
116 /* by cosine rule */
117 return (int)sqrt(b*b+a*a-2.0*a*b*cos(PI/2.0+degrees_to_radian(sweep_angle)))-EARTH_RADIUS43;
118}
119
120int altitude_to_bin(int altitude,float sweep_angle){
121 const float c=EARTH_RADIUS43+altitude;
122 const float a=EARTH_RADIUS43;
123 const float gamma=degrees_to_radian(sweep_angle)+PI/2.0;
124 const float beta=PI-gamma-asin(a*sin(gamma)/c);
125 /* by sine rule */
126 /* sin(gamma)/c = sin(beta)/b => b=sin(beta)*c/sin(gamma) */
127 return (sin(beta)*c/sin(gamma)/fmi_radar_bin_depth);
128}
129
130int ground_to_bin(int g_metre,float sweep_angle){
131 float beta; /* angle<RADAR,GROUND_POINT> */
132 float gamma; /* angle<BIN_RADAR,BIN_GROUND_POINT> */
133 beta=(float)g_metre/(float)EARTH_RADIUS43;
134 gamma=PI-degrees_to_radian(sweep_angle)-PI/2.0-beta;
135 /* printf("...%f\n",sweep_angle); */
136 /* SINE RULE */
137 /* sin(beta)/BIN = sin(gamma) / EARTH_RADIUS */
138 return (int)(sin(beta)/sin(gamma)*(float)EARTH_RADIUS43/fmi_radar_bin_depth);
139 /* return (int)(2.0*sweep_angle); */
140}
141
142int bin_to_ground(int bin,float sweep_angle){
143 float x,y;
144 const float m=bin_to_metre(bin);
145 const float chi=degrees_to_radian(sweep_angle);
146 x=m*cos(chi);
147 y=m*sin(chi);
148 return (EARTH_RADIUS43*atan(x/(y+(float)EARTH_RADIUS43)));
149 /* COSINE RULE? */
150}
151
152int bin_to_bin(int sweep_bin,float sweep_angle,float target_sweep_angle){
153 return ground_to_bin( bin_to_ground(sweep_bin,sweep_angle), target_sweep_angle);
154}
155
156void xy_to_polar(int i,int j,int *theta,int *radius){
157 /* const int radius=250; */
158 i=(i-250)*2;
159 j=(j-250)*2;
160 *radius=(int)sqrt((double)i*i+j*j);
161 *theta=180*atan2(i,-j)/3.14;
162 if (*theta<0)
163 *theta+=360;
164}
165
166void volume_to_cappi(FmiImage *volume,int height,FmiImage *cappi){
167 int i,j,k;
168 /* VERTICAL INTERPOLATION SCHEME */
169 int channels = volume->channels;
170 int *bin;
171 Byte b,b_upper,b_lower;
172 /* const Byte PSEUDOCAPPI_MARKER=31; */
173 const Byte PSEUDOCAPPI_MARKER=1;
174 /* sweep indices */
175 int upper,lower;
176 int h,h_upper,h_lower;
177 int mix;
178
179 bin = (int *)RAVE_MALLOC(sizeof(int) * volume->sweep_count);
180
181 /* assumption: max area = area of lowest ppi */
182 /*
183 Can't work with variable ray counts.
184 Actually, that shouldn't be channels, should it ?
185
186 martin.raspaud@NOSPAM.smhi.se, Fri Aug 5 11:04:42 2011.
187 if (volume->channels==1){
188 fmi_debug(0,"warning: computing CAPPI of only one PPI?");
189 channels=volume->channels;
190 split_to_channels(volume,volume->height/FMI_RADAR_RAY_COUNT);
191 }
192 */
193 setup_context(volume);
194
195 canonize_image(&volume[1],cappi);
196 for (i=0;i<cappi->width;i++){
197 upper=-1;
198 lower=-1;
199 h_upper=INT_MAX;
200 h_lower=0;
201 for (k=0;k<volume->channels;k++){
202 bin[k]=ground_to_bin(i*fmi_radar_bin_depth,volume[k+1].elevation_angle);
203 if (bin[k]>=volume->width)
204 bin[k]=volume->width-1;
205 h=bin_to_altitude(bin[k],volume[k+1].elevation_angle);
206 if ((h<=height)&&(h>=h_lower)){
207 lower=k;
208 h_lower=h;
209 }
210 if ((h>=height)&&(h<=h_upper)){
211 upper=k;
212 h_upper=h;
213 }
214 }
215
216 if (FMI_DEBUG(5))
217 fprintf(stderr,"lower(%d)=%dm [%d]\t upper(%d)=%dm [%d]\n",lower,h_lower,bin[lower],upper,h_upper,bin[upper]);
218
219
220 if (upper==-1) {
221 /* NO UPPER SWEEP AVAILABLE */
222 for (j=0;j<cappi->height;j++){
223 b=get_pixel(volume,bin[lower],j,lower);
224 b=b&~PSEUDOCAPPI_MARKER;
225 put_pixel(cappi,i,j,0,b);
226 }
227 } else if (lower==-1) {
228 /* NO LOWER SWEEP AVAILABLE */
229 for (j=0;j<cappi->height;j++){
230 b=get_pixel(volume,bin[upper],j,upper);
231 b=b&~PSEUDOCAPPI_MARKER;
232 /* b=(i*255)/cappi->width; */
233 put_pixel(cappi,i,j,0,b);
234 }
235 } else {
236 /* OK - BETWEEN TWO SWEEPS */
237 mix=(255*(height-h_lower))/(h_upper-h_lower);
238 if (mix>255) mix=255;
239 if (mix<0) mix=0;
240 for (j=0;j<cappi->height;j++) {
241 b_lower=get_pixel(volume,bin[lower],j,lower);
242 b_upper=get_pixel(volume,bin[upper],j,upper);
243 b=(mix*b_upper+(255-mix)*b_lower)/255;
244 b=b | PSEUDOCAPPI_MARKER;
245 /* b=128; */
246 put_pixel(cappi,i,j,0,b);
247 }
248 }
249 }
250 split_to_channels(volume,channels);
251 RAVE_FREE(bin);
252}
253
254void dump_sweep_info(void){
255 int i,j;
256 float beta;
257 int b,alt;
258 for (j=0;j<FMI_RADAR_SWEEP_COUNT;j++){
259 printf("#[%d]",j);
260 printf("\t%3.1f\t",fmi_radar_sweep_angles[j]);
261 }
262 printf("\n");
263 for (i=0;i<250000;i+=100){
264 printf("%d",i);
265 for (j=0;j<FMI_RADAR_SWEEP_COUNT;j++){
266 beta=fmi_radar_sweep_angles[j];
267 /* printf("\t[%.1f]%d",fmi_radar_sweep_angles[j],ground_to_bin(i,fmi_radar_sweep_angles[j])); */
268 b=ground_to_bin(i,beta);
269 b=MIN(b,FMI_RADAR_BIN_COUNT);
270 printf("\t%3d",b);
271 alt=bin_to_altitude(b,beta);
272 printf("%7d",alt);
273 }
274 /* printf("\t ppi0:'%d' ppi45 %d",i/500,bin_to_bin(i/500,fmi_radar_sweep_angles[0],fmi_radar_sweep_angles[FMI_RADAR_SWEEP_COUNT-1])); */
275 /* printf("\t alt=%d",bin_altitude(ground_to_bin(i,45),45)); */
276 printf("\n");
277 }
278 /*fprintf(stderr,"plot ",i); */
279 fprintf(stderr,"plot ");
280 for (j=0;j<FMI_RADAR_SWEEP_COUNT;j++)
281 fprintf(stderr,"\\\n'sweep.dat' using 1:%d title \"%.1f�\",",2*j+3,fmi_radar_sweep_angles[j]);
282 fprintf(stderr,"\b \n");
283
284}
285
286
287/* enhances invidual responses on lines with large total response */
288void enhance_horz(FmiImage *trace){
289 register int i, j, k;
290 int m, c;
291 int *n;
292 n = (int*) RAVE_MALLOC(trace->height*sizeof(int));
293 /* int m[trace->height]; */
294 for (k = 0; k < trace->channels; k++) {
295 for (j = 0; j < trace->height; j++) {
296 n[j] = 0;
297 for (i = 0; i < trace->width; i++) {
298 if (get_pixel(trace, i, j, k) > 0)
299 n[j]++;
300 }
301 /*n[j]=MIN(n[j],trace->width); */
302 /* n[j]=MAX(n[j],0); */
303 }
304 for (j = 0; j < trace->height; j++) {
305 m = (n[(j - 1) % trace->height] + 2 * n[j] + n[(j + 1) % trace->height])
306 / 4;
307 m = MAX(m,n[j]);
308 for (i = 0; i < trace->width; i++) {
309 /* put_pixel(trace,i,j,k,255); */
310 c = get_pixel(trace, i, j, k) * m / trace->width;
311 c = MIN(c,255);
312 put_pixel(trace, i, j, k, c);
313 }
314 }
315 }
316 RAVE_FREE(n);
317}
318
319void enhance_horz255(FmiImage *trace,Byte row_statistic[]){
320 register int i,j;
321 register int c,s;
322
323 for (j=0;j<trace->height;j++){
324 s=row_statistic[j];
325 for (i=0;i<trace->width;i++){
326 c=get_pixel(trace,i,j,0)*s/255;
327 put_pixel(trace,i,j,0,c);
328 }
329 }
330}
331
332/* REMOVE DISTINCT HORIZONTAL LINES ??? */
333/* detect pixels brighter than neighborhood */
334/* compute lengths of detected segments, store as segment intesities */
335/* replace segments longer than max_length pixels with neighborhood mean */
336
337
338/* FUZZY PRODUCT OF vert AND horz lengths; VERT CUT FIRST! */
339void detect_horz_segments(FmiImage *source,FmiImage *trace,int max_width,int min_length){
340 /* register int i,j; */
341 /* int min_length=60; */
342 FmiImage horz;
343 FmiImage vert;
344
345 init_new_image(&horz);
346 init_new_image(&vert);
347
348 canonize_image(source,trace);
349 canonize_image(source,&horz);
350 canonize_image(source,&vert);
351
352 /* threshold_image(source,trace,min_intensity); */
353
354 /* COMPUTE VERTICAL RUN LENGTHS; SCALE */
355 vert_seg_lengths(source,&vert);
356 semisigmoid_image_inv(&vert,max_width);
357 translate_intensity(&vert,255,0);
358 threshold_image(&vert,trace,32);
359 threshold_image(&vert,&vert,96);
360
361 if (FMI_DEBUG(5)) write_image("debug_horz_segments_vert",&vert,PGM_RAW);
362
363 /* COMPUTE VERTICAL RUN LENGTHS; SCALE */
364 horz_seg_lengths(&vert,&horz);
365 /* semisigmoid_image(&horz,min_length); */
366 sigmoid_image(&horz,min_length,1);
367
368 /* multiply_image255_sigmoid(&vert,&horz,trace); */
369 multiply_image255_sigmoid(trace,&horz,trace);
370
371 reset_image(&horz);
372 reset_image(&vert);
373 if (FMI_DEBUG(5)) write_image("debug_horz_segments",trace,PGM_RAW);
374}
375
376
377/* UNITY-WIDTH SEGMENTS */
378/* CLIENTS: detect_emitters2 */
379void detect_emitters(FmiImage *source,FmiImage *trace,int min_elevation,int min_length){
380
381 canonize_image(source,trace);
382
383 /* FIND VERT MAXIMA... */
384 /* DEBUG threshold_image(source,trace,min_elevation); */
385 /*detect_vert_maxima(source,trace); */
386
387
388 detect_vert_maxima(source,trace);
389 /*put_pixel(trace,20,20,0,200); */
390 threshold_image(trace,trace,min_elevation);
391 if (FMI_DEBUG(5)) write_image("debug_emitter_1_vert_max",trace,PGM_RAW);
392
393 /* ... AND COMPUTE HORZ LENGTHS */
394 horz_seg_lengths(trace,trace);
395 threshold_image(trace,trace,min_length-1);
396 semisigmoid_image(trace,min_length);
397
398 if (FMI_DEBUG(4)) write_image("debug_emitter",trace,PGM_RAW);
399
400}
401
402void detect_emitters2(FmiImage *source,FmiImage *trace,int min_intensity,int min_length,int max_width){
403 /*register int i,j; */
404
405 /* FmiImage unity_width_segments; */
406 FmiImage candidate;
407 FmiImage mask,mask2;
408 /* FILE *fp; // debug */
409 FmiImage temp;
410 init_new_image(&candidate);
411 init_new_image(&mask);
412 init_new_image(&mask2);
413 init_new_image(&temp);
414
415 canonize_image(source,&temp);
416 canonize_image(source,trace);
417 canonize_image(source,&candidate);
418
419 initialize_vert_stripe(&mask,source->height);
420 initialize_vert_stripe(&mask2,source->height);
421
422 /* canonize_image(source,&vert); */
423
424 /* PHASE 1: marginal (ray) sums of unity-width segments */
425 /*
426 detect_vert_maxima(source,&temp); // unity-width segments
427 threshold_image(&temp,&temp,2); // ROBUST ANYWAY
428 if (FMI_DEBUG(4)) write_image("debug_emitter_1_seg1",&temp,PGM_RAW);
429 horz_seg_lengths(&temp,&temp);
430 threshold_image(&temp,&temp,min_length-1);
431 semisigmoid_image(&temp,min_length);
432 if (FMI_DEBUG(5)) write_image("debug_emitter_2_seg2",&temp,PGM_RAW);
433 */
434
435 /* COMPUTE UNITY-WIDTH SEGMENTS... */
436 detect_emitters(source,&temp,min_intensity/2,min_length/2);
437 /* ...TO BE USED AS TENTATIVE EVIDENCE. */
438 image_average_horz(&temp,&mask);
439 pipeline_process(&mask ,&mask2,0,1,histogram_max);
440 pipeline_process(&mask2,&mask ,0,1,histogram_mean);
441 /*semisigmoid_image(&mask,32); */
442 sigmoid_image(&mask,16,2);
443 if (FMI_DEBUG(5)) write_image("debug_emitter2_3_stripe",&mask,PGM_RAW);
444
445 /* PHASE 2: calculate candidates by rigid vert x horz probing */
446 /* copy_image(source,trace); */
447 /*
448 threshold_image(source,trace,min_intensity);
449
450 vert_seg_lengths(trace,&temp);
451 translate_intensity(&temp,0,255);
452 sigmoid_image(&temp,max_width,-1);
453 threshold_image(&temp,&temp,64);
454 if (FMI_DEBUG(4)) write_image("debug_emitter_4_vert_run",&temp,PGM_RAW);
455
456 horz_seg_lengths(&temp,&candidate);
457 sigmoid_image(&candidate,min_length,2);
458 threshold_image(&candidate,&candidate,64);
459 if (FMI_DEBUG(4)) write_image("debug_emitter_5_horzrun",&candidate,PGM_RAW);
460 */
461
462 /* THEN, DETECT HORIZONTAL SEGMENTS... */
463 threshold_image(source,&temp,min_intensity); /* seems: was needed */
464 detect_horz_segments(&temp,&candidate,max_width,min_length);
465 threshold_image(&candidate,trace,16);
466 /* pipeline_process(&candidate,&temp,4,1,histogram_max); */
467 /* pipeline_process(&temp,trace,3,1,histogram_mean); */
468 /* pipeline_process(&temp,trace,4,1,histogram_max); */
469 if (FMI_DEBUG(5)) write_image("debug_emitter2_6_raw",trace,PGM_RAW);
470
471 /* PHASE 3: weight PHASE 2 image by rowsum obtained in PHASE 1 */
472 /*enhance_horz255(trace,row_nonzero); */
473 multiply_image255_flex(trace,&mask,trace);
474 semisigmoid_image(trace,32); /* 16 */
475
476 reset_image(&candidate);
477 reset_image(&mask);
478 reset_image(&mask2);
479 reset_image(&temp);
480
481 if (FMI_DEBUG(4)) write_image("debug_emitter2",trace,PGM_RAW);
482}
483
484
485/*----------------- */
486
487void smooth_signal(Byte signal[],int length){
488 register int i;
489 Byte *signal2;
490 signal2=(Byte*)RAVE_MALLOC(sizeof(Byte)*length);
491 for (i=0;i<length;i++)
492 signal2[i]=(signal[(i-1)%length] + 2*signal[i] +signal[(i+1)%length])/4;
493 for (i=0;i<length;i++)
494 signal[i]=MAX(signal[i],signal2[i]);
495 RAVE_FREE(signal2);
496}
497
498void detect_emitters2old(FmiImage *source,FmiImage *trace,int min_intensity,int min_length,int max_width){
499 register int i,j;
500 Byte *row_nonzero;
501 Byte *row_avg;
502 Byte *row_pow;
503 /* FmiImage unity_width_segments; */
504 FmiImage candidate;
505 FILE *fp; /* debug */
506 FmiImage temp;
507
508 row_nonzero=(Byte*)RAVE_MALLOC(sizeof(Byte)*source->height);
509 row_avg=(Byte*)RAVE_MALLOC(sizeof(Byte)*source->height);
510 row_pow=(Byte*)RAVE_MALLOC(sizeof(Byte)*source->height);
511
512 init_new_image(&candidate);
513 init_new_image(&temp);
514
515 canonize_image(source,&temp);
516 canonize_image(source,trace);
517 canonize_image(source,&candidate);
518 /* canonize_image(source,&vert); */
519
520 /* PHASE 1: marginal (ray) sums of unity-width segments */
521 detect_vert_maxima2(source,&temp); /* unity-width segments */
522 threshold_image(&temp,&temp,2); /* ROBUST ANYWAY */
523 if (FMI_DEBUG(4)) write_image("debug_emitter_seg1",&temp,PGM_RAW);
524 /* no intensity-min_length compensation -> box logic: */
525 horz_seg_lengths(&temp,&temp);
526 sigmoid_image(&temp,min_length,1);
527 threshold_image(&temp,&temp,126);
528 if (FMI_DEBUG(5)) write_image("debug_emitter_seg2",&temp,PGM_RAW);
529 row_statistics(&temp,row_nonzero,row_avg,row_pow);
530 for (i=0;i<trace->height;i++){
531 /* if (row_nonzero[i]<16) row_nonzero[i]=0; */
532 j=128+pseudo_sigmoid(1,((int)row_nonzero[i])-16); /* =16/255 *100% */
533 j=MAX(j,0);
534 j=MIN(j,255);
535 /* if (row_nonzero[i]<16) j=0; */
536 row_nonzero[i]=j;}
537 /* for (i=0;i<32;i+=1) printf("%d\t%d\n",i,128+pseudo_sigmoid(1,i-16)/2); */
538 smooth_signal(row_nonzero,trace->height);
539 if (FMI_DEBUG(5)) {
540 fp=fopen("row_stats.txt","w");
541 for (j=0;j<temp.height;j++){
542 fprintf(fp,"%d\t%d\t%d\n",row_nonzero[j],row_avg[j],row_pow[j]);
543 put_pixel(&temp,row_nonzero[j],j,0,255);
544 put_pixel(&temp,row_avg[j],j,0,254);
545 put_pixel(&temp,sqrt(row_pow[j]),j,0,253);
546 }
547 fclose(fp);
548 }
549 if (FMI_DEBUG(4)) write_image("debug_emitter_horz_spread",&temp,PGM_RAW);
550
551 /* PHASE 2: calculate candidates by rigid vert x horz probing */
552 copy_image(source,trace);
553 threshold_image(trace,trace,min_intensity);
554
555 vert_seg_lengths(trace,&temp);
556 translate_intensity(&temp,0,255);
557 sigmoid_image(&temp,max_width,-1);
558 threshold_image(&temp,&temp,64);
559 if (FMI_DEBUG(4)) write_image("debug_emitter_vert_run",&temp,PGM_RAW);
560
561 horz_seg_lengths(&temp,&candidate);
562 sigmoid_image(&candidate,min_length,2);
563 threshold_image(&candidate,&candidate,64);
564 if (FMI_DEBUG(4)) write_image("debug_emitter_horz_run",&candidate,PGM_RAW);
565
566 pipeline_process(&candidate,&temp,5,1,histogram_max);
567 pipeline_process(&temp,trace,3,1,histogram_mean);
568 if (FMI_DEBUG(4)) write_image("debug_emitter_trace",trace,PGM_RAW);
569
570 /* PHASE 3: weight PHASE 2 image by rowsum obtained in PHASE 1 */
571 enhance_horz255(trace,row_nonzero);
572 semisigmoid_image(trace,32); /* 16 */
573
574 if (FMI_DEBUG(4)) write_image("debug_emitter_trace_enh",trace,PGM_RAW);
575
576 reset_image(&temp);
577 reset_image(&candidate);
578
579 RAVE_FREE(row_pow);
580 RAVE_FREE(row_avg);
581 RAVE_FREE(row_nonzero);
582}
583
584/*----------------- */
585
586
587
588void detect_sun(FmiImage *source,FmiImage *trace,int min_intensity,int max_width,int min_total_length){
589 /* FmiImage mask; */
590 const int closing_dist=4;
591 const int min_seg_length=4;
592
593 canonize_image(source,trace);
594 /* initialize_vert_stripe(&mask,source->height); */
595
596 /* */
597 threshold_image(source,trace,min_intensity);
598 morph_closing(trace,trace,closing_dist,0);
599 detect_horz_segments(trace,trace,max_width,min_seg_length);
600
601 horz_seg_lengths(trace,trace);
602 /* if (FMI_DEBUG(4)) write_image("debug_sun_length",trace,PGM_RAW); */
603 sigmoid_image(trace,min_total_length,4);
604 /* if (FMI_DEBUG(4)) write_image("debug_sun_length2",trace,PGM_RAW); */
605
606 /* IF YOU USE THIS, CLEAR-SKY NORMALIZE THIS!
607 image_average_horz(trace,&mask);
608 multiply_image255_flex(trace,&mask,trace);
609 */
610 /* threshold_image(trace,trace,64); */
611 if (FMI_DEBUG(4)) write_image("debug_sun",trace,PGM_RAW);
612
613}
614
615
616void detect_sun2(FmiImage *source,FmiImage *trace,int min_intensity,int max_width,int min_total_length,int azimuth,int elevation){
617 register int j,mj=source->height/2;
618 FmiImage mask;
619 const int closing_dist=4;
620 /*const int min_seg_length=4; */
621
622 fmi_debug(2,"sun2");
623
624 init_new_image(&mask);
625
626 canonize_image(source,trace);
627
628 if ((elevation<-2)||(elevation>20)) {
629 fill_image(trace,0);
630 return;
631 }
632
633 /* detect_sun(source,trace,min_intensity,min_length,max_width); */
634 threshold_image(source,trace,min_intensity);
635 morph_closing(trace,trace,closing_dist,0);
636 if (FMI_DEBUG(5)) write_image("debug_sun1",trace,PGM_RAW);
637 detect_horz_segments(trace,trace,max_width,min_total_length);
638 if (FMI_DEBUG(5)) write_image("debug_sun2",trace,PGM_RAW);
639 /*morph_closing(trace,trace,closing_dist,0); */
640 /* fmi_debug(5,"debug_sun_4"); */
641
642 initialize_vert_stripe(&mask,source->height);
643 for (j=0;j<source->height;j++){
644 put_pixel_direct(&mask,(j+mj+azimuth)%source->height,pseudo_gauss_int(max_width,j-mj));
645 /* put_pixel(trace,0,(j+mj+azimuth)%source->height,0,pseudo_gauss_int(width,j-mj)); */
646 }
647 if (FMI_DEBUG(5)) write_image("debug_sun3",&mask,PGM_RAW);
648 /* fmi_debug(5,"debug_sun_4"); */
649 multiply_image255_flex(trace,&mask,trace);
650
651 RAVE_FREE(mask.array);
652
653 if (FMI_DEBUG(4)) write_image("debug_sun",trace,PGM_RAW);
654 /* fmi_debug(2,"sun2"); */
655}
656
657/*
658 BASIC IDEA
659 - Detect specks, of which size < "max_area" and intensity > "min_intensity"
660 - SPECK must be pronounced, not just thresholded
661*/
662void detect_ships(FmiImage *source,FmiImage *prob,int min_intensity,int max_area){
663 /* register int i; */
664 int max_radius;
665 /* FmiImage trace; */
666 /* FmiImage trace; */
667 /*FmiImage trace4; */
668
669 FmiImage temp1;
670 FmiImage temp2;
671 /* FmiImage temp3; */
672 FmiImage specks;
673 FmiImage virtual;
674 FmiImage lines;
675
676 max_radius=sqrt(max_area)/2;
677
678 init_new_image(&temp1);
679 init_new_image(&temp2);
680 init_new_image(&specks);
681 init_new_image(&virtual);
682 init_new_image(&lines);
683
684 canonize_image(source,&temp1);
685 fmi_debug(2,"--------------");
686 if (FMI_DEBUG(2)) image_info(&temp1);
687 fmi_debug(2,"==============");
688
689 canonize_image(source,&temp2);
690 /* image_info(&temp2); */
691 /* canonize_image(source,&temp3); */
692 canonize_image(source,&specks);
693 canonize_image(source,&virtual);
694 canonize_image(source,&lines);
695
696 /* fmi_debug(2,"--------------"); */
697 /*
698 image_info(&temp1);
699 image_info(&temp2);
700 image_info(&specks);
701 image_info(&virtual);
702 image_info(&lines);
703 */
704 fmi_debug(2,"remove ships2");
705
706 /* high-boost filter for detecting specks */
707 pipeline_process(source,&temp1,max_radius+2,max_radius+2,histogram_mean);
708 subtract_image(source,&temp1,&specks);
709 threshold_image(&specks,&specks,min_intensity);
710 if (FMI_DEBUG(5)) write_image("debug_ship_speck1",&specks,PGM_RAW);
711
712 /* cut off short segments */
713 propagate_right(&specks,&specks,&specks,-16,put_pixel);
714 propagate_left(&specks,&specks,&specks,0,put_pixel_min);
715 threshold_image(&specks,&specks,min_intensity/2);
716 if (FMI_DEBUG(4)) write_image("debug_ship_speck2",&specks,PGM_RAW);
717
718 /* create virtual echoes (= locations of possible sidelobe echoes) */
719 iir_up(&specks,&temp1,975);
720 iir_down(&specks,&temp2,975);
721 max_image(&temp1,&temp2,&virtual);
722 if (FMI_DEBUG(4)) write_image("debug_ship_virtual",&virtual,PGM_RAW);
723
724
725 /* detect possible sidelobe echoes in data */
726 /* edges */
727 detect_vert_edges(source,&temp1);
728 threshold_image(&temp1,&temp1,8);
729 /* emphasize long segments, prune short segments */
730 propagate_up(NULL,&temp1,&temp2,1*8,put_pixel);
731 propagate_down(&temp2,&temp2,&lines,0,put_pixel);
732 threshold_image(&lines,&lines,2*8);
733 if (FMI_DEBUG(3)) write_image("debug_ship_edges",&lines,PGM_RAW);
734
735 /* detect suspicious segments = connect HORZ segments */
736 pipeline_process(source,&temp2,1,0,histogram_max);
737 pipeline_process(&temp2,&temp1,1,0,histogram_min);
738 if (FMI_DEBUG(4)) write_image("debug_ship_edges2",&temp1,PGM_RAW);
739 propagate_right(NULL,&temp1,&temp2,1,put_pixel);
740 propagate_left(&temp2,&temp2,&temp1,0,put_pixel);
741 if (FMI_DEBUG(4)) write_image("debug_ship_edges3",&temp1,PGM_RAW);
742
743 /* here we get the "real" sidelobes */
744 subtract_image(&lines,&temp1,&lines);
745 pipeline_process(&lines,&temp1,0,1,histogram_max);
746 pipeline_process(&temp1,&lines,0,2,histogram_mean);
747 if (FMI_DEBUG(4)) write_image("debug_ship_edges4",&lines,PGM_RAW);
748
749 /* multiply_image(&lines,&virtual,&lines); */
750 min_image(&lines,&virtual,&lines);
751 if (FMI_DEBUG(3)) write_image("debug_ship_edges5",&lines,PGM_RAW);
752
753 /* combine ships and their sidelobes */
754 max_image(&specks,&lines,prob);
755
756 pipeline_process(prob,&temp1,1,2,histogram_mean); /* smooth a bit */
757 average_images(prob,&temp1,prob);
758 multiply_image_scalar255(prob,768);
759 /* if (FMI_DEBUG(3)) write_image("ships",prob,PGM_RAW); */
760
761 /* reset_image(&trace); */
762 fmi_debug(2,"remove ships2: reset temp1");
763 fmi_debug(2,"--------------");
764 if (FMI_DEBUG(2)) image_info(&temp1);
765 fmi_debug(2,"==============");
766 reset_image(&temp1);
767 fmi_debug(2,"remove ships2: reset temp2");
768 reset_image(&temp2);
769 fmi_debug(2,"remove ships2: reset specks1");
770 reset_image(&specks);
771 reset_image(&virtual);
772 reset_image(&lines);
773}
774
775
776void detect_doppler_anomaly(FmiImage *source,FmiImage *target,int width, int height,int threshold){
777 /* peura hack 10.12.2002:�gaussian - ADDS PASSIVE ARE NEAR ZERO */
778 /* histogram_threshold=threshold; */
779 histogram_threshold=128;
780 pipeline_process(source,target,width,height,histogram_variance_rot);
781 sigmoid_image(target,threshold,threshold/16);
782 /*invert_image(target); */
783 if (FMI_DEBUG(4)) write_image("debug_doppler",target,PGM_RAW);
784 /*pipeline_process(source,target,1,1,histogram_mean); */
785}
786
787
788/* NEW! */
789void detect_ground_echo_minnetgrad(FmiImage *source, int ppi_count,
790 FmiImage *prob, int gradT, int altT)
791{
792 register int i, j;
793 /*register int h,l; */
794 register int l;
795 int grad; /*,alt_delta,alt_m; */
796 /*const int altMAX=altT*3; */
797 const int gradD = ABS(gradT);
798 const int image_height = source[0].height;
799 const int image_width = source[0].width;
800 /* int g_max,g_max_alt,g_span_max; */
801 int g; /* current gray level */
802 int altD; /* altitude difference */
803 int altM; /* altitude mean */
804 /* int p,p_min; */
805 int p; /* prob of this */
806 int p_max; /* max prob obtained */
807 int pGRAD; /* prob according to current grad */
808 int pALT; /* prob according to current (grad-halfway) altitude */
809 int g_min; /* minimum intensity obtained (before this) */
810 int pGRADmax = 0; /* for debug images */
811
812 FmiImage debug_grad_raw, debug_grad;
813 FmiImage median0;
814 float *altitude;
815 int *bin;
816
817 altitude = (float *) RAVE_MALLOC(source->width * sizeof(float));
818 bin = (int *) RAVE_MALLOC(source->width * sizeof(int));
819
820 init_new_image(&debug_grad_raw);
821 init_new_image(&debug_grad);
822 init_new_image(&median0);
823
824 setup_context(source);
825
826 fmi_debug(2, "detect_ground_echo");
827
828 canonize_image(&source[0], prob);
829 fill_image(prob, 0);
830
831 canonize_image(&source[0], &median0);
832 /* histogram_sample_count=(5*3)*3/4; */
833 histogram_sample_count = 3;
834 pipeline_process(&source[0], &median0, 1, 1, histogram_median2);
835
836 if (FMI_DEBUG(5)) {
837 canonize_image(&source[0], &debug_grad_raw);
838 fill_image(&debug_grad_raw, 0);
839 canonize_image(&source[0], &debug_grad);
840 fill_image(&debug_grad, 0);
841 }
842
843 if (FMI_DEBUG(3))
844 fprintf(stderr, " intensity_grad %.2d per 1000m, half_altitude %d \n",
845 gradT, altT);
846
847 /* traverse image, one cirle at the time */
848 for (i = 0; i < image_width; i++) {
849 /* save BIN INDICES and ALTITUDES to array */
850 for (l = 0; l < ppi_count; l++) {
851 bin[l] = bin_to_bin(i, source[1].elevation_angle,
852 source[l + 1].elevation_angle);
853 altitude[l] = bin_to_altitude(i, source[l + 1].elevation_angle);
854 }
855 /* traverse one circular sweep */
856 for (j = 0; j < image_height; j++) {
857 /*g_max=-1000; */
858 /* g_span_max=-1000; */
859 /*g_max_alt=-1000; */
860 /* */
861 p_max = 0;
862 /* g_min=get_pixel(&source[0],i,j,0); */
863 g_min = get_pixel(&median0, i, j, 0);
864 if (FMI_DEBUG(5))
865 pGRADmax = 0;
866 for (l = 1; l < ppi_count; l++) {
867 if (g_min == 0)
868 break;
869 /* RAW INTENSITY */
870 g = get_pixel(&source[l], i, j, 0);
871 if (g == NO_DATA)
872 break;
873 altD = altitude[l] - altitude[l - 1] + 100; /* STABILITY TRICK */
874 altM = (altitude[l] + altitude[l - 1]) / 2;
875 /* if (altD==0) altD==100; // WARNING? */
876
877 grad = (1000 * (g - g_min)) / altD;
878
879 pGRAD = 128 + pseudo_sigmoid(gradD, -(grad - gradT)) / 2;
880
881 if (FMI_DEBUG(5))
882 if (pGRAD > pGRADmax)
883 pGRADmax = pGRAD;
884
885 /* fuzzify by altitude (255 at 0m, 128 at half-m) */
886 pALT = 128 - pseudo_sigmoid(altD, altM - altT) / 2;
887
888 p = pGRAD * pALT / 256;
889 if (p < 24)
890 p = 0;
891
892 if (p > p_max)
893 p_max = p;
894 if (g < g_min)
895 g_min = g;
896 }
897 if (FMI_DEBUG(5)) {
898 put_pixel_max(&debug_grad_raw, i, j, 0, pGRADmax);
899 put_pixel_max(&debug_grad, i, j, 0, p_max);
900 /*if (p>get_pixel(prob,i,j,0)) */
901 /* put_pixel(&debug,i,j,0,16*h+l); */
902 }
903
904 put_pixel_max(prob, i, j, 0, p_max);
905 }
906 }
907 if (FMI_DEBUG(5)) {
908 write_image("debug_ground_1grad_raw", &debug_grad_raw, PGM_RAW);
909 write_image("debug_ground_2grad", &debug_grad, PGM_RAW);
910 write_image("debug_ground_3grad", prob, PGM_RAW);
911 }
912 RAVE_FREE(bin);
913 RAVE_FREE(altitude);
914 reset_image(&debug_grad_raw);
915 reset_image(&debug_grad);
916 reset_image(&median0);
917}
918
919void detect_ground_echo_mingrad(FmiImage *source, int ppi_count,
920 FmiImage *prob, int intensity_grad, int half_altitude)
921{
922 register int i, j;
923 register int l; /* h */
924 int grad, alt_delta, alt_m;
925 const int max_altitude = half_altitude * 3;
926 const int half_width = ABS(intensity_grad);
927 const int image_height = source[0].height;
928 const int image_width = source[0].width;
929
930 int p; /*,p_min; */
931 FmiImage debug_grad_raw, debug_grad;
932 float *altitude;
933 int *bin;
934
935 altitude = (float *) RAVE_MALLOC(source->width * sizeof(float));
936 bin = (int *) RAVE_MALLOC(source->width * sizeof(int));
937
938 init_new_image(&debug_grad_raw);
939 init_new_image(&debug_grad);
940
941 setup_context(source);
942
943 fmi_debug(2, "detect_ground_echo");
944
945 canonize_image(&source[0], prob);
946 fill_image(prob, 0);
947
948 if (FMI_DEBUG(5)) {
949 canonize_image(&source[0], &debug_grad_raw);
950 fill_image(&debug_grad_raw, 255);
951 canonize_image(&source[0], &debug_grad);
952 fill_image(&debug_grad, 0);
953 }
954
955 if (FMI_DEBUG(3))
956 fprintf(stderr, " intensity_grad %.2d per 1000m, half_altitude %d \n",
957 intensity_grad, half_altitude);
958
959 for (i = 0; i < image_width; i++) {
960 for (l = 0; l < ppi_count; l++) {
961 bin[l] = bin_to_bin(i, source[1].elevation_angle,
962 source[l + 1].elevation_angle);
963 altitude[l] = bin_to_altitude(i, source[l + 1].elevation_angle);
964 }
965 for (j = 0; j < image_height; j++) {
966 /*
967 grad_min=0;
968 g_max=0;
969 g_span_max=0;
970 g_max_alt=0;
971 */
972 for (l = 0; l < ppi_count - 1; l++) {
973
974 /* RAW INTENSITY */
975 alt_m = (altitude[l + 1] + altitude[l]) / 2;
976
977 if (alt_m > max_altitude)
978 break;
979
980 alt_delta = (altitude[l + 1] - altitude[l]);
981 grad = 1000 * (get_pixel(&source[l + 1], i, j, 0)
982 - get_pixel(&source[l], i, j, 0)) / alt_delta;
983
984 /*
985 if (grad>grad_max)
986 grad_max=grad;
987 if (grad+grad_max<grad_net_min)
988 grad_net_min=grad+grad_max;
989 */
990
991 /* RAW INTENSITY GRADIENT */
992
993 /* fuzzify by gradient (e.g. -10dbz / 1000m => 128b) */
994
995 p = 128 + pseudo_sigmoid(half_width, -(grad - intensity_grad));
996 if (p < 0)
997 p = 0;
998 if (p > 255)
999 p = 255;
1000
1001 if (FMI_DEBUG(5)) {
1002 put_pixel_min(&debug_grad_raw, i, j, 0, 128 + grad);
1003 put_pixel_max(&debug_grad, i, j, 0, p);
1004 /*if (p>get_pixel(prob,i,j,0)) */
1005 /* put_pixel(&debug,i,j,0,16*h+l); */
1006 }
1007
1008 /* fuzzify by altitude (255 at 0m, 128 at half-m) */
1009 p = (pseudo_gauss(half_altitude, alt_m)) * p / 256;
1010 /* put_pixel_max(prob,i,j,0,(p+p_min)/2); */
1011 put_pixel_max(prob, i, j, 0, p);
1012
1013 }
1014 }
1015 }
1016 if (FMI_DEBUG(5)) {
1017 write_image("debug_ground_1grad_raw", &debug_grad_raw, PGM_RAW);
1018 write_image("debug_ground_2grad", &debug_grad, PGM_RAW);
1019 write_image("debug_ground_3grad", prob, PGM_RAW);
1020 }
1021 RAVE_FREE(bin);
1022 RAVE_FREE(altitude);
1023 reset_image(&debug_grad_raw);
1024 reset_image(&debug_grad);
1025}
1026
1027void detect_too_warm(FmiImage *source,FmiImage *prob,FmiImage *meteosat,Celsius c50,Celsius c75,int min_intensity,int min_size){
1028 FmiImage specks;
1029 int b50=celsius_to_meteosatbyte(c50);
1030 int b75=celsius_to_meteosatbyte(c75);
1031
1032 init_new_image(&specks);
1033
1034 canonize_image(source,&specks);
1035 detect_specks(source,&specks,min_intensity,histogram_area);
1036 semisigmoid_image(&specks,min_size);
1037 if (FMI_DEBUG(5)) write_image("debug_warm_specks",&specks,PGM_RAW);
1038
1039 copy_image(meteosat,prob);
1040 sigmoid_image(prob,b50,b75-b50);
1041 /* sigmoid_image(prob,b50,b50-b75); */
1042 if (FMI_DEBUG(5)) write_image("debug_warm_temp",prob,PGM_RAW);
1043
1044 multiply_image255(prob,&specks,prob);
1045 if (FMI_DEBUG(4)) write_image("debug_warm",prob,PGM_RAW);
1046 reset_image(&specks);
1047}
1048
1049void remove_thin_horz_lines(FmiImage *target, int min_elevation, int weight)
1050{
1051 int i, j, k;
1052 /*int gd,gmax; */
1053 unsigned char g1, g2;
1054 int n;
1055 int min_length;
1056 float w;
1057 FmiImage trace;
1058
1059 init_new_image(&trace);
1060
1061 min_length = 10;
1062
1063 weight = 10;
1064 fmi_debug(1, "remove_sun/emitter_lines");
1065 printf("weight=%d \n", weight);
1066
1067 canonize_image(target, &trace);
1068
1069 /* detect_horz_segments(target,&trace,min_length,min_elevation); */
1070 /* fmi_image_filter_line.h : */
1071 detect_horz_line_segments(target, &trace, min_length, min_elevation);
1072
1073 /*printf("n=%d w=%f weight=%d \n",n,w,weight); */
1074 printf("weight=%d \n", weight);
1075
1076 /* fmi_error("remove_emitter_lines?"); */
1077
1078 /* fill_image(trace,0); */
1079 for (k = 0; k < target->channels; k++) {
1080 for (j = 0; j < target->height; j++) {
1081 n = 0;
1082 /* cumulate horz segments */
1083 for (i = 0; i < trace.width; i++) {
1084 if (get_pixel(&trace, i, j, k) > 0)
1085 n++;
1086 }
1087
1088 /* w=weight*((float)n)/(float)trace.width;*/
1089 w = weight * n / trace.width;
1090
1091 /* if (w>1.0) w=1.0; */
1092 /* printf("n=%d w=%f weight=%f \n",n,w,weight); */
1093
1094 /* IR filtering (strengthen lines) */
1095 for (i = 1; i < trace.width; i++) {
1096 g1 = get_pixel(&trace, i, j, k);
1097 g2 = w * (float) get_pixel(&trace, i - 1, j, k);
1098 put_pixel(&trace, i, j, k, MAX(g1,g2));
1099 }
1100 for (i = trace.width - 2; i > 0; i--) {
1101 g1 = get_pixel(&trace, i, j, k);
1102 g2 = w * (float) get_pixel(&trace, i + 1, j, k);
1103 put_pixel(&trace, i, j, k, MAX(g1,g2));
1104 }
1105
1106 /* DELETE / COVER */
1107 for (i = 0; i < trace.width; i++) {
1108 if (get_pixel(&trace, i, j, k) > 2) { /* > CRITICAL_LENGTH */
1109 g1 = get_pixel(target, i, j - 1, k);
1110 g2 = get_pixel(target, i, j + 1, k);
1111 /* put_pixel(target,i,j,k,(g1+g2)/2);} */
1112 put_pixel(target, i, j, k, SUN);
1113 }
1114 /* put_pixel(target,i,j,k,MIN(g1,g2));} */
1115 /*put_pixel(target,i,j,k,255);} */
1116 }
1117
1118 }
1119 }
1120 write_image("lines", &trace, PGM_RAW);
1121 reset_image(&trace);
1122}
1123
1124
1125void enhance_horz_lines2(FmiImage *trace,int weight){
1126 int i,j,k;
1127 int hrad;
1128 int vrad;
1129 int n,count;
1130 /* int n1[trace->height],n2[trace->height]; */
1131 Histogram hist; /*,weights; */
1132 FmiImage trace2;
1133 fmi_debug(3,"enhance_horz_lines2");
1134
1135 init_new_image(&trace2);
1136
1137 /* for (i=0;i<256;i++) histogram_weighted_mean2_weights[i]=i+1; */
1138 for (i=0;i<256;i++) histogram_weights[i]=i+1;
1139
1140 canonize_image(trace,&trace2);
1141 /* copy_image(trace,&trace2); */
1142 pipeline_process(trace,&trace2,4,1,histogram_max);
1143 pipeline_process(&trace2,trace,4,0,histogram_mean);
1144 /* threshold_image(trace,trace,8,0,histogram_max); */
1145
1146 /* histogram_median2_count=(2*hrad+1)*(2*vrad+1)*7/8; */
1147
1148 if (FMI_DEBUG(4)){
1149 fprintf(stderr," **** weight=%d\n",weight);
1150 /*fprintf(stderr," count=%d\n",count); */
1151 }
1152
1153 vrad=1;
1154 hrad=4;
1155 count=(2*hrad+1)*(2*vrad+1) * weight;
1156
1157 for (k=0;k<trace->channels;k++){
1158 for (j=0;j<trace->height;j++){
1159 n=0;
1160 for (i=0;i<trace->width;i++) n+=(get_pixel(trace,i,j,k)>0?1:0);
1161 if (n>5){
1162 histogram_sample_count=count* n/trace->width;
1163 /* RISK 2010 +null */
1164 initialize_histogram(trace,hist,hrad,vrad,0,j,NULL);
1165 for(i=0;i<trace->width;right(trace,hist,hrad,vrad,&i,&j))
1166 put_pixel(&trace2,i,j,k,histogram_median2(hist));}
1167 }
1168 }
1169 copy_image(&trace2,trace);
1170 reset_image(&trace2);
1171}
1172
1173/* enhance by */
1174/* height: hrad */
1175void enhance_vert_lines(FmiImage *trace, int weight)
1176{
1177 int i, j, k;
1178 int hrad;
1179 int vrad;
1180 int n, count;
1181 /* int n1[trace->height],n2[trace->height]; */
1182 Histogram hist; /*,weights; */
1183 FmiImage trace2;
1184 fmi_debug(3, "enhance_horz_lines2");
1185
1186 init_new_image(&trace2);
1187
1188 /* for (i=0;i<256;i++) histogram_weighted_mean2_weights[i]=i+1; */
1189 for (i = 0; i < 256; i++)
1190 histogram_weights[i] = i + 1;
1191
1192 canonize_image(trace, &trace2);
1193 /* copy_image(trace,&trace2); */
1194 pipeline_process(trace, &trace2, 4, 1, histogram_max);
1195 pipeline_process(&trace2, trace, 4, 0, histogram_mean);
1196 /* threshold_image(trace,trace,8,0,histogram_max); */
1197 /* histogram_median2_count=(2*hrad+1)*(2*vrad+1)*7/8; */
1198
1199 for (k = 0; k < trace->channels; k++) {
1200 for (i = 0; i < trace->width; i++) {
1201 n = 0;
1202 for (j = 0; j < trace->height; j++)
1203 n += (get_pixel(trace, i, j, k) > 0 ? 1 : 0);
1204 /*vrad= weight * n/trace->width; */
1205 /*hrad= 4*weight * n/trace->width; */
1206 /* count=weight*weight*(2*hrad+1)*(2*vrad+1)*n/trace->width; */
1207 vrad = 4;
1208 hrad = 1;
1209 count = (2 * hrad + 1) * (2 * vrad + 1) * weight * n / trace->width;
1210 histogram_sample_count = count;
1211 /* RISK 2010 */
1212 initialize_histogram(trace, hist, hrad, vrad, 0, j, NULL);
1213 for (j = 0; j < trace->height; up(trace, hist, hrad, vrad, &i, &j))
1214 /* put_pixel(&trace2,i,j,k,histogram_median(hist,count)); */
1215 /*put_pixel(&trace2,i,j,k,histogram_weighted_mean2(hist)); */
1216 /* put_pixel(&trace2,i,j,k,histogram_cumul_bottom(hist,count)); */
1217 put_pixel(&trace2, i, j, k, histogram_median2(hist));
1218 }
1219 }
1220 /* invert_image(&trace2); */
1221 /* pipeline_process(&trace2,trace,0,1,histogram_max); */
1222 copy_image(&trace2, trace);
1223 reset_image(&trace2);
1224}
1225
1226/* */
1227void put_nonzero(FmiImage *img,int x,int y,int channel,Byte c){
1228 if (c>0) img->array[channel*img->area + y*img->width + x]=c;
1229}
1230
1231void hide_segments(FmiImage *target,FmiImage *trace){
1232 /*register int i,j,k; */
1233 /*int n,count; */
1234 FmiImage trace2; /*,glue; */
1235
1236 init_new_image(&trace2);
1237 /* canonize_image(target,&glue); */
1238
1239 /*
1240 copy_image(trace,&trace2);
1241 pipeline_process(&trace2,trace,0,1,histogram_max);
1242 if (FMI_DEBUG(2)) write_image("hide",trace,PGM_RAW);
1243 */
1244
1245 /*subtract_image(trace,&trace2,trace); */
1246
1247 /* GLUE SEPARATE DOTS with trace2 */
1248 pipeline_process(trace,&trace2,0,1,histogram_min);
1249 max_image(target,&trace2,&trace2);
1250 if (FMI_DEBUG(2)) write_image("glue",&trace2,PGM_RAW);
1251 /* copy_image(target,&trace2); */
1252
1253 /* return; */
1254
1255 /* propagate_up(&trace2,trace,target,8,put_pixel_max); */
1256 /* propagate_down(&trace2,trace,target,8,put_pixel_max); */
1257 propagate_up(&trace2,trace,target,0,put_nonzero);
1258 /* propagate_up(&trace2,trace,target,0,put_pixel_min); */
1259 propagate_down(&trace2,trace,target,0,put_pixel_max);
1260 reset_image(&trace2);
1261}
1262
1263/* first full, then slope/256 % at max distance */
1264void distance_compensation_die(FmiImage *image,int slope){
1265 register int i,j,k,l;
1266 for (k=0;k<image->channels;k++)
1267 for (i=0;i<image->width;i++){
1268 l=((image->width-i*slope/256)/image->width);
1269 for (j=0;j<image->height;j++)
1270 put_pixel(image,i,j,k,get_pixel(image,i,j,k)*l);
1271 }
1272}
1273
1274/* first mul by 1, then by coeff at max distance */
1275void distance_compensation_mul(FmiImage *image, int coeff)
1276{
1277 register int i, j, k, l, m;
1278 //printf("%d\n", DATA_MAX);
1279 for (k = 0; k < image->channels; k++) {
1280 for (i = 0; i < image->width; i++) {
1281 l = image->width + (coeff - 1) * i;
1282 for (j = 0; j < image->height; j++) {
1283 m = get_pixel(image, i, j, k) * l / image->width;
1284 // if (m>DATA_MAX) m=DATA_MAX; /* Undeclared, defaults to 16. Shouldn't it be 250? */
1285 if (m > 254)
1286 m = 254; /* What's preventing us from using the data's full range? */
1287 put_pixel(image, i, j, k, m);
1288 }
1289 }
1290 }
1291}
1292
1293/* div by [1...slope] (at origin... at max distance) */
1294/* NOTICE! ROUNDS 0.001 => 1 */
1295void distance_compensation_div(FmiImage *image, int slope)
1296{
1297 register int i, j, k;
1298 int l, m;
1299 for (k = 0; k < image->channels; k++) {
1300 for (i = 0; i < image->width; i++) {
1301 /* l=(image->width-i)/image->width; */
1302 l = 1024 * slope * i / image->width + 1024;
1303 for (j = 0; j < image->height; j++) {
1304 m = get_pixel(image, i, j, k);
1305 put_pixel(image, i, j, k, m * 1024 / l + (m > 0));
1306 }
1307 }
1308 }
1309}
1310
1311/*
1312void tyrannize(FmiImage *image,int threshold_intensity,int max_size,int max_intensity){
1313
1314}
1315*/
1316
1317void remove_horz_lines(FmiImage *target,int min_length,int min_elevation,int weight){
1318 /*
1319 int i,j,k;
1320 int gd,gmax;
1321 unsigned char g1,g2;
1322 int n;
1323 float w;
1324 */
1325 FmiImage trace,trace2,trace3;
1326 /* const int up_edges[1][3]={0,1,-1}; */
1327 /* const int down_edges[1][3]={-1,1,0}; */
1328
1329 init_new_image(&trace);
1330 init_new_image(&trace2);
1331 init_new_image(&trace3);
1332
1333 canonize_image(target,&trace);
1334 canonize_image(target,&trace2);
1335 canonize_image(target,&trace3);
1336
1337 fmi_debug(1,"remove_emitters2");
1338 if (FMI_DEBUG(2)) printf(" min_elevation=%d\n",min_elevation);
1339 detect_horz_edges(target,&trace);
1340 distance_compensation_die(&trace,50);
1341 threshold_image(&trace,&trace,min_elevation);
1342
1343 /* COMPUTE "HORIZONTAL" LENGTHS OF SEGMENTS */
1344 fill_image(&trace2,0);
1345 propagate_right(NULL,&trace,&trace2,+1,put_pixel);
1346 limit_image_intensities(&trace2,0,32);
1347 fill_image(&trace,0);
1348 propagate_left(&trace2,&trace2,&trace,0,put_pixel);
1349 if (FMI_DEBUG(2)) printf(" min_length=%d\n",min_length);
1350 threshold_image(&trace,&trace,min_length);
1351 if (FMI_DEBUG(2)) write_image("debug_edges",&trace,PGM_RAW);
1352 /* AT THIS POINT, WE HAVE SEGMENTS LONGER THAN n, MARKED WITH n+ */
1353
1354 /* COMPUTE VERTICAL WIDTH BY A WAVE FORTH AND BACK, IN BOTH DIRS */
1355 fill_image(&trace2,0);
1356 propagate_up(&trace,target,&trace2,-8,put_pixel);
1357 propagate_down(&trace2,target,&trace2,0,put_pixel_min);
1358
1359 fill_image(&trace3,0);
1360 propagate_down(&trace,target,&trace3,-8,put_pixel);
1361 propagate_up(&trace3,target,&trace3,0,put_pixel_min);
1362
1363 max_image(&trace2,&trace3,&trace3);
1364 if (FMI_DEBUG(2)) write_image("debug_edges2",&trace3,PGM_RAW);
1365 threshold_image(&trace3,&trace3,min_length/2);
1366 /* AT THIS POINT, TOO THICK SEGMENTS HAVE BEEN PRUNED */
1367
1368 /* propagate_left(&trace,&trace,&trace,0,put_pixel); */
1369 enhance_horz_lines2(&trace3,weight);
1370 if (FMI_DEBUG(2)) write_image("debug_lines",&trace3,PGM_RAW);
1371
1372 invert_image(&trace3);
1373 mask_image(target,&trace3,255,EMITTER);
1374 /* hide_segments(target,&trace3); */
1375 /* if (FMI_DEBUG(2)) write_image("edges2",&trace,PGM_RAW); */
1376
1377 /* detect_horz_edge_segments(target,&trace,min_length,min_elevation); */
1378 /* convolve(target,&trace,1,3,up_edges,2); */
1379 reset_image(&trace);
1380 reset_image(&trace2);
1381 reset_image(&trace3);
1382}
1383
1384/* start_intensity = threshold at the origin */
1385/* radius = range of 50% effect */
1386/* weight = steepness, 1=steep, 100=soft */
1387/*void detect_insect_band(FmiImage *source,FmiImage *prob,int start_intensity,int radius,int slope){ */
1388void detect_insect_band(FmiImage *source, FmiImage *prob, int start_intensity,
1389 int radius, int slope)
1390{
1391 register int i, j, k;
1392 int threshold, temp;
1393 canonize_image(source, prob);
1394 for (k = 0; k < source->channels; k++) {
1395 for (i = 0; i < source->width; i++) {
1396 temp = i - radius;
1397 threshold = start_intensity * (256 - pseudo_sigmoid(slope, temp)) / 512
1398 + 1;
1399 /* printf("%d\t",threshold); */
1400 for (j = 0; j < source->height; j++) {
1401 temp = threshold - get_pixel(source, i, j, k);
1402 if (temp <= -threshold)
1403 temp = -threshold;
1404 /* temp=MAX(temp,-threshold); */
1405 if (get_pixel(source, i, j, k) > DATA_MIN)
1406 put_pixel(prob, i, j, k, 128 + 127 * temp / threshold);
1407 else
1408 put_pixel(prob, i, j, k, 0);
1409 }
1410 /*put_pixel(prob,i,j,k,threshold); */
1411 }
1412 }
1413}
1414
1415void detect_biomet(FmiImage *source, FmiImage *prob, int intensity_max,
1416 int intensity_delta, int altitude_max, int altitude_delta)
1417{
1418 register int i, j, k;
1419 int f, h;
1420
1421 setup_context(source);
1422 /*int threshold,temp; */
1423 canonize_image(source, prob);
1424 for (k = 0; k < source->channels; k++) {
1425 for (i = 0; i < source->width; i++) {
1426
1427 h = bin_to_altitude(i, source[k + 1].elevation_angle);
1428 /*printf("bin %d[%d]: %d metres",i,k,h); */
1429 h = (pseudo_sigmoid(altitude_delta, altitude_max - h) + 255) / 2;
1430 /* printf(", prob=%d\n",h); */
1431 /*printf("bin %d[%d]: %d\n",i,k,h); */
1432 for (j = 0; j < source->height; j++) {
1433 /* for (j=0;j<2;j++){ */
1434 f = get_pixel(source, i, j, k);
1435 if ((f == 0) || (f == NO_DATA)) {
1436 f = 240; /* ? */
1437 put_pixel(prob, i, j, k, 0);
1438 } else {
1439 f = (pseudo_sigmoid(intensity_delta, intensity_max - f) + 255) / 2;
1440 put_pixel(prob, i, j, k, f * h / 255);
1441 }
1442 /* printf("bin %d[%d]: prob=%d \n",i,k,h); */
1443 /* put_pixel(prob,i,j,k,f); */
1444 /* put_pixel(prob,i,j,k,129); */
1445 }
1446 /*put_pixel(prob,i,j,k,threshold); */
1447 }
1448 }
1449}
1450
1451void pgm_to_ppm_radar(FmiImage *source, FmiImage *target)
1452{
1453 register int i;
1454 /* Byte i,r,g,b; */
1455 ColorMap256 map;
1456
1457 for (i = 0; i < 256; i++) {
1458 /* colorcode(i,&r,&g,&b); */
1459 map[i][0] = i;
1460 map[i][1] = i;
1461 map[i][2] = i;
1462 }
1463
1464 #include "fmi_radar_codes.inc"
1465
1466 copy_image_properties(source, target);
1467 target->channels = 3;
1468 initialize_image(target);
1469 map_channel_to_256_colors(source, 0, target, map);
1470}
1471
1472/* */
1473void pgm_to_pgm_print(FmiImage *source, FmiImage *target)
1474{
1475 register int i;
1476 int g;
1477 canonize_image(source, target);
1478 for (i = 0; i < source->volume; i++) {
1479 g = source->array[i];
1480 if (g > 0)
1481 g = ((g - 64) / 16) * 32 + 96;
1482 /* g = ((g-64)/16)*32+128; */
1483 if (g > 255)
1484 g = 255;
1485 target->array[i] = 255 - g;
1486 }
1487}
1488
1489/* INVERTED */
1490void pgm_to_pgm_print2(FmiImage *source,FmiImage *target){
1491 register int i;
1492 int g;
1493 canonize_image(source,target);
1494 for (i=0;i<source->volume;i++){
1495 g = source->array[i];
1496 if (g>0){
1497 g = ((g-64)/16)*32+64;
1498 /* g = ((g-64)/8)*32+64; */
1499 if (g>=255) g=254;
1500 g=255-g;
1501 }
1502 target->array[i] =255-g;
1503 }
1504}
1505
1506void pgm_to_ppm_radar_iris(FmiImage *source, FmiImage *target)
1507{
1508 register int i;
1509 int temp;
1510 ColorMap256 map;
1511
1512 for (i = 0; i < DATA_MIN; i++) {
1513 map[i][0] = 0;
1514 map[i][1] = 0;
1515 map[i][2] = 0;
1516 }
1517
1518 /*for (i=0;i<16;i++) */
1519 /*fprintf(stderr,"map[%3d]= %3d,%3d,%3d\n",i,map[i][0],map[i][1],map[i][2]); */
1520
1521 for (i = DATA_MIN; i < 256; i++) {
1522 temp = 128 + pseudo_sigmoid(16, i - 112) / 2;
1523 map[i][0] = MIN(temp,255);
1524 temp = pseudo_gauss(32, i - 92) + 64 + pseudo_sigmoid(16, i - 144) / 4;
1525 map[i][1] = MIN(temp,255);
1526 temp = pseudo_gauss(24, i - 64) * 2 / 3 + 128 + pseudo_sigmoid(32, i - 176)
1527 / 2;
1528 map[i][2] = MIN(temp,255);
1529 }
1530
1531 map[255][0] = 255;
1532 map[255][1] = 255;
1533 map[255][2] = 255;
1534
1535 copy_image_properties(source, target);
1536 target->channels = 3;
1537 initialize_image(target);
1538 map_channel_to_256_colors(source, 0, target, map);
1539 /*for (i=0;i<16;i++) */
1540 /*fprintf(stderr,"map[%3d]= %3d,%3d,%3d\n",i,map[i][0],map[i][1],map[i][2]); */
1541}
1542
1543void pgm_to_redgreen(FmiImage *source,FmiImage *target){
1544 register int i;
1545 ColorMap256 map;
1546
1547 for (i=0;i<255;i++){
1548 map[0][0]= (i>128) ? pseudo_sigmoid(64,128) : 0;
1549 map[0][1]= (i<128) ? 255-pseudo_sigmoid(64,128) : 0;
1550 map[0][2]=0;}
1551
1552 copy_image_properties(source,target);
1553 target->channels=3;
1554 initialize_image(target);
1555 map_channel_to_256_colors(source,0,target,map);
1556}
1557
1558
1559
1560/* SAMPLING */
1561
1562/* sample images */
1563void virtual_rhi(FmiImage *volume){
1564 int i,j=0,k,j_start=0,j_end;
1565 FmiImage target;
1566
1567 init_new_image(&target);
1568
1569 setup_context(volume);
1570 copy_image_properties(volume,&target);
1571 target.channels=1;
1572 initialize_image(&target);
1573 fill_image(&target,0);
1574 for (i=0;i<volume->width;i++){
1575 j_start=0;
1576 for (k=0;j<volume->channels;k++){
1577 j_end=bin_to_bin(i,0,volume[k+1].elevation_angle);
1578 for (j=j_start;j<j_end;j++)
1579 put_pixel(&target,i,j,0,5);
1580 j_start=j_end;}
1581 }
1582
1583 reset_image(&target);
1584}
1585
1586void gradient_rgb(FmiImage *volume){
1587 FmiImage target[1+3],cart;
1588 const int sweeps=volume->height/360;
1589
1590 fprintf(stderr,"gradient_rgb: %d sweeps\n",sweeps);
1591
1592 if (sweeps<4)
1593 fmi_error("gradient_rgb: needs at least 4 sweeps");
1594
1595 copy_image_properties(&volume[1],target);
1596 target->channels=3;
1597 initialize_image(target);
1598 /* channels_to_link_array(target,&target[1]); */
1599 split_to_link_array(target,3,&target[1]);
1600
1601 subtract_image128(&volume[2],&volume[1],&target[1]);
1602 /* fill_image(&target[2],128); */
1603 subtract_image128(&volume[3],&volume[1],&target[2]);
1604 subtract_image128(&volume[4],&volume[1],&target[3]);
1605
1606 /* split_to_channels(target,3); */
1607 canonize_image(target,&cart);
1608 to_cart(target,&cart,NO_DATA);
1609
1610 write_image("Grad",target,PPM_RAW);
1611 write_image("Gradc",&cart,PPM_RAW);
1612}
1613
1614
1615/* pointwise images */
1616
1617int histogram_dominate_anaprop(Histogram h){
1618 register int i,i_max;
1619 i_max=1;
1620 for (i=1;i<DATA_MIN;i++)
1621 if (h[i]>h[i_max])
1622 i_max=i;
1623 if (h[i_max]==0)
1624 return 0;
1625 else
1626 return i_max;
1627}
1628