00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032
00033
00034
00035
00036 #include <math.h>
00037 #include <float.h>
00038 #include <cpl.h>
00039
00040 #include "xsh_spectrum.h"
00041 #include "xsh_utils_wrappers.h"
00042
00043
00044
00045
00046
00047 #define SPECTRUM_HW 16
00048 #define MIN_THRESH_FACT 0.9
00049 #define MAX_THRESH_FACT 1.1
00050 #define SPEC_SHADOW_FACT 30.0
00051 #define SPEC_MAXWIDTH 48
00052
00053
00054
00055
00056
00057 static int select_valid_spectra(cpl_image *, cpl_apertures *, int,
00058 spec_shadows, int, int *, int **) ;
00059 static int valid_spectrum(cpl_image *, cpl_apertures *, int, spec_shadows, int,
00060 int) ;
00061
00062
00066
00067
00070
00085
00086 int xsh_spectrum_find_brightest(
00087 const cpl_image * in,
00088 int offset,
00089 spec_shadows shadows,
00090 double min_bright,
00091 int orient,
00092 double * pos)
00093 {
00094 cpl_image * loc_ima ;
00095 cpl_image * filt_image ;
00096 cpl_matrix * kernel ;
00097 cpl_image * collapsed ;
00098 float * pcollapsed ;
00099 cpl_vector * line ;
00100 double * pline ;
00101 cpl_vector * line_filt ;
00102 double threshold ;
00103 double median, stdev, max, mean ;
00104 cpl_mask * mask ;
00105 cpl_image * labels ;
00106 cpl_size nlabels ;
00107 cpl_apertures * aperts ;
00108 int n_valid_specs ;
00109 int * valid_specs ;
00110 double brightness;
00111
00112 int i ;
00113
00114
00115 if (in == NULL) return -1 ;
00116 if (orient!=0 && orient!=1) return -1 ;
00117
00118
00119 if (orient == 1) {
00120 loc_ima = cpl_image_duplicate(in) ;
00121 cpl_image_flip(loc_ima, 1) ;
00122 } else {
00123 loc_ima = cpl_image_duplicate(in) ;
00124 }
00125
00126
00127 kernel = cpl_matrix_new(3, 3) ;
00128 cpl_matrix_fill(kernel, 1.0) ;
00129 if ((filt_image = xsh_image_filter_median(loc_ima, kernel)) == NULL) {
00130 cpl_matrix_delete(kernel) ;
00131 cpl_image_delete(loc_ima) ;
00132 cpl_msg_error(cpl_func, "cannot filter the image") ;
00133 return -1 ;
00134 }
00135 cpl_image_delete(loc_ima) ;
00136 cpl_matrix_delete(kernel) ;
00137
00138
00139 if ((collapsed = cpl_image_collapse_median_create(filt_image, 1, 0,
00140 0)) == NULL) {
00141 cpl_msg_error(cpl_func, "collapsing image: aborting spectrum detection");
00142 cpl_image_delete(filt_image) ;
00143 return -1 ;
00144 }
00145 cpl_image_delete(filt_image) ;
00146
00147
00148 line = cpl_vector_new_from_image_column(collapsed, 1) ;
00149 cpl_image_delete(collapsed) ;
00150 line_filt = cpl_vector_filter_median_create(line, SPECTRUM_HW) ;
00151 cpl_vector_subtract(line, line_filt) ;
00152 cpl_vector_delete(line_filt) ;
00153
00154
00155 median = cpl_vector_get_median_const(line) ;
00156 stdev = cpl_vector_get_stdev(line) ;
00157 max = cpl_vector_get_max(line) ;
00158 mean = cpl_vector_get_mean(line) ;
00159
00160
00161 threshold = median + stdev ;
00162 if (threshold > MIN_THRESH_FACT * max) threshold = MIN_THRESH_FACT * max ;
00163 if (threshold < MAX_THRESH_FACT * mean) threshold = MAX_THRESH_FACT * mean;
00164
00165
00166 collapsed = cpl_image_new(1, cpl_vector_get_size(line), CPL_TYPE_FLOAT) ;
00167 pcollapsed = cpl_image_get_data_float(collapsed) ;
00168 pline = cpl_vector_get_data(line) ;
00169 for (i=0 ; i<cpl_vector_get_size(line) ; i++)
00170 pcollapsed[i] = (float)pline[i] ;
00171 cpl_vector_delete(line) ;
00172
00173
00174 if ((mask = cpl_mask_threshold_image_create(collapsed, threshold,
00175 DBL_MAX)) == NULL) {
00176 cpl_msg_error(cpl_func, "cannot binarise") ;
00177 cpl_image_delete(collapsed) ;
00178 return -1 ;
00179 }
00180 if (cpl_mask_count(mask) < 1) {
00181 cpl_msg_error(cpl_func, "not enough signal to detect spectra") ;
00182 cpl_image_delete(collapsed) ;
00183 cpl_mask_delete(mask) ;
00184 return -1 ;
00185 }
00186
00187 if ((labels = cpl_image_labelise_mask_create(mask, &nlabels))==NULL) {
00188 cpl_msg_error(cpl_func, "cannot labelise") ;
00189 cpl_image_delete(collapsed) ;
00190 cpl_mask_delete(mask) ;
00191 return -1 ;
00192 }
00193 cpl_mask_delete(mask) ;
00194
00195
00196 if ((aperts = cpl_apertures_new_from_image(collapsed, labels)) == NULL) {
00197 cpl_msg_error(cpl_func, "cannot compute apertures") ;
00198 cpl_image_delete(collapsed) ;
00199 cpl_image_delete(labels) ;
00200 return -1 ;
00201 }
00202 cpl_image_delete(labels) ;
00203
00204
00205 if (select_valid_spectra(collapsed, aperts, offset, shadows, SPEC_MAXWIDTH,
00206 &n_valid_specs, &valid_specs) == -1) {
00207 cpl_msg_debug(cpl_func, "cannot select valid spectra") ;
00208 cpl_image_delete(collapsed) ;
00209 cpl_apertures_delete(aperts) ;
00210 return -1 ;
00211 }
00212 cpl_image_delete(collapsed) ;
00213 if (n_valid_specs < 1) {
00214 cpl_msg_error(cpl_func, "no valid spectrum detected") ;
00215 cpl_free(valid_specs) ;
00216 cpl_apertures_delete(aperts) ;
00217 return -1 ;
00218 }
00219
00220
00221 *pos = cpl_apertures_get_centroid_y(aperts, valid_specs[0]+1) ;
00222
00223 brightness = cpl_apertures_get_flux(aperts, valid_specs[0]+1) ;
00224 for (i=0 ; i<n_valid_specs ; i++) {
00225 if (cpl_apertures_get_flux(aperts, valid_specs[i]+1) > brightness) {
00226 *pos = cpl_apertures_get_centroid_y(aperts, valid_specs[i]+1) ;
00227
00228 brightness = cpl_apertures_get_flux(aperts, valid_specs[i]+1) ;
00229 }
00230 }
00231 cpl_apertures_delete(aperts) ;
00232 cpl_free(valid_specs) ;
00233
00234
00235 if (brightness < min_bright) {
00236 cpl_msg_error(cpl_func, "brightness %f too low <%f", brightness,
00237 min_bright) ;
00238 return -1 ;
00239 }
00240
00241
00242 return 0 ;
00243 }
00244
00245
00254
00255 cpl_vector * xsh_spectrum_detect_peaks(
00256 const cpl_vector * in,
00257 int fwhm,
00258 double kappa,
00259 int display)
00260 {
00261 cpl_vector * filtered ;
00262 cpl_vector * spec_clean ;
00263 double * pspec_clean ;
00264 int filt_size ;
00265 cpl_vector * conv_kernel ;
00266 cpl_vector * big_detected ;
00267 double * pbig_detected ;
00268 cpl_vector * detected ;
00269 double * pdetected ;
00270 double max, med, stdev, cur_val ;
00271 int nb_det, nb_samples ;
00272 int i, j ;
00273
00274
00275 if (in == NULL) return NULL ;
00276
00277
00278 nb_samples = cpl_vector_get_size(in) ;
00279 filt_size = 5 ;
00280
00281
00282 cpl_msg_info(__func__, "Low Frequency signal removal") ;
00283 if ((filtered=cpl_vector_filter_median_create(in, filt_size))==NULL){
00284 cpl_msg_error(__func__, "Cannot filter the spectrum") ;
00285 return NULL ;
00286 }
00287 spec_clean = cpl_vector_duplicate(in) ;
00288 cpl_vector_subtract(spec_clean, filtered) ;
00289 cpl_vector_delete(filtered) ;
00290
00291
00292 if (display) {
00293 cpl_plot_vector(
00294 "set grid;set xlabel 'Position (pixels)';set ylabel 'Intensity (ADU)';",
00295 "t 'Filtered extracted spectrum' w lines", "", spec_clean);
00296 }
00297
00298
00299 cpl_msg_info(__func__, "Spectrum convolution") ;
00300
00301 if ((conv_kernel = cpl_wlcalib_xc_convolve_create_kernel(fwhm,
00302 fwhm)) == NULL) {
00303 cpl_msg_error(cpl_func, "Cannot create convolution kernel") ;
00304 cpl_vector_delete(spec_clean) ;
00305 return NULL ;
00306 }
00307
00308
00309 if (cpl_wlcalib_xc_convolve(spec_clean, conv_kernel)) {
00310 cpl_msg_error(cpl_func, "Cannot smoothe the signal");
00311 cpl_vector_delete(spec_clean) ;
00312 cpl_vector_delete(conv_kernel) ;
00313 return NULL ;
00314 }
00315 cpl_vector_delete(conv_kernel) ;
00316
00317
00318 if (display) {
00319 cpl_plot_vector(
00320 "set grid;set xlabel 'Position (pixels)';set ylabel 'Intensity (ADU)';",
00321 "t 'Convolved extracted spectrum' w lines", "", spec_clean);
00322 }
00323
00324
00325 big_detected = cpl_vector_duplicate(spec_clean) ;
00326 pbig_detected = cpl_vector_get_data(big_detected) ;
00327 pspec_clean = cpl_vector_get_data(spec_clean) ;
00328
00329
00330 pspec_clean[0] = pspec_clean[nb_samples-1] = 0.0 ;
00331
00332
00333 max = cpl_vector_get_max(spec_clean) ;
00334 stdev = cpl_vector_get_stdev(spec_clean) ;
00335 med = cpl_vector_get_median_const(spec_clean) ;
00336
00337
00338 nb_det = 0 ;
00339 while (max > med + stdev * kappa) {
00340
00341 i=0 ;
00342 while (pspec_clean[i] < max) i++ ;
00343 if (i<=0 || i>=nb_samples-1) break ;
00344
00345
00346 pbig_detected[nb_det] = (pspec_clean[i]*i +
00347 pspec_clean[i-1]*(i-1) + pspec_clean[i+1]*(i+1)) /
00348 (pspec_clean[i]+pspec_clean[i-1]+pspec_clean[i+1]);
00349
00350 pbig_detected[nb_det] ++ ;
00351
00352
00353 nb_det ++ ;
00354
00355
00356 j = i-1 ;
00357 cur_val = pspec_clean[i] ;
00358 while (j>=0 && pspec_clean[j] < cur_val) {
00359 cur_val = pspec_clean[j] ;
00360 pspec_clean[j] = 0.0 ;
00361 j-- ;
00362 }
00363
00364 j = i+1 ;
00365 cur_val = pspec_clean[i] ;
00366 while (j<=nb_samples-1 && pspec_clean[j] < cur_val) {
00367 cur_val = pspec_clean[j] ;
00368 pspec_clean[j] = 0.0 ;
00369 j++ ;
00370 }
00371
00372 pspec_clean[i] = 0.0 ;
00373
00374
00375 max = cpl_vector_get_max(spec_clean) ;
00376 stdev = cpl_vector_get_stdev(spec_clean) ;
00377 med = cpl_vector_get_median_const(spec_clean) ;
00378 }
00379 cpl_vector_delete(spec_clean) ;
00380 cpl_msg_info(__func__, "%d lines detected", nb_det) ;
00381
00382
00383 if (nb_det == 0) {
00384 detected = NULL ;
00385 } else {
00386 detected = cpl_vector_new(nb_det) ;
00387 pdetected = cpl_vector_get_data(detected) ;
00388 pbig_detected = cpl_vector_get_data(big_detected) ;
00389 for (i=0 ; i<nb_det ; i++) pdetected[i] = pbig_detected[i] ;
00390 }
00391 cpl_vector_delete(big_detected) ;
00392
00393
00394 return detected ;
00395 }
00396
00399
00411
00412 static int select_valid_spectra(
00413 cpl_image * in,
00414 cpl_apertures * aperts,
00415 int offset,
00416 spec_shadows shadows,
00417 int max_spec_width,
00418 int * n_valid_specs,
00419 int ** valid_specs)
00420 {
00421 int nb_aperts ;
00422 int i, j ;
00423
00424
00425 *valid_specs = NULL ;
00426 nb_aperts = cpl_apertures_get_size(aperts) ;
00427 *n_valid_specs = 0 ;
00428
00429
00430 if (nb_aperts < 1) return -1 ;
00431
00432
00433 j = 0 ;
00434 for (i=0 ; i<nb_aperts ; i++)
00435 if (valid_spectrum(in, aperts, offset, shadows, max_spec_width,
00436 i+1)) (*n_valid_specs)++ ;
00437
00438
00439 if (*n_valid_specs) {
00440 *valid_specs = cpl_calloc(*n_valid_specs, sizeof(int)) ;
00441 j = 0 ;
00442 for (i=0 ; i<nb_aperts ; i++)
00443 if (valid_spectrum(in, aperts, offset, shadows, max_spec_width,
00444 i+1)) {
00445 (*valid_specs)[j] = i ;
00446 j++ ;
00447 }
00448 } else return -1 ;
00449
00450 return 0 ;
00451 }
00452
00453
00464
00465 static int valid_spectrum(
00466 cpl_image * in,
00467 cpl_apertures * aperts,
00468 int offset,
00469 spec_shadows shadows,
00470 int max_spec_width,
00471 int objnum)
00472 {
00473 int objwidth ;
00474 double valover, valunder, valcenter ;
00475
00476
00477 objwidth = cpl_apertures_get_top(aperts, objnum) -
00478 cpl_apertures_get_bottom(aperts, objnum) + 1 ;
00479 if (objwidth > max_spec_width) {
00480 cpl_msg_error(cpl_func, "object is too wide") ;
00481 return 0 ;
00482 }
00483
00484
00485 if (cpl_apertures_get_npix(aperts, objnum) < 2) return 0 ;
00486
00487
00488 if (shadows == NO_SHADOW) return 1 ;
00489
00490
00491 valcenter = cpl_apertures_get_median(aperts, objnum) ;
00492
00493
00494 if (cpl_apertures_get_bottom(aperts, objnum) - offset < 1) valunder = 0.0 ;
00495 else valunder = cpl_image_get_median_window(in, 1,
00496 cpl_apertures_get_bottom(aperts, objnum) - offset, 1,
00497 cpl_apertures_get_top(aperts, objnum) - offset) ;
00498
00499 if (cpl_apertures_get_top(aperts, objnum) + offset > 1024) valover = 0.0 ;
00500 else valover = cpl_image_get_median_window(in, 1,
00501 cpl_apertures_get_bottom(aperts, objnum) + offset, 1,
00502 cpl_apertures_get_top(aperts, objnum) + offset) ;
00503
00504 switch (shadows) {
00505 case TWO_SHADOWS:
00506 if ((valunder < -fabs(valcenter/SPEC_SHADOW_FACT)) &&
00507 (valover < -fabs(valcenter/SPEC_SHADOW_FACT)) &&
00508 (valunder/valover > 0.5) &&
00509 (valunder/valover < 2.0)) return 1 ;
00510 else return 0 ;
00511
00512 case ONE_SHADOW:
00513 if ((valunder < -fabs(valcenter/SPEC_SHADOW_FACT)) ||
00514 (valover < -fabs(valcenter/SPEC_SHADOW_FACT))) return 1 ;
00515 else return 0 ;
00516
00517 case NO_SHADOW:
00518 return 1 ;
00519
00520 default:
00521 cpl_msg_error(cpl_func, "unknown spec_detect_mode") ;
00522 break ;
00523 }
00524
00525 return 0 ;
00526 }