CR2RE Pipeline Reference Manual 1.6.8
cr2res_trace.c
1/*
2 * This file is part of the CR2RES Pipeline
3 * Copyright (C) 2002,2003 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include <math.h>
29#include <string.h>
30
31#include <cpl.h>
32#include "cr2res_dfs.h"
33#include "cr2res_trace.h"
34#include "cr2res_pfits.h"
35#include "cr2res_io.h"
36#include "cr2res_wave.h"
37#include "cr2res_utils.h"
38
39/*-----------------------------------------------------------------------------
40 Defines
41 -----------------------------------------------------------------------------*/
42#define min(a,b) (((a)<(b))?(a):(b))
43#define any(arr, f) ({ \
44 int isError = FALSE;\
45 for (cpl_size i = 0; i < cpl_array_get_size(arr); i++) \
46 {\
47 isError = f(cpl_array_get(arr, i, NULL));\
48 if (isError) break;\
49 }\
50 isError;\
51 })
52
53/*-----------------------------------------------------------------------------
54 Functions prototypes
55 -----------------------------------------------------------------------------*/
56
57/*static int cr2res_trace_apply_shift(
58 cpl_table * traces,
59 double shift) ;*/
60/*static double cr2res_trace_compute_shift(
61 const cpl_table * traces1,
62 const cpl_table * traces2) ;*/
63static int cr2res_trace_new_trace(
64 const cpl_array * slit_fraction_in,
65 const cpl_array ** trace_in,
66 const int nb_traces,
67 const cpl_array * slit_fraction_wished,
68 cpl_array ** trace_all_new,
69 cpl_array ** trace_upper_new,
70 cpl_array ** trace_lower_new) ;
71static int cr2res_trace_check_slit_fraction(const cpl_array * slit_fraction) ;
72static cpl_array * cr2res_trace_get_slit_frac(
73 const cpl_table * traces,
74 cpl_size idx,
75 cr2res_decker decker_pos) ;
76static cpl_mask * cr2res_trace_signal_detect(
77 const cpl_image * image,
78 int smooth_x,
79 int smooth_y,
80 double thresh) ;
81static cpl_table * cr2res_trace_fit_traces(
82 cpl_table * clustertable,
83 int degree) ;
84static cpl_array * cr2res_trace_fit_trace(
85 cpl_table * table,
86 int degree) ;
87static cpl_table * cr2res_trace_restore_edge_traces(
88 cpl_table * trace_table) ;
89static cpl_table * cr2res_trace_convert_labels_to_cluster(cpl_image * labels) ;
90static cpl_mask * cr2res_trace_clean_blobs(
91 cpl_mask * mask,
92 int min_cluster) ;
93static int cr2res_trace_extract_edges(
94 cpl_table * pixels_table,
95 cpl_table ** edge_lower_table,
96 cpl_table ** edge_upper_table) ;
97static int cr2res_trace_get_subtrace(
98 cpl_table * trace_wave,
99 double slit_pos,
100 double height,
101 int order_idx,
102 cpl_array ** bottom,
103 cpl_array ** center,
104 cpl_array ** top,
105 cpl_array ** fraction,
106 cpl_array ** wave) ;
107static int cr2res_trace_filter_keep(
108 const char * setting,
109 int real_order) ;
110static double cr2res_trace_calculate_pixel_shift(
111 int n,
112 double sf_lower,
113 double sf_all,
114 double sf_upper,
115 double sf_new,
116 cpl_polynomial * poly_lower,
117 cpl_polynomial * poly_all,
118 cpl_polynomial * poly_upper,
119 cpl_polynomial * poly_a,
120 cpl_polynomial * poly_b,
121 cpl_polynomial * poly_c,
122 double * a,
123 double * b,
124 double * c,
125 double * pix_shift_y);
126
127
128/*----------------------------------------------------------------------------*/
132/*----------------------------------------------------------------------------*/
133
136/*----------------------------------------------------------------------------*/
162/*----------------------------------------------------------------------------*/
163cpl_table * cr2res_trace(
164 cpl_image * ima,
165 int smooth_x,
166 int smooth_y,
167 double threshold,
168 int opening,
169 int degree,
170 int min_cluster)
171{
172 cpl_mask * mask ;
173 cpl_mask * mask_clean ;
174 cpl_image * labels ;
175 cpl_table * clustertable ;
176 cpl_table * trace_table ;
177 cpl_table * restored_trace_table ;
178 cpl_size nlabels ;
179
180 /* Check Entries */
181 if (ima == NULL) return NULL ;
182
183 /* Apply detection */
184 cpl_msg_info(__func__, "Detect the signal") ;
185 if ((mask = cr2res_trace_signal_detect(ima, smooth_x, smooth_y,
186 threshold)) == NULL) {
187 cpl_msg_error(__func__, "Detection failed") ;
188 return NULL ;
189 }
190
191 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
192 if (cpl_mask_save(mask, "debug_mask_before_cleaning.fits", NULL,
193 CPL_IO_CREATE) != CPL_ERROR_NONE)
194 cpl_error_reset();
195 }
196 /* Clean the traces in the image */
197 cpl_msg_info(__func__, "Traces cleaning") ;
198 if ((mask_clean = cr2res_trace_clean(mask, opening, min_cluster)) == NULL) {
199 cpl_msg_error(__func__, "Cannot clean the traces") ;
200 cpl_mask_delete(mask) ;
201 return NULL ;
202 }
203 cpl_mask_delete(mask) ;
204
205 /* Labelization */
206 cpl_msg_info(__func__, "Labelise the traces") ;
207 if ((labels=cpl_image_labelise_mask_create(mask_clean, &nlabels)) == NULL) {
208 cpl_msg_error(__func__, "Cannot labelise") ;
209 cpl_mask_delete(mask_clean);
210 return NULL ;
211 }
212 if (nlabels == 0) {
213 cpl_msg_error(__func__, "Found no labels");
214 cpl_image_delete(labels);
215 cpl_mask_delete(mask_clean);
216 return NULL;
217 }
218 cpl_mask_delete(mask_clean);
219
220 /* Analyse and dump traces */
221 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
222 if (cpl_image_get_max(labels) != 0){
223 cpl_apertures * aperts ;
224 aperts = cpl_apertures_new_from_image(ima, labels);
225 cpl_apertures_dump(aperts, stdout) ;
226 cpl_apertures_delete(aperts) ;
227 } else {
228 cpl_msg_debug(__func__, "No labels found, can not create aperture");
229 }
230 }
231
232 /* Create cluster table needed for fitting */
233 clustertable = cr2res_trace_convert_labels_to_cluster(labels) ;
234
235 /* Debug Saving */
236 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
237 if (cpl_image_save(labels, "debug_labels.fits",
238 CPL_TYPE_INT, NULL, CPL_IO_CREATE) != CPL_ERROR_NONE)
239 cpl_error_reset();
240 if (cpl_table_save(clustertable, NULL, NULL, "debug_cluster_table.fits",
241 CPL_IO_CREATE) != CPL_ERROR_NONE)
242 cpl_error_reset();
243 }
244 cpl_image_delete(labels) ;
245
246 /* Fit the traces */
247 cpl_msg_info(__func__, "Fit the trace edges") ;
248 if ((trace_table = cr2res_trace_fit_traces(clustertable, degree)) == NULL) {
249 cpl_msg_error(__func__, "Failed to Fit") ;
250 cpl_table_delete(clustertable);
251 return NULL ;
252 }
253
254 /* Debug Saving */
255 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
256 if (cpl_table_save(trace_table, NULL, NULL,
257 "debug_trace_table.fits", CPL_IO_CREATE) != CPL_ERROR_NONE)
258 cpl_error_reset();
259 }
260
261 /* Detect and restore the edge traces */
262 cpl_msg_info(__func__, "Restore the trace edges") ;
263 if ((restored_trace_table = cr2res_trace_restore_edge_traces(
264 trace_table)) == NULL) {
265 cpl_msg_error(__func__, "Failed to Restore the edge traces") ;
266 cpl_table_delete(clustertable);
267 cpl_table_delete(trace_table);
268 return NULL ;
269 }
270 cpl_table_delete(trace_table);
271 cpl_table_delete(clustertable);
272
273 /* Debug Saving */
274 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
275 if (cpl_table_save(restored_trace_table, NULL, NULL,
276 "debug_restored_trace_table.fits", CPL_IO_CREATE)
277 != CPL_ERROR_NONE)
278 cpl_error_reset();
279 }
280 return restored_trace_table ;
281}
282
283/*----------------------------------------------------------------------------*/
291/*----------------------------------------------------------------------------*/
293 cpl_mask * mask,
294 int opening,
295 int min_cluster)
296{
297 cpl_mask * new_mask ;
298 cpl_mask * clean_mask ;
299
300 /* Check entries */
301 if (mask == NULL) return NULL ;
302 if ((opening != 0) & (opening != 1)) return NULL;
303
304 /* Apply a opening to join horizontally the close clusters */
305 if (opening) {
306
307 cpl_mask * mask_kernel ;
308 cpl_mask * diff_mask ;
309
310 cpl_msg_info(__func__, "Apply Opening to cleanup the traces") ;
311 mask_kernel = cpl_mask_new(5, 1) ;
312 cpl_mask_not(mask_kernel);
313 new_mask = cpl_mask_duplicate(mask) ;
314 cpl_mask_filter(new_mask, mask, mask_kernel, CPL_FILTER_OPENING,
315 CPL_BORDER_COPY) ;
316 cpl_mask_delete(mask_kernel) ;
317
318 /* Compute the difference */
319 diff_mask = cpl_mask_duplicate(mask) ;
320 cpl_mask_xor(diff_mask, new_mask) ;
321 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
322 if (cpl_mask_save(diff_mask, "debug_diff_mask.fits", NULL,
323 CPL_IO_CREATE) != CPL_ERROR_NONE)
324 cpl_error_reset();
325 }
326 cpl_mask_delete(diff_mask) ;
327 } else {
328 new_mask = cpl_mask_duplicate(mask) ;
329 }
330
331 /* Clean the small blobs */
332 cpl_msg_info(__func__, "Remove the small blobs (<= %d pixels)",
333 min_cluster) ;
334 if ((clean_mask = cr2res_trace_clean_blobs(new_mask, min_cluster)) == NULL){
335 cpl_msg_error(__func__, "Cannot clean the blobs") ;
336 cpl_mask_delete(new_mask) ;
337 return NULL ;
338 }
339 cpl_mask_delete(new_mask) ;
340
341 /* Debug Saving */
342 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
343 if (cpl_mask_save(clean_mask, "debug_mask.fits",
344 NULL, CPL_IO_CREATE) != CPL_ERROR_NONE)
345 cpl_error_reset();
346 }
347 return clean_mask ;
348}
349
350/*----------------------------------------------------------------------------*/
361/*----------------------------------------------------------------------------*/
363 cpl_table * trace,
364 int nx,
365 int ny)
366{
367 cpl_image * out ;
368 int * pout ;
369 int order_idx, i ;
370 cpl_size j, k, y_pos_lower, y_pos_upper ;
371
372 /* Check entries */
373 if (trace == NULL) return NULL ;
374 if (nx < 1 || ny < 1) return NULL ;
375
376 /* Create the empty image */
377 out = cpl_image_new(nx, ny, CPL_TYPE_INT) ;
378 cpl_image_add_scalar(out, -1.0) ;
379 pout = cpl_image_get_data_int(out) ;
380
381 /* Loop on the traces */
382 for (i=0 ; i<cpl_table_get_nrow(trace) ; i++) {
383
384 const cpl_array * coeffs_upper ;
385 const cpl_array * coeffs_lower ;
386 cpl_polynomial * poly_upper ;
387 cpl_polynomial * poly_lower ;
388 /* Get the Order - Use fix value when no order column */
389 if (cpl_table_has_column(trace, CR2RES_COL_ORDER))
390 order_idx = cpl_table_get(trace, CR2RES_COL_ORDER, i, NULL) ;
391 else
392 order_idx = 100 ;
393
394 /* Get the Upper polynomial*/
395 coeffs_upper = cpl_table_get_array(trace, CR2RES_COL_UPPER, i) ;
396 poly_upper = cr2res_convert_array_to_poly(coeffs_upper) ;
397
398 /* Get the Lower polynomial*/
399 coeffs_lower = cpl_table_get_array(trace, CR2RES_COL_LOWER, i) ;
400 poly_lower = cr2res_convert_array_to_poly(coeffs_lower) ;
401
402 /* Draw It */
403 for (j=0 ; j<nx ; j++) {
404 y_pos_lower = (cpl_size)cpl_polynomial_eval_1d(poly_lower,
405 (double)j+1, NULL) ;
406 y_pos_upper = (cpl_size)cpl_polynomial_eval_1d(poly_upper,
407 (double)j+1, NULL) ;
408 for (k = y_pos_lower-1 ; k < y_pos_upper ; k++)
409 if (k < ny && k >=0)
410 pout[j+k*nx] = order_idx ;
411
412 }
413 cpl_polynomial_delete(poly_upper) ;
414 cpl_polynomial_delete(poly_lower) ;
415 }
416 return out;
417}
418
419/*----------------------------------------------------------------------------*/
430/*----------------------------------------------------------------------------*/
432 const cpl_table * trace,
433 int * nb_order_idx_values)
434{
435 const int * porder_idx_values ;
436 int nrows, count_order_idx_values;
437 int * tmp_out ;
438 int * out ;
439 int i, j ;
440
441 /* Check entries */
442 if (trace == NULL || nb_order_idx_values == NULL) return NULL ;
443
444 /* Initialise */
445 nrows = cpl_table_get_nrow(trace) ;
446 porder_idx_values = cpl_table_get_data_int_const(trace, CR2RES_COL_ORDER);
447
448 /* Allocate orders list */
449 tmp_out = cpl_malloc(nrows * sizeof(int)) ;
450
451 /* Count the different orders */
452 count_order_idx_values = 0 ;
453 for (i=0 ; i<nrows ; i++) {
454 int new_order_idx ;
455 /* Is the current order a new one ? */
456 new_order_idx = 1 ;
457 for (j=0 ; j<count_order_idx_values ; j++)
458 if (tmp_out[j] == porder_idx_values[i])
459 new_order_idx = 0 ;
460
461 /* Current order not yet stored */
462 if (new_order_idx) {
463 tmp_out[count_order_idx_values] = porder_idx_values[i] ;
464 count_order_idx_values ++ ;
465 }
466 }
467
468 /* Allocate and fill output array */
469 out = cpl_malloc(count_order_idx_values * sizeof(int)) ;
470 for (i=0 ; i<count_order_idx_values ; i++) out[i] = tmp_out[i] ;
471
472 /* Free and return */
473 cpl_free(tmp_out) ;
474 *nb_order_idx_values = count_order_idx_values ;
475 return out ;
476}
477
478/*----------------------------------------------------------------------------*/
485/*----------------------------------------------------------------------------*/
487 const cpl_table * trace_wave,
488 int order_idx)
489{
490 cpl_size nrows, i, count ;
491
492 /* Check Entries */
493 if (trace_wave == NULL) return -1 ;
494
495 /* Initialise */
496 count = 0 ;
497 nrows = cpl_table_get_nrow(trace_wave) ;
498
499 /* Loop on the table rows */
500 for (i=0 ; i<nrows ; i++)
501 if (cpl_table_get(trace_wave, CR2RES_COL_ORDER, i, NULL)==order_idx) {
502 count ++ ;
503 }
504 return count ;
505}
506
507/*----------------------------------------------------------------------------*/
516/*----------------------------------------------------------------------------*/
518 const cpl_table * trace_wave,
519 int order_idx,
520 int * nb_traces)
521{
522 cpl_size nrows, i, k;
523 int number_traces;
524 int * traces;
525 /* Check Entries */
526 if (trace_wave == NULL) return NULL ;
527
528 number_traces = cr2res_get_nb_traces(trace_wave, order_idx);
529 if (number_traces == -1) return NULL ;
530
531
532 /* Initialise */
533 k = 0;
534 nrows = cpl_table_get_nrow(trace_wave) ;
535 traces = cpl_malloc(number_traces * sizeof(int));
536
537 /* Loop on the table rows */
538 for (i=0 ; i<nrows ; i++)
539 if (cpl_table_get(trace_wave, CR2RES_COL_ORDER, i, NULL)==order_idx) {
540 traces[k] = cpl_table_get(trace_wave, CR2RES_COL_TRACENB, i, NULL);
541 k++;
542 }
543
544 if (nb_traces != NULL) *nb_traces = number_traces;
545
546 if (k != number_traces){
547 cpl_msg_warning(__func__, "Not all expected traces found");
548 }
549 return traces;
550}
551#ifdef CR2RES_UNUSED
552/*----------------------------------------------------------------------------*/
560/*----------------------------------------------------------------------------*/
561cpl_size cr2res_get_nb_traces_with_wavelength(
562 const cpl_table * trace_wave,
563 int order_idx)
564{
565 cpl_size nrows, i, count ;
566
567 /* Check Entries */
568 if (trace_wave == NULL) return -1 ;
569
570 /* Initialise */
571 count = 0 ;
572 nrows = cpl_table_get_nrow(trace_wave) ;
573
574 /* Loop on the table rows */
575 for (i=0 ; i<nrows ; i++) {
576 const cpl_array * wave_array ;
577 wave_array = cpl_table_get_array(trace_wave, CR2RES_COL_WAVELENGTH, i) ;
578 if (cpl_table_get(trace_wave, CR2RES_COL_ORDER, i, NULL) == order_idx
579 && wave_array != NULL) count ++ ;
580 }
581 return count ;
582}
583#endif
584/*----------------------------------------------------------------------------*/
591/*----------------------------------------------------------------------------*/
593 const cpl_table * trace_wave1,
594 const cpl_table * trace_wave2)
595{
596 cpl_table * merged;
597 int * order_idx_values ;
598 int norder_idx_values, j;
599 cpl_size i, nrows ;
600
601 /* Check Entries */
602 if (trace_wave1 == NULL || trace_wave2 == NULL) return NULL ;
603 nrows = cpl_table_get_nrow(trace_wave1) ;
604
605 /* Create the merged table */
606 merged = cpl_table_duplicate(trace_wave1) ;
607
608 /* Merge the tables */
609 if (cpl_table_insert(merged, trace_wave2, nrows) != CPL_ERROR_NONE) {
610 cpl_msg_error(__func__, "Failed merging the tables") ;
611 cpl_table_delete(merged) ;
612 return NULL ;
613 }
614
615 /* Recompute the merged table size */
616 nrows = cpl_table_get_nrow(merged) ;
617
618 /* Get the order_idx_values information */
619 order_idx_values = cr2res_trace_get_order_idx_values(merged,
620 &norder_idx_values) ;
621
622 /* Update the trace_id Information */
623 /* Loop on the orders */
624 for (j=0 ; j<norder_idx_values ; j++) {
625 int cur_trace_id ;
626 /* Initialise the trace ID */
627 cur_trace_id = 1 ;
628
629 /* Loop on the table */
630 for (i=0 ; i<nrows ; i++) {
631 /* Each time the current order is seen, update the trace id */
632 if (cpl_table_get(merged, CR2RES_COL_ORDER, i,
633 NULL)==order_idx_values[j]) {
634 cpl_table_set(merged, CR2RES_COL_TRACENB, i, cur_trace_id);
635 cur_trace_id++ ;
636 }
637 }
638 }
639 cpl_free(order_idx_values) ;
640 return merged ;
641}
642
643/*----------------------------------------------------------------------------*/
651/*----------------------------------------------------------------------------*/
653 const cpl_table * trace_wave,
654 int order_idx,
655 int trace_nb)
656{
657 cpl_size nrows, i ;
658
659 /* Check Entries */
660 if (trace_wave == NULL) return -1 ;
661
662 /* Initialise */
663 nrows = cpl_table_get_nrow(trace_wave) ;
664
665 /* Loop on the table rows */
666 for (i=0 ; i<nrows ; i++) {
667 if (cpl_table_get(trace_wave, CR2RES_COL_ORDER,i,NULL)==order_idx &&
668 cpl_table_get(trace_wave, CR2RES_COL_TRACENB,i,NULL)==trace_nb)
669 return i ;
670 }
671 return -1 ;
672}
673
674/*----------------------------------------------------------------------------*/
684/*----------------------------------------------------------------------------*/
686 const cpl_table * trace_wave,
687 const char * poly_column,
688 int order_idx,
689 int trace_nb)
690{
691 const cpl_array * wave_arr ;
692 cpl_polynomial * wave_poly ;
693 cpl_size index ;
694
695 /* Check Entries */
696 if (trace_wave == NULL) return NULL ;
697 if (strcmp(poly_column, CR2RES_COL_WAVELENGTH) &&
698 strcmp(poly_column, CR2RES_COL_UPPER) &&
699 strcmp(poly_column, CR2RES_COL_LOWER) &&
700 strcmp(poly_column, CR2RES_COL_ALL) &&
701 strcmp(poly_column, CR2RES_COL_SLIT_CURV_A) &&
702 strcmp(poly_column, CR2RES_COL_SLIT_CURV_B) &&
703 strcmp(poly_column, CR2RES_COL_SLIT_CURV_C)) return NULL ;
704
705 /* Get Table index from order_idx and trace_nb */
706 index = cr2res_get_trace_table_index(trace_wave, order_idx, trace_nb) ;
707 if (index == -1) return NULL;
708
709 /* Read the Table */
710 wave_arr = cpl_table_get_array(trace_wave, poly_column, index) ;
711 if (wave_arr == NULL) return NULL ;
712
713 /* Convert to Polynomial */
714 wave_poly = cr2res_convert_array_to_poly(wave_arr) ;
715
716 return wave_poly ;
717}
718
719/*----------------------------------------------------------------------------*/
729/*----------------------------------------------------------------------------*/
731 const cpl_table * trace_wave,
732 int order_idx,
733 int trace_nb,
734 int size)
735{
736 cpl_vector * out ;
737 cpl_polynomial * wl_poly;
738
739 /* Check Inputs */
740 if (trace_wave == NULL || size < 1) return NULL ;
741
742 /* Get the Wavelength polynomial */
743 wl_poly = cr2res_get_trace_wave_poly(trace_wave, CR2RES_COL_WAVELENGTH,
744 order_idx, trace_nb) ;
745 if (wl_poly == NULL) return NULL ;
746
747 /* Allocate output */
748 out = cpl_vector_new(size) ;
749 if (cpl_vector_fill_polynomial(out, wl_poly, 1, 1) != CPL_ERROR_NONE) {
750 cpl_vector_delete(out);
751 cpl_polynomial_delete(wl_poly);
752 return NULL;
753 }
754 cpl_polynomial_delete(wl_poly);
755 return out ;
756}
757
758/*----------------------------------------------------------------------------*/
768/*----------------------------------------------------------------------------*/
770 const cpl_table * trace,
771 int order_idx,
772 int trace_nb,
773 int size)
774{
775 cpl_vector * out ;
776 cpl_polynomial * pos_poly;
777
778 if (trace == NULL || size < 1) return NULL ;
779
780 /* Get the Positions polynomial */
781 pos_poly = cr2res_get_trace_wave_poly(trace, CR2RES_COL_ALL,
782 order_idx, trace_nb) ;
783 if (pos_poly == NULL) return NULL ;
784
785 /* Allocate output */
786 out = cpl_vector_new(size) ;
787 if (cpl_vector_fill_polynomial(out, pos_poly, 1, 1) != CPL_ERROR_NONE) {
788 cpl_vector_delete(out);
789 cpl_polynomial_delete(pos_poly);
790 return NULL;
791 }
792 cpl_polynomial_delete(pos_poly);
793 return out ;
794}
795
796/*----------------------------------------------------------------------------*/
804/*----------------------------------------------------------------------------*/
806 const cpl_table * trace,
807 cpl_size order_idx,
808 cpl_size trace_nb)
809{
810 int height;
811 cpl_polynomial * poly_upper ;
812 cpl_polynomial * poly_lower ;
813
814 /* Check entries */
815 if (trace == NULL) return -1 ;
816
817 /* Get the trace edges */
818 poly_upper = cr2res_get_trace_wave_poly(trace, CR2RES_COL_UPPER,
819 order_idx, trace_nb);
820 poly_lower = cr2res_get_trace_wave_poly(trace, CR2RES_COL_LOWER,
821 order_idx, trace_nb);
822 if (poly_upper == NULL || poly_lower == NULL) return -1;
823
824 /* Compute the height */
825 height = cr2res_trace_compute_height(poly_upper, poly_lower,
826 CR2RES_DETECTOR_SIZE);
827
828 cpl_polynomial_delete(poly_upper);
829 cpl_polynomial_delete(poly_lower);
830
831 if (height > 300){
832 cpl_msg_warning(__func__, "Computed height unreasonably large");
833 return -1;
834 }
835 return height;
836}
837
838/*----------------------------------------------------------------------------*/
850/*----------------------------------------------------------------------------*/
852 cpl_polynomial * trace1,
853 cpl_polynomial * trace2,
854 int vector_size)
855{
856 cpl_vector * out ;
857 cpl_polynomial * tmp;
858
859 if (trace1 == NULL || trace2 == NULL || vector_size < 1){
860 return NULL;
861 }
862
863 out = cpl_vector_new(vector_size) ;
864 tmp = cpl_polynomial_new(1);
865 cpl_polynomial_add(tmp, trace1, trace2);
866 cpl_polynomial_multiply_scalar(tmp, tmp, 0.5);
867
868 cpl_vector_fill_polynomial(out, tmp, 1, 1);
869 cpl_polynomial_delete(tmp);
870
871 return out ;
872}
873
874/*----------------------------------------------------------------------------*/
885/*----------------------------------------------------------------------------*/
887 cpl_polynomial * trace1,
888 cpl_polynomial * trace2,
889 int vector_size)
890{
891 cpl_polynomial * diff_poly;
892 cpl_vector * diff_vec ;
893 int height ;
894
895 /* Check Entries */
896 if (trace1 == NULL || trace2 == NULL || vector_size < 1) return -1 ;
897
898 diff_poly = cpl_polynomial_new(1);
899 diff_vec = cpl_vector_new(vector_size);
900 cpl_polynomial_subtract(diff_poly, trace1, trace2);
901 cpl_vector_fill_polynomial(diff_vec, diff_poly, 1, 1);
902 height = (int)ceil(fabs( cpl_vector_get_mean(diff_vec) ));
903 cpl_polynomial_delete(diff_poly) ;
904
905 if (cpl_vector_get_stdev(diff_vec) > 10){ // TODO: make this not hardcoded?
906 cpl_msg_warning(__func__, "Stdev of extraction height is large: %.1f",
907 cpl_vector_get_stdev(diff_vec));
908 }
909 cpl_vector_delete(diff_vec) ;
910
911 cpl_msg_debug(__func__, "Computed height is %d pix.", height);
912 return height;
913}
914
915/*----------------------------------------------------------------------------*/
922/*----------------------------------------------------------------------------*/
924 const cpl_table * traces,
925 int idx)
926{
927 const cpl_array * coeffs ;
928 cpl_polynomial * poly ;
929 double ypos ;
930
931 /* Check Entries */
932 if (traces == NULL) return -1.0 ;
933 if (idx < 0) return -1.0 ;
934 if (idx >= cpl_table_get_nrow(traces)) return -1.0 ;
935
936 /* Get the trace polynomial*/
937 coeffs = cpl_table_get_array(traces, CR2RES_COL_ALL, idx) ;
938 poly = cr2res_convert_array_to_poly(coeffs) ;
939
940 /* Evaluate the central pixel */
941 ypos = cpl_polynomial_eval_1d(poly, CR2RES_DETECTOR_SIZE / 2, NULL) ;
942 cpl_polynomial_delete(poly) ;
943
944 return ypos ;
945}
946
947/*----------------------------------------------------------------------------*/
971/*----------------------------------------------------------------------------*/
973 cpl_table * traces,
974 const char * infile,
975 int det_nr)
976{
977 cpl_propertylist * ext_plist ;
978 cpl_propertylist * main_plist ;
979 int * order_idx_values ;
980 cpl_array * array_id ;
981 cpl_array * array_zero ;
982 cpl_array * array_neg ;
983 cr2res_decker decker_pos ;
984 int order_idx, nb_order_idx_values,
985 i, j ;
986
987 if (traces == NULL) return -1;
988
989 /* Load the Plist */
990 main_plist = cpl_propertylist_load(infile, 0) ;
991 ext_plist = cpl_propertylist_load(infile,
992 cr2res_io_get_ext_idx(infile, det_nr, 1)) ;
993 if (ext_plist == NULL || main_plist == 0) {
994 cpl_error_reset();
995 cpl_propertylist_delete(main_plist);
996 cpl_propertylist_delete(ext_plist);
997 return -1;
998 }
999
1000 /* Get the decker position */
1001 decker_pos = cr2res_pfits_get_decker_position(main_plist) ;
1002 cpl_propertylist_delete(main_plist) ;
1003
1004 /* Add The Order column using the header */
1005 cpl_table_new_column(traces, CR2RES_COL_ORDER, CPL_TYPE_INT) ;
1006
1007 /* Loop on the traces */
1008 for (i=0 ; i<cpl_table_get_nrow(traces) ; i++) {
1009 double y_pos ;
1010 /* Get the current trace Y position */
1011 y_pos = cr2res_trace_get_trace_ypos(traces, i) ;
1012
1013 /* Compute the trace order_idx from the header */
1014 order_idx = cr2res_pfits_get_order_idx(ext_plist, y_pos) ;
1015
1016 /* Store the Order in the table */
1017 cpl_table_set(traces, CR2RES_COL_ORDER, i, order_idx);
1018 }
1019 cpl_propertylist_delete(ext_plist) ;
1020
1021 /* Add The TraceNb column */
1022 cpl_table_new_column(traces, CR2RES_COL_TRACENB, CPL_TYPE_INT);
1023
1024 order_idx_values = cr2res_trace_get_order_idx_values(traces,
1025 &nb_order_idx_values) ;
1026 for (i=0 ; i<nb_order_idx_values ; i++) {
1027 int trace_nb;
1028 /* Initialise */
1029 trace_nb = 1 ;
1030 /* Loop on the traces */
1031 for (j=0 ; j<cpl_table_get_nrow(traces) ; j++) {
1032 if (cpl_table_get(traces, CR2RES_COL_ORDER, j, NULL) ==
1033 order_idx_values[i]) {
1034 cpl_table_set(traces, CR2RES_COL_TRACENB, j, trace_nb);
1035 trace_nb ++ ;
1036 }
1037 }
1038 }
1039 cpl_free(order_idx_values) ;
1040
1041 /* Add The Wavelength(_Error) column using the header */
1042 cpl_table_new_column_array(traces, CR2RES_COL_WAVELENGTH,
1043 CPL_TYPE_DOUBLE, 3) ;
1044 cpl_table_new_column_array(traces, CR2RES_COL_WAVELENGTH_ERROR,
1045 CPL_TYPE_DOUBLE, 2) ;
1046
1047 /* Loop on the traces */
1048 for (i=0 ; i<cpl_table_get_nrow(traces) ; i++) {
1049 cpl_array * wl_array ;
1050 /* Get the Order number */
1051 order_idx = cpl_table_get(traces, CR2RES_COL_ORDER, i, NULL) ;
1052
1053 /* Get the Wavelength estimates from the header */
1054 if ((wl_array = cr2res_wave_get_estimate(infile, det_nr,
1055 order_idx)) == NULL) {
1056 cpl_msg_warning(__func__,
1057 "No Wavelength estimate for Detector %d / order_idx %d",
1058 det_nr, order_idx) ;
1059 cpl_error_reset() ;
1060 cpl_table_set_array(traces, CR2RES_COL_WAVELENGTH, i, NULL);
1061 cpl_table_set_array(traces, CR2RES_COL_WAVELENGTH_ERROR, i, NULL);
1062 } else {
1063 /* Store the Wavelength in the table */
1064 cpl_table_set_array(traces, CR2RES_COL_WAVELENGTH, i, wl_array);
1065 cpl_array_delete(wl_array) ;
1066
1067 wl_array = cpl_array_new(2, CPL_TYPE_DOUBLE) ;
1068 cpl_array_set(wl_array, 0, CR2RES_WAVELENGTH_ERROR_DEFAULT) ;
1069 cpl_array_set(wl_array, 1, CR2RES_WAVELENGTH_ERROR_DEFAULT) ;
1070 cpl_table_set_array(traces, CR2RES_COL_WAVELENGTH_ERROR,i,wl_array);
1071 cpl_array_delete(wl_array) ;
1072 }
1073 }
1074
1075 /* Add the Slit Curvature Coefficients */
1076 /* A(X) = X, B(X) = 0, C(X) = 0, X:1->2048 */
1077 /* This means that for X=1024, the Slit curvature polynomial is: */
1078 /* x = A(1024) + B(1024) * y + C(1024) *y^2 */
1079 /* i.e. x = 1024 */
1080 /* where x, y are the detector coordinates, (1,1) as Lower left */
1081 cpl_table_new_column_array(traces,CR2RES_COL_SLIT_CURV_A,CPL_TYPE_DOUBLE,3);
1082 cpl_table_new_column_array(traces,CR2RES_COL_SLIT_CURV_B,CPL_TYPE_DOUBLE,3);
1083 cpl_table_new_column_array(traces,CR2RES_COL_SLIT_CURV_C,CPL_TYPE_DOUBLE,3);
1084 array_id = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1085 cpl_array_set(array_id, 0, 0.0) ;
1086 cpl_array_set(array_id, 1, 1.0) ;
1087 cpl_array_set(array_id, 2, 0.0) ;
1088 array_zero = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1089 cpl_array_set(array_zero, 0, 0.0) ;
1090 cpl_array_set(array_zero, 1, 0.0) ;
1091 cpl_array_set(array_zero, 2, 0.0) ;
1092
1093 /* Loop on the traces */
1094 for (i=0 ; i<cpl_table_get_nrow(traces) ; i++) {
1095 cpl_table_set_array(traces, CR2RES_COL_SLIT_CURV_A, i, array_id);
1096 cpl_table_set_array(traces, CR2RES_COL_SLIT_CURV_B, i, array_zero);
1097 cpl_table_set_array(traces, CR2RES_COL_SLIT_CURV_C, i, array_zero);
1098 }
1099 cpl_array_delete(array_id) ;
1100 cpl_array_delete(array_zero) ;
1101
1102 /* Add the Slit Fraction position */
1103 /* 0 is the Bottom of the slit, 1 is the Top. */
1104 /* The 3 numbers correspond to the Lower, All, Upper trace positions */
1105 cpl_table_new_column_array(traces,CR2RES_COL_SLIT_FRACTION,
1106 CPL_TYPE_DOUBLE,3);
1107 array_neg = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1108 cpl_array_set(array_neg, 0, -1.0) ;
1109 cpl_array_set(array_neg, 1, -1.0) ;
1110 cpl_array_set(array_neg, 2, -1.0) ;
1111 for (i=0 ; i<cpl_table_get_nrow(traces) ; i++) {
1112 cpl_array * slit_frac ;
1113 /* Get the slit fraction array */
1114 slit_frac = cr2res_trace_get_slit_frac(traces, i, decker_pos) ;
1115 if (slit_frac == NULL) {
1116 cpl_table_set_array(traces, CR2RES_COL_SLIT_FRACTION, i, array_neg);
1117 cpl_msg_warning(__func__, "Cannot assign slit fraction.");
1118 } else {
1119 cpl_table_set_array(traces, CR2RES_COL_SLIT_FRACTION, i, slit_frac);
1120 cpl_array_delete(slit_frac) ;
1121 }
1122 }
1123 cpl_array_delete(array_neg) ;
1124 return 0 ;
1125}
1126
1127/*----------------------------------------------------------------------------*/
1151/*----------------------------------------------------------------------------*/
1153 const cpl_table * traces,
1154 const cpl_array * new_slit_fraction)
1155{
1156 cpl_table * out ;
1157 const cpl_array * slit_frac_old;
1158 const cpl_array * trace_all_old ;
1159 const cpl_array * trace_upper_old ;
1160 const cpl_array * trace_lower_old ;
1161 const cpl_array ** trace_old;
1162 cpl_array * trace_all_new ;
1163 cpl_array * trace_upper_new ;
1164 cpl_array * trace_lower_new ;
1165 cpl_array * wave ;
1166 const cpl_array * const_wave ;
1167 const cpl_array * const_wave_err;
1168 cpl_array * wave_err ;
1169 cpl_array * slit_curv_a ;
1170 cpl_array * slit_curv_b ;
1171 cpl_array * slit_curv_c ;
1172 const cpl_array * const_slit_curv_a;
1173 const cpl_array * const_slit_curv_b;
1174 const cpl_array * const_slit_curv_c;
1175 cpl_polynomial * poly_lower;
1176 cpl_polynomial * poly_all;
1177 cpl_polynomial * poly_upper;
1178 cpl_polynomial * poly_a ;
1179 cpl_polynomial * poly_b ;
1180 cpl_polynomial * poly_c ;
1181 cpl_matrix * samppos;
1182 cpl_vector * a_vec;
1183 cpl_vector * b_vec;
1184 cpl_vector * c_vec;
1185 cpl_size i, j, k, m, n, nrows, degree ;
1186 int nb_order_idx_values, nb_traces;
1187 int * order_idx_values;
1188 double a, b, c;
1189 double sf_lower, sf_upper, sf_all, sf_new;
1190 double pix_shift_x, pix_shift_y;
1191
1192 /* Check entries */
1193 if (traces == NULL || new_slit_fraction == NULL) return NULL ;
1194 if (cr2res_dfs_check_traces_table(traces) != 1) {
1195 cpl_msg_error(__func__, "The traces table is incomplete") ;
1196 return NULL ;
1197 }
1198 if (cpl_array_get_size(new_slit_fraction) != 3){
1199 cpl_msg_error(__func__,
1200 "New slitfraction must have 3 components (Upper, Middle, Lower)");
1201 return NULL;
1202 }
1203
1204 /* Initialise */
1205 //nrows = cpl_table_get_nrow(traces) ;
1206 order_idx_values = cr2res_trace_get_order_idx_values(traces,
1207 &nb_order_idx_values);
1208 out = cpl_table_new(nb_order_idx_values);
1209 cpl_table_copy_structure(out, traces);
1210 cpl_table_select_all(out);
1211
1212 /* Loop on the order_idx values */
1213 for (i=0 ; i<nb_order_idx_values; i++) {
1214
1215 cpl_array * slit_frac_old_trace ;
1216 int * trace_numbers;
1217 trace_numbers = cr2res_get_trace_numbers(traces, order_idx_values[i],
1218 &nb_traces);
1219 trace_old = cpl_malloc(nb_traces * 3 * sizeof(cpl_array*));
1220 for (j = 0; j < nb_traces * 3; j++) trace_old[j] = NULL;
1221 slit_frac_old_trace = cpl_array_new(nb_traces * 3, CPL_TYPE_DOUBLE);
1222
1223 for(j = m = 0; j < nb_traces; j++, m++) {
1224 k=cr2res_get_trace_table_index(traces, order_idx_values[i],
1225 trace_numbers[j]);
1226 /* Check if the input trace slit_fraction is available */
1227 slit_frac_old = cpl_table_get_array(traces,
1228 CR2RES_COL_SLIT_FRACTION, k) ;
1229 trace_all_old = cpl_table_get_array(traces, CR2RES_COL_ALL, k) ;
1230 trace_upper_old = cpl_table_get_array(traces, CR2RES_COL_UPPER, k) ;
1231 trace_lower_old = cpl_table_get_array(traces, CR2RES_COL_LOWER, k) ;
1232
1233 /* Unselect rows with wrong slit_fraction or without trace */
1234 /* to be erased below */
1235 if (cpl_table_is_selected(out, i) == 0 ||
1236 cr2res_trace_check_slit_fraction(slit_frac_old) != 1 ||
1237 trace_upper_old == NULL || trace_lower_old == NULL ||
1238 trace_all_old == NULL) {
1239 cpl_table_unselect_row(out, i) ;
1240 m--;
1241 continue ;
1242 }
1243 trace_old[3 * m + 0] = trace_lower_old;
1244 trace_old[3 * m + 1] = trace_all_old;
1245 trace_old[3 * m + 2] = trace_upper_old;
1246 cpl_array_set(slit_frac_old_trace, 3 * m + 0, cpl_array_get(slit_frac_old, 0, NULL));
1247 cpl_array_set(slit_frac_old_trace, 3 * m + 1, cpl_array_get(slit_frac_old, 1, NULL));
1248 cpl_array_set(slit_frac_old_trace, 3 * m + 2, cpl_array_get(slit_frac_old, 2, NULL));
1249 }
1250
1251 if (m <= 0){
1252 cpl_msg_error(__func__,
1253 "No valid traces found for order %i", order_idx_values[i]) ;
1254 cpl_array_delete(slit_frac_old_trace);
1255 cpl_free(trace_numbers);
1256 cpl_free(trace_old);
1257 continue;
1258 }
1259
1260 trace_old = cpl_realloc(trace_old, m * 3 * sizeof(cpl_array*));
1261 cpl_array_set_size(slit_frac_old_trace, m * 3);
1262
1263 /* Fill out fields */
1264 cpl_table_set_array(out, CR2RES_COL_SLIT_FRACTION, i,new_slit_fraction);
1265 cpl_table_set_int(out, CR2RES_COL_ORDER, i, order_idx_values[i]);
1266 cpl_table_set_int(out, CR2RES_COL_TRACENB, i, 1);
1267
1268 /* Compute the new trace */
1269 if (cr2res_trace_new_trace(slit_frac_old_trace, trace_old, nb_traces,
1270 new_slit_fraction, &trace_all_new, &trace_upper_new,
1271 &trace_lower_new) == -1) {
1272 cpl_msg_error(__func__,
1273 "Cannot compute the new trace for order %i",
1274 order_idx_values[i]) ;
1275 cpl_free(trace_old);
1276 cpl_free(trace_numbers);
1277 cpl_array_delete(slit_frac_old_trace);
1278 continue;
1279 }
1280 cpl_array_delete(slit_frac_old_trace);
1281
1282 /* Set new trace */
1283 cpl_table_set_array(out, CR2RES_COL_ALL, i, trace_all_new);
1284 cpl_table_set_array(out, CR2RES_COL_UPPER, i, trace_upper_new);
1285 cpl_table_set_array(out, CR2RES_COL_LOWER, i, trace_lower_new);
1286 cpl_array_delete(trace_all_new) ;
1287 cpl_array_delete(trace_upper_new) ;
1288 cpl_array_delete(trace_lower_new) ;
1289
1290 // Read data arrays from existing table
1291 // TODO this only works if trace_numbers 0 is a valid trace
1292 k = cr2res_get_trace_table_index(traces, order_idx_values[i],
1293 trace_numbers[0]);
1294 const_wave = cpl_table_get_array(traces, CR2RES_COL_WAVELENGTH, k) ;
1295 const_wave_err = cpl_table_get_array(traces, CR2RES_COL_WAVELENGTH_ERROR, k) ;
1296
1297 const_slit_curv_a = cpl_table_get_array(traces, CR2RES_COL_SLIT_CURV_A,
1298 k) ;
1299 const_slit_curv_b = cpl_table_get_array(traces, CR2RES_COL_SLIT_CURV_B,
1300 k) ;
1301 const_slit_curv_c = cpl_table_get_array(traces, CR2RES_COL_SLIT_CURV_C,
1302 k) ;
1303
1304 /* Compute the new wavelength */
1305 // Calculate the horizontal pixel shift of the new trace, using
1306 // the slit curvature first determine the vertical shift
1307 slit_frac_old = cpl_table_get_array(traces, CR2RES_COL_SLIT_FRACTION,k);
1308 trace_lower_old = trace_old[0];
1309 trace_all_old = trace_old[1];
1310 trace_upper_old = trace_old[2];
1311
1312 poly_all = cr2res_convert_array_to_poly(trace_all_old);
1313 poly_lower = cr2res_convert_array_to_poly(trace_lower_old);
1314 poly_upper = cr2res_convert_array_to_poly(trace_upper_old);
1315
1316 sf_lower = cpl_array_get_double(slit_frac_old, 0, NULL);
1317 sf_all = cpl_array_get_double(slit_frac_old, 1, NULL);
1318 sf_upper = cpl_array_get_double(slit_frac_old, 2, NULL);
1319 sf_new = cpl_array_get_double(new_slit_fraction, 1, NULL);
1320 cpl_msg_debug(__func__, "New Slitfunction %f", sf_new);
1321
1322 // then use the slit curvature to translate that into a horizontal shift
1323 poly_a = cr2res_convert_array_to_poly(const_slit_curv_a);
1324 poly_b = cr2res_convert_array_to_poly(const_slit_curv_b);
1325 poly_c = cr2res_convert_array_to_poly(const_slit_curv_c);
1326
1327 samppos = cpl_matrix_new(1, CR2RES_DETECTOR_SIZE);
1328 a_vec = cpl_vector_new(CR2RES_DETECTOR_SIZE);
1329 b_vec = cpl_vector_new(CR2RES_DETECTOR_SIZE);
1330 c_vec = cpl_vector_new(CR2RES_DETECTOR_SIZE);
1331
1332 for (n = 0; n < CR2RES_DETECTOR_SIZE; n++)
1333 {
1334 pix_shift_x = cr2res_trace_calculate_pixel_shift(n, sf_lower,
1335 sf_all, sf_upper, sf_new, poly_lower, poly_all,
1336 poly_upper, poly_a, poly_b, poly_c, &a, &b, &c, &pix_shift_y);
1337
1338 // Set the location with the shifted position
1339 cpl_matrix_set(samppos, 0, n, n + 1 - pix_shift_x);
1340 // Set the vectors with the global values
1341 cpl_vector_set(a_vec, n, a);
1342 cpl_vector_set(b_vec, n, b);
1343 cpl_vector_set(c_vec, n, c);
1344 }
1345
1346 cpl_polynomial_delete(poly_lower);
1347 cpl_polynomial_delete(poly_all);
1348 cpl_polynomial_delete(poly_upper);
1349
1350 degree = cpl_polynomial_get_degree(poly_a);
1351 cpl_polynomial_fit(poly_a, samppos, NULL, a_vec, NULL,
1352 CPL_FALSE, NULL, &degree);
1353
1354 degree = cpl_polynomial_get_degree(poly_b);
1355 cpl_polynomial_fit(poly_b, samppos, NULL, b_vec, NULL,
1356 CPL_FALSE, NULL, &degree);
1357
1358 degree = cpl_polynomial_get_degree(poly_c);
1359 cpl_polynomial_fit(poly_c, samppos, NULL, c_vec, NULL,
1360 CPL_FALSE, NULL, &degree);
1361
1362 if (cpl_error_get_code() != CPL_ERROR_NONE){
1363 cpl_msg_error(__func__,
1364 "Could not calculate the new trace polynomial. %s",
1365 cpl_error_get_message());
1366 cpl_error_reset();
1367 //TODO: delete polynomial
1368 cpl_polynomial_delete(poly_a);
1369 cpl_polynomial_delete(poly_b);
1370 cpl_polynomial_delete(poly_c);
1371 cpl_free(trace_numbers);
1372 cpl_free(trace_old);
1373 cpl_matrix_delete(samppos);
1374 cpl_vector_delete(a_vec);
1375 cpl_vector_delete(b_vec);
1376 cpl_vector_delete(c_vec);
1377 continue;
1378 }
1379
1380 cpl_matrix_delete(samppos);
1381 cpl_vector_delete(a_vec);
1382 cpl_vector_delete(b_vec);
1383 cpl_vector_delete(c_vec);
1384
1385 slit_curv_a = cr2res_convert_poly_to_array(poly_a,
1386 cpl_array_get_size(const_slit_curv_a));
1387 slit_curv_b = cr2res_convert_poly_to_array(poly_b,
1388 cpl_array_get_size(const_slit_curv_b));
1389 slit_curv_c = cr2res_convert_poly_to_array(poly_c,
1390 cpl_array_get_size(const_slit_curv_c));
1391
1392 cpl_polynomial_delete(poly_a);
1393 cpl_polynomial_delete(poly_b);
1394 cpl_polynomial_delete(poly_c);
1395
1396
1397 /* Set new Wavelength */
1398 wave = cpl_array_duplicate(const_wave);
1399 wave_err = cpl_array_duplicate(const_wave_err);
1400 cpl_table_set_array(out, CR2RES_COL_WAVELENGTH, i, wave);
1401 cpl_table_set_array(out, CR2RES_COL_WAVELENGTH_ERROR, i, wave_err);
1402 cpl_array_delete(wave) ;
1403 cpl_array_delete(wave_err) ;
1404
1405
1406 /* Set the new slit curvature */
1407 cpl_table_set_array(out, CR2RES_COL_SLIT_CURV_A, i, slit_curv_a);
1408 cpl_table_set_array(out, CR2RES_COL_SLIT_CURV_B, i, slit_curv_b);
1409 cpl_table_set_array(out, CR2RES_COL_SLIT_CURV_C, i, slit_curv_c);
1410 cpl_array_delete(slit_curv_a) ;
1411 cpl_array_delete(slit_curv_b) ;
1412 cpl_array_delete(slit_curv_c) ;
1413
1414 cpl_free(trace_numbers);
1415 cpl_free(trace_old);
1416 }
1417 cpl_free(order_idx_values);
1418
1419 /* Clean the selected invalid slit_fractions entries */
1420 cpl_table_not_selected(out) ;
1421 cpl_table_erase_selected(out) ;
1422
1423 /* Check if there is at lease one remaining trace */
1424 if (cpl_table_get_nrow(out) == 0) {
1425 cpl_table_delete(out) ;
1426 return NULL ;
1427 }
1428 cpl_table_not_selected(out) ;
1429
1430 // Shift Wavelength according to curvature
1431 nrows = cpl_table_get_nrow(out);
1432 for (k = 0; k < nrows; k++)
1433 {
1434 int order, trace_id;
1435 order = cpl_table_get_int(out, CR2RES_COL_ORDER, k, NULL);
1436 trace_id = cpl_table_get_int(out, CR2RES_COL_TRACENB, k, NULL);
1437 out = cr2res_trace_shift_wavelength(out, 0.5, order, trace_id);
1438 }
1439
1440 return out ;
1441}
1442
1443static double cr2res_trace_calculate_pixel_shift(
1444 int n,
1445 double sf_lower,
1446 double sf_all,
1447 double sf_upper,
1448 double sf_new,
1449 cpl_polynomial * poly_lower,
1450 cpl_polynomial * poly_all,
1451 cpl_polynomial * poly_upper,
1452 cpl_polynomial * poly_a,
1453 cpl_polynomial * poly_b,
1454 cpl_polynomial * poly_c,
1455 double * a,
1456 double * b,
1457 double * c,
1458 double * pix_shift_y)
1459{
1460 double pix_lower, pix_upper, pix_all;
1461 double pix_shift_x;
1462
1463 pix_lower = cpl_polynomial_eval_1d(poly_lower, n + 1, NULL);
1464 pix_upper = cpl_polynomial_eval_1d(poly_upper, n + 1, NULL);
1465 pix_all = cpl_polynomial_eval_1d(poly_all, n + 1, NULL);
1466
1467 *a = cpl_polynomial_eval_1d(poly_a, n + 1, NULL);
1468 *b = cpl_polynomial_eval_1d(poly_b, n + 1, NULL);
1469 *c = cpl_polynomial_eval_1d(poly_c, n + 1, NULL);
1470
1471 // Shift to the local coordinate system
1472 // c is 0 usually, since we don't fit it always
1473 *a = 0;
1474 *b += 2 * (*c) * pix_all;
1475
1476 // vertical pixel shift
1477 *pix_shift_y = (pix_upper - pix_lower) /
1478 (sf_upper - sf_lower) * (sf_all - sf_new);
1479 // horizontal pixel shift
1480 pix_shift_x = *a + (*c * (*pix_shift_y) + *b) * (*pix_shift_y);
1481
1482 // Shift to global position
1483 *a = n + 1;
1484 *b -= 2 * (*c) * (*pix_shift_y + pix_all);
1485
1486 return pix_shift_x;
1487}
1488
1489cpl_table * cr2res_trace_shift_wavelength(
1490 cpl_table * traces,
1491 double old_slit_fraction,
1492 int order,
1493 int trace_id)
1494{
1495 cpl_vector * wave_vec;
1496 cpl_polynomial * poly_wave;
1497 cpl_array * wave;
1498 cpl_matrix * samppos;
1499 const cpl_array * const_wave;
1500 const cpl_array * slit_frac_old;
1501 const cpl_array * trace_all_old;
1502 const cpl_array * trace_lower_old;
1503 const cpl_array * trace_upper_old;
1504 const cpl_array * const_slit_curv_a;
1505 const cpl_array * const_slit_curv_b;
1506 const cpl_array * const_slit_curv_c;
1507 cpl_polynomial * poly_lower;
1508 cpl_polynomial * poly_all;
1509 cpl_polynomial * poly_upper;
1510 cpl_polynomial * poly_a;
1511 cpl_polynomial * poly_b;
1512 cpl_polynomial * poly_c;
1513 cpl_size n, k ;
1514 cpl_size degree;
1515 double a, b, c;
1516 double pix_shift_y;
1517 double sf_lower, sf_all, sf_upper, sf_new;
1518
1519 k = cr2res_get_trace_table_index(traces, order, trace_id);
1520
1521 // Get values from the trace wave table
1522 const_wave = cpl_table_get_array(traces, CR2RES_COL_WAVELENGTH, k) ;
1523 if (isnan(cpl_array_get(const_wave,0,NULL))) {
1524 cpl_msg_warning(__func__,
1525 "Invalid input wavelength in order %d, trace %d",
1526 order, trace_id);
1527 return traces;
1528 }
1529
1530 //const_wave_err = cpl_table_get_array(traces,
1531 // CR2RES_COL_WAVELENGTH_ERROR, k);
1532 slit_frac_old = cpl_table_get_array(traces,
1533 CR2RES_COL_SLIT_FRACTION, k);
1534 trace_all_old = cpl_table_get_array(traces, CR2RES_COL_ALL, k) ;
1535 trace_upper_old = cpl_table_get_array(traces, CR2RES_COL_UPPER, k) ;
1536 trace_lower_old = cpl_table_get_array(traces, CR2RES_COL_LOWER, k) ;
1537 const_slit_curv_a = cpl_table_get_array(traces,
1538 CR2RES_COL_SLIT_CURV_A, k) ;
1539 const_slit_curv_b = cpl_table_get_array(traces,
1540 CR2RES_COL_SLIT_CURV_B, k) ;
1541 const_slit_curv_c = cpl_table_get_array(traces,
1542 CR2RES_COL_SLIT_CURV_C, k) ;
1543
1544 poly_all = cr2res_convert_array_to_poly(trace_all_old);
1545 poly_lower = cr2res_convert_array_to_poly(trace_lower_old);
1546 poly_upper = cr2res_convert_array_to_poly(trace_upper_old);
1547
1548 // we switch around sf_new and sf_all, since we are correcting
1549 // for a change that has already happened
1550 sf_lower = cpl_array_get_double(slit_frac_old, 0, NULL);
1551 sf_new = cpl_array_get_double(slit_frac_old, 1, NULL);
1552 sf_upper = cpl_array_get_double(slit_frac_old, 2, NULL);
1553 sf_all = old_slit_fraction;
1554
1555 poly_a = cr2res_convert_array_to_poly(const_slit_curv_a);
1556 poly_b = cr2res_convert_array_to_poly(const_slit_curv_b);
1557 poly_c = cr2res_convert_array_to_poly(const_slit_curv_c);
1558
1559 poly_wave = cr2res_convert_array_to_poly(const_wave);
1560 wave_vec = cpl_vector_new(CR2RES_DETECTOR_SIZE);
1561 samppos = cpl_matrix_new(1, CR2RES_DETECTOR_SIZE);
1562
1563
1564 for (n = 0; n < CR2RES_DETECTOR_SIZE; n++)
1565 {
1566 double pix_shift_x;
1567 cpl_vector_set(wave_vec, n,
1568 cpl_polynomial_eval_1d(poly_wave, n + 1, NULL));
1569
1570 pix_shift_x = cr2res_trace_calculate_pixel_shift(n, sf_lower,
1571 sf_all, sf_upper, sf_new, poly_lower, poly_all,
1572 poly_upper, poly_a, poly_b, poly_c, &a, &b, &c,
1573 &pix_shift_y);
1574
1575 cpl_matrix_set(samppos, 0, n, n + 1 - pix_shift_x);
1576 }
1577
1578 cpl_polynomial_delete(poly_a);
1579 cpl_polynomial_delete(poly_b);
1580 cpl_polynomial_delete(poly_c);
1581 cpl_polynomial_delete(poly_lower);
1582 cpl_polynomial_delete(poly_all);
1583 cpl_polynomial_delete(poly_upper);
1584
1585 degree = cpl_polynomial_get_degree(poly_wave);
1586 cpl_polynomial_fit(poly_wave, samppos, NULL, wave_vec, NULL,
1587 CPL_FALSE, NULL, &degree);
1588
1589 if (cpl_error_get_code() != CPL_ERROR_NONE){
1590 cpl_msg_error(__func__,
1591 "Could not calculate the new wavelength polynomial. %s. %s",
1592 cpl_error_get_message(), cpl_error_get_where());
1593 cpl_error_reset();
1594 cpl_vector_delete(wave_vec);
1595 cpl_polynomial_delete(poly_wave);
1596 cpl_matrix_delete(samppos);
1597 return NULL;
1598 }
1599
1600 wave = cr2res_convert_poly_to_array(poly_wave,
1601 cpl_array_get_size(const_wave));
1602
1603 cpl_table_set_array(traces, CR2RES_COL_WAVELENGTH, k, wave);
1604
1605 cpl_vector_delete(wave_vec);
1606 cpl_polynomial_delete(poly_wave);
1607 cpl_array_delete(wave);
1608 cpl_matrix_delete(samppos);
1609
1610 return traces;
1611}
1612#ifdef CR2RES_UNUSED
1613/*----------------------------------------------------------------------------*/
1621/*----------------------------------------------------------------------------*/
1622cpl_table * cr2res_trace_adjust(
1623 const cpl_table * trace_wave,
1624 const cpl_frameset * flat_raw,
1625 int det_nr)
1626{
1627 hdrl_imagelist * imlist ;
1628 hdrl_image * collapsed ;
1629 cpl_image * contrib ;
1630 cpl_table * new_traces ;
1631 const char * first_file ;
1632 cpl_table * corrected_traces ;
1633 int trace_opening, trace_degree,
1634 trace_min_cluster, trace_smooth_x, trace_smooth_y ;
1635 double trace_threshold, traces_shift ;
1636
1637 /* Check Entries */
1638 if (trace_wave == NULL || flat_raw == NULL ||
1639 det_nr < 1 || det_nr > CR2RES_NB_DETECTORS)
1640 return NULL ;
1641
1642 /* Initialise */
1643 trace_smooth_x = 200 ;
1644 trace_smooth_y = 11 ;
1645 trace_threshold = 5.0 ;
1646 trace_opening = 1 ;
1647 trace_degree = 5 ;
1648 trace_min_cluster = 10000 ;
1649
1650 /* Load the image list */
1651 imlist = cr2res_io_load_image_list_from_set(flat_raw, det_nr) ;
1652 if (imlist == NULL) {
1653 cpl_msg_error(__func__, "Failed to load the RAW flat frames") ;
1654 return NULL ;
1655 }
1656
1657 /* Collapse the inputs */
1658 cpl_msg_info(__func__, "Collapse the input images") ;
1659 if (hdrl_imagelist_collapse_mean(imlist, &collapsed, &contrib) !=
1660 CPL_ERROR_NONE) {
1661 cpl_msg_error(__func__, "Failed to Collapse") ;
1662 hdrl_imagelist_delete(imlist) ;
1663 cpl_msg_indent_less() ;
1664 return NULL ;
1665 }
1666 hdrl_imagelist_delete(imlist) ;
1667 cpl_image_delete(contrib) ;
1668
1669 /* Compute the trace */
1670 cpl_msg_info(__func__, "Compute the traces") ;
1671 if ((new_traces = cr2res_trace(hdrl_image_get_image(collapsed),
1672 trace_smooth_x, trace_smooth_y, trace_threshold,
1673 trace_opening, trace_degree, trace_min_cluster)) == NULL) {
1674 cpl_msg_error(__func__, "Failed compute the traces") ;
1675 hdrl_image_delete(collapsed) ;
1676 cpl_msg_indent_less() ;
1677 return NULL ;
1678 }
1679 hdrl_image_delete(collapsed) ;
1680
1681 /* Add The remaining Columns to the new trace table */
1682 first_file = cpl_frame_get_filename(
1683 cpl_frameset_get_position_const(flat_raw, 0)) ;
1684 cr2res_trace_add_extra_columns(new_traces, first_file, det_nr) ;
1685
1686 /* Compute the shift */
1687 cpl_msg_info(__func__, "Compute the Shift between 2 traces tables") ;
1688 traces_shift = cr2res_trace_compute_shift(trace_wave, new_traces) ;
1689 cpl_table_delete(new_traces) ;
1690
1691 /* Apply the shift */
1692 corrected_traces = cpl_table_duplicate(trace_wave) ;
1693 cpl_msg_error(__func__, "Apply correction shift of %g pixels",
1694 traces_shift) ;
1695 cr2res_trace_apply_shift(corrected_traces, traces_shift) ;
1696
1697 /* Free and return */
1698 return corrected_traces ;
1699}
1700#endif
1701
1702/*----------------------------------------------------------------------------*/
1709/*----------------------------------------------------------------------------*/
1711 const cpl_array * slit_frac,
1712 int * up_or_down)
1713{
1714 double up, down;
1715 cr2res_decker decker_pos ;
1716
1717 /* Initialise */
1718 if (up_or_down != NULL) *up_or_down=-1 ;
1719
1720 /* Check entries */
1721 if (slit_frac == NULL) return CR2RES_DECKER_INVALID ;
1722
1723 /* Read the positions */
1724 down = cpl_array_get(slit_frac, 0, NULL) ;
1725 //mid = cpl_array_get(slit_frac, 1, NULL) ;
1726 up = cpl_array_get(slit_frac, 2, NULL) ;
1727 if (cpl_error_get_code()) return CR2RES_DECKER_INVALID ;
1728
1729 if ((fabs(down-0.0)<1e-3) && (fabs(up-1.0)<1e-3)) {
1730 decker_pos = CR2RES_DECKER_NONE ;
1731 if (up_or_down != NULL) *up_or_down=0 ;
1732 } else if ((fabs(down-0.750)<1e-3) && (fabs(up-1.000)<1e-3)) {
1733 decker_pos = CR2RES_DECKER_1_3 ;
1734 if (up_or_down != NULL) *up_or_down=1 ;
1735 } else if ((fabs(down-0.250)<1e-3) && (fabs(up-0.500)<1e-3)) {
1736 decker_pos = CR2RES_DECKER_1_3 ;
1737 if (up_or_down != NULL) *up_or_down=2 ;
1738 } else if ((fabs(down-0.500)<1e-3) && (fabs(up-0.750)<1e-3)) {
1739 decker_pos = CR2RES_DECKER_2_4 ;
1740 if (up_or_down != NULL) *up_or_down=1 ;
1741 } else if ((fabs(down-0.000)<1e-3) && (fabs(up-0.250)<1e-3)) {
1742 decker_pos = CR2RES_DECKER_2_4 ;
1743 if (up_or_down != NULL) *up_or_down=2 ;
1744 } else {
1745 decker_pos = CR2RES_DECKER_INVALID ;
1746 if (up_or_down != NULL) *up_or_down=-1 ;
1747 }
1748 return decker_pos ;
1749}
1750
1751/*----------------------------------------------------------------------------*/
1759/*----------------------------------------------------------------------------*/
1761 cr2res_decker decker_position,
1762 int up_or_down)
1763{
1764 cpl_array * slit_frac ;
1765
1766 /* Check entries */
1767 if (decker_position != CR2RES_DECKER_NONE &&
1768 decker_position != CR2RES_DECKER_1_3 &&
1769 decker_position != CR2RES_DECKER_2_4)
1770 return NULL ;
1771 if (up_or_down != 0 && up_or_down != 1 && up_or_down != 2)
1772 return NULL ;
1773
1774 /* Allocate */
1775 slit_frac = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1776
1777 if (decker_position == CR2RES_DECKER_NONE) {
1778 /* TRACE_OPEN */
1779 cpl_array_set(slit_frac, 0, 0.0) ;
1780 cpl_array_set(slit_frac, 1, 0.5) ;
1781 cpl_array_set(slit_frac, 2, 1.0) ;
1782 } else if (decker_position == CR2RES_DECKER_1_3) {
1783 /* DECKER 1_3 */
1784 if (up_or_down == 1) {
1785 /* Upper trace */
1786 cpl_array_set(slit_frac, 0, 0.750) ;
1787 cpl_array_set(slit_frac, 1, 0.875) ;
1788 cpl_array_set(slit_frac, 2, 1.000) ;
1789 } else if (up_or_down == 2) {
1790 /* Lower trace */
1791 cpl_array_set(slit_frac, 0, 0.250) ;
1792 cpl_array_set(slit_frac, 1, 0.375) ;
1793 cpl_array_set(slit_frac, 2, 0.500) ;
1794 } else {
1795 cpl_array_delete(slit_frac) ;
1796 slit_frac = NULL ;
1797 }
1798 } else if (decker_position == CR2RES_DECKER_2_4) {
1799 /* DECKER 2_4 */
1800 if (up_or_down == 1) {
1801 /* Upper trace */
1802 cpl_array_set(slit_frac, 0, 0.500) ;
1803 cpl_array_set(slit_frac, 1, 0.625) ;
1804 cpl_array_set(slit_frac, 2, 0.750) ;
1805 } else if (up_or_down == 2) {
1806 /* Lower trace */
1807 cpl_array_set(slit_frac, 0, 0.000) ;
1808 cpl_array_set(slit_frac, 1, 0.125) ;
1809 cpl_array_set(slit_frac, 2, 0.250) ;
1810 } else {
1811 cpl_array_delete(slit_frac) ;
1812 slit_frac = NULL ;
1813 }
1814 }
1815 return slit_frac ;
1816}
1817
1818/*----------------------------------------------------------------------------*/
1833/*----------------------------------------------------------------------------*/
1835 cpl_table * trace_wave,
1836 int order_idx,
1837 int nb_subtraces)
1838{
1839 cpl_table * sub_trace_wave ;
1840 cpl_size i, j, k, table_index;
1841 cpl_array * bottom, *center, *top, *fraction, *wave ;
1842 const cpl_array * wave_err, *slit_a, *slit_b, *slit_c;
1843 double height = 1. / (nb_subtraces * 2.);
1844 double pos;
1845 int res = -1;
1846 int nb_order_idx_values, nb_traces, size_new_tw,
1847 ndegree;
1848 int * order_idx_values,
1849 * traces;
1850
1851 if (trace_wave == NULL || nb_subtraces <= 0) return NULL ;
1852
1853 order_idx_values = cr2res_trace_get_order_idx_values(trace_wave,
1854 &nb_order_idx_values);
1855
1856 // Expand the trace table to fit the new data
1857 if (order_idx == -100)
1858 size_new_tw = nb_subtraces * nb_order_idx_values;
1859 else
1860 size_new_tw = nb_subtraces;
1861 sub_trace_wave = cpl_table_new(size_new_tw);
1862 cpl_table_copy_structure(sub_trace_wave, trace_wave);
1863 k=0;
1864
1865 // Prepare data to fill the other columns of the table
1866 for (j = 0; j < nb_order_idx_values; j++){
1867 int ord;
1868 ord = order_idx;
1869 if (order_idx == -100) ord = order_idx_values[j];
1870 else if (order_idx != order_idx_values[j]) continue;
1871
1872 traces = cr2res_get_trace_numbers(trace_wave, ord, &nb_traces);
1873 i = cr2res_get_trace_table_index(trace_wave, ord, traces[0]);
1874 cpl_free(traces);
1875 wave_err = cpl_table_get_array(trace_wave, CR2RES_COL_WAVELENGTH_ERROR,
1876 i);
1877 slit_a = cpl_table_get_array(trace_wave, CR2RES_COL_SLIT_CURV_A, i);
1878 slit_b = cpl_table_get_array(trace_wave, CR2RES_COL_SLIT_CURV_B, i);
1879 slit_c = cpl_table_get_array(trace_wave, CR2RES_COL_SLIT_CURV_C, i);
1880
1881
1882 for (i = 0; i < nb_subtraces; i++){
1883 // center of first subtrace is one height above bottom
1884 pos = height + 2 * height * i;
1885 ndegree = cpl_table_get_column_dimension(trace_wave, CR2RES_COL_ALL,
1886 0);
1887 bottom = cpl_array_new(ndegree, CPL_TYPE_DOUBLE);
1888 top = cpl_array_new(ndegree, CPL_TYPE_DOUBLE);
1889 center = cpl_array_new(ndegree, CPL_TYPE_DOUBLE);
1890 fraction = cpl_array_new(3, CPL_TYPE_DOUBLE);
1891 ndegree = cpl_table_get_column_dimension(trace_wave,
1892 CR2RES_COL_WAVELENGTH, 0);
1893 wave = cpl_array_new(ndegree, CPL_TYPE_DOUBLE);
1894
1895 res = cr2res_trace_get_subtrace(trace_wave, pos, height, ord,
1896 &bottom,
1897 &center, &top, &fraction, &wave);
1898 if (res == -1) {
1899 cpl_array_delete(bottom);
1900 cpl_array_delete(center);
1901 cpl_array_delete(top);
1902 cpl_array_delete(fraction);
1903 cpl_array_delete(wave);
1904 break; // if something went wrong stop here
1905 }
1906 // attach new trace information to the bottom of the table
1907 table_index = k++;
1908 cpl_table_set_int(sub_trace_wave, CR2RES_COL_ORDER, table_index,
1909 ord);
1910 // Traces start counting at 1
1911 cpl_table_set_int(sub_trace_wave, CR2RES_COL_TRACENB, table_index,
1912 i + 1);
1913
1914 // Assign interpolated data
1915 cpl_table_set_array(sub_trace_wave, CR2RES_COL_ALL, table_index,
1916 center);
1917 cpl_table_set_array(sub_trace_wave, CR2RES_COL_LOWER, table_index,
1918 bottom);
1919 cpl_table_set_array(sub_trace_wave, CR2RES_COL_UPPER, table_index,
1920 top);
1921 cpl_table_set_array(sub_trace_wave, CR2RES_COL_SLIT_FRACTION,
1922 table_index, fraction);
1923 cpl_table_set_array(sub_trace_wave, CR2RES_COL_WAVELENGTH,
1924 table_index, wave);
1925
1926 // keep wavelength error from original order
1927 cpl_table_set_array(sub_trace_wave, CR2RES_COL_WAVELENGTH_ERROR,
1928 table_index, wave_err);
1929
1930 // set slit polynomials to default values for now
1931 cpl_table_set_array(sub_trace_wave, CR2RES_COL_SLIT_CURV_A,
1932 table_index, slit_a);
1933 cpl_table_set_array(sub_trace_wave, CR2RES_COL_SLIT_CURV_B,
1934 table_index, slit_b);
1935 cpl_table_set_array(sub_trace_wave, CR2RES_COL_SLIT_CURV_C,
1936 table_index, slit_c);
1937
1938 // Clean up data
1939 cpl_array_delete(bottom);
1940 cpl_array_delete(center);
1941 cpl_array_delete(top);
1942 cpl_array_delete(fraction);
1943 cpl_array_delete(wave);
1944 }
1945 if (res == -1) break;
1946 }
1947 cpl_free(order_idx_values);
1948
1949 if (res == -1) {
1950 cpl_table_delete(sub_trace_wave);
1951 return NULL ;
1952 }
1953 return sub_trace_wave ;
1954}
1955
1956/*----------------------------------------------------------------------------*/
1964/*----------------------------------------------------------------------------*/
1966 const cpl_table * tw,
1967 const char * setting,
1968 int zp_order)
1969{
1970 cpl_table * selected_tw ;
1971 cpl_table * filtered_tw ;
1972 cpl_size nrows, i ;
1973
1974 selected_tw = cpl_table_duplicate(tw) ;
1975 nrows = cpl_table_get_nrow(selected_tw) ;
1976 for (i=0 ; i<nrows ; i++) {
1977 int order_idx, order_real ;
1978 order_idx = cpl_table_get(selected_tw, CR2RES_COL_ORDER, i, NULL) ;
1979 order_real = cr2res_order_idx_to_real(order_idx, zp_order) ;
1980 if (cr2res_trace_filter_keep(setting, order_real)) {
1981 cpl_table_select_row(selected_tw, i) ;
1982 } else {
1983 cpl_table_unselect_row(selected_tw, i) ;
1984 }
1985 }
1986 filtered_tw = cpl_table_extract_selected(selected_tw) ;
1987 cpl_table_delete(selected_tw) ;
1988 return filtered_tw ;
1989}
1990
1992#ifdef CR2RES_UNUSED
1993/*----------------------------------------------------------------------------*/
2006/*----------------------------------------------------------------------------*/
2007static double cr2res_trace_compute_shift(
2008 const cpl_table * traces1,
2009 const cpl_table * traces2)
2010{
2011 cpl_size i ;
2012
2013 for (i=0 ; i<cpl_table_get_nrow(traces1) ; i++) {
2014 int order_idx;
2015 order_idx = cpl_table_get(traces1, CR2RES_COL_ORDER, i, NULL) ;
2016 if (order_idx >= 0) {
2017
2018 }
2019 }
2020 cpl_msg_warning(__func__, "NOT YET IMPLEMENTED") ;
2021 return 0.0 ;
2022}
2023
2024/*----------------------------------------------------------------------------*/
2031/*----------------------------------------------------------------------------*/
2032static int cr2res_trace_apply_shift(
2033 cpl_table * traces,
2034 double shift)
2035{
2036 return -1 ;
2037}
2038#endif
2039
2040/*----------------------------------------------------------------------------*/
2055/*----------------------------------------------------------------------------*/
2056static cpl_array * cr2res_trace_get_slit_frac(
2057 const cpl_table * traces,
2058 cpl_size idx,
2059 cr2res_decker decker_pos)
2060{
2061 cpl_array * slit_frac ;
2062 int order_idx ;
2063 cpl_size nb_traces, other_idx, i ;
2064 double center_pos_curr, center_pos_other ;
2065
2066 /* Get the current trace order */
2067 order_idx = cpl_table_get(traces, CR2RES_COL_ORDER, idx, NULL) ;
2068
2069 /* Get the number of traces of this order */
2070 nb_traces = cr2res_get_nb_traces(traces, order_idx) ;
2071
2072 /* The number of traces and the decker positions need to be consistent */
2073 if (nb_traces == 1 && decker_pos == CR2RES_DECKER_NONE) {
2074 /* TRACE_OPEN */
2075 slit_frac = cr2res_trace_slit_fraction_create(decker_pos, 0) ;
2076 } else if (nb_traces == 2 &&
2077 (decker_pos==CR2RES_DECKER_1_3 || decker_pos==CR2RES_DECKER_2_4)) {
2078 /* DECKER - Identify if the trace is the lower or upper one */
2079 center_pos_curr = cr2res_trace_get_trace_ypos(traces, idx) ;
2080
2081 /* Search the other trace */
2082 other_idx = -1 ;
2083 for (i=0 ; i<cpl_table_get_nrow(traces) ; i++) {
2084 if (cpl_table_get(traces, CR2RES_COL_ORDER, i, NULL)==order_idx &&
2085 i != idx) other_idx = i ;
2086 }
2087 if (other_idx < 0) return NULL ;
2088
2089 /* Get the position of the other trace */
2090 center_pos_other = cr2res_trace_get_trace_ypos(traces, other_idx) ;
2091
2092 /* Write the result */
2093 if (center_pos_curr < center_pos_other) {
2094 /* Lower Trace */
2095 slit_frac = cr2res_trace_slit_fraction_create(decker_pos, 2) ;
2096 } else {
2097 /* Upper Trace */
2098 slit_frac = cr2res_trace_slit_fraction_create(decker_pos, 1) ;
2099 }
2100 } else {
2101 /* Inconsistent */
2102 slit_frac = NULL ;
2103 }
2104 return slit_frac ;
2105}
2106
2107/*----------------------------------------------------------------------------*/
2120/*----------------------------------------------------------------------------*/
2121static cpl_mask * cr2res_trace_signal_detect(
2122 const cpl_image * image,
2123 int smooth_x,
2124 int smooth_y,
2125 double thresh)
2126{
2127 cpl_image *smx_image;
2128 cpl_image *smxy_image;
2129 int kernel_x, kernel_y;
2130 cpl_mask *kernel;
2131 cpl_mask *mask;
2132
2133 /* Check Entries */
2134 if (image == NULL) return NULL;
2135 if (cpl_image_get_type(image) != CPL_TYPE_DOUBLE) {
2136 cpl_msg_error(__func__,"Expecting double image.");
2137 return NULL;
2138 }
2139 if (smooth_x < 0 || smooth_y < 0) return NULL;
2140
2141 /* Prepare kernel */
2142 kernel_x = smooth_x;
2143 if (kernel_x % 2 == 0) kernel_x++;
2144 kernel_y = smooth_y ;
2145 if (kernel_y % 2 == 0) kernel_y++;
2146
2147 // Start with smooth in X
2148 kernel = cpl_mask_new(kernel_x, 1);
2149 cpl_mask_not(kernel);
2150
2151 smx_image = cpl_image_duplicate(image);
2152 if (cpl_image_filter_mask(smx_image, image, kernel, CPL_FILTER_AVERAGE_FAST,
2153 CPL_BORDER_FILTER) != CPL_ERROR_NONE) {
2154 cpl_msg_error(__func__, "Cannot filter the image");
2155 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
2156 cpl_mask_delete(kernel);
2157 cpl_image_delete(smx_image);
2158 return NULL;
2159 }
2160 cpl_mask_delete(kernel);
2161 #ifndef CR2RES_UNUSED
2162 // Filter log image instead of the original
2163 /* Shift image to counts >1 so that log works */
2164 double img_min = cpl_image_get_min(smx_image) - 1.0;
2165 cpl_image_subtract_scalar(smx_image, img_min);
2166 smxy_image = cpl_image_logarithm_create(smx_image, CPL_MATH_E);
2167
2168 // Boxcar average instead of optimal filter
2169 cpl_image *tmp_image;
2170 kernel = cpl_mask_new(1, kernel_y);
2171 cpl_mask_not(kernel);
2172 tmp_image = cpl_image_duplicate(smxy_image);
2173 if (cpl_image_filter_mask(smxy_image, tmp_image, kernel,
2174 CPL_FILTER_AVERAGE_FAST,
2175 CPL_BORDER_FILTER) != CPL_ERROR_NONE) {
2176 cpl_msg_error(__func__, "Cannot filter the image");
2177 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
2178 cpl_mask_delete(kernel);
2179 cpl_image_delete(smx_image);
2180 cpl_image_delete(tmp_image);
2181 return NULL;
2182 }
2183 cpl_mask_delete(kernel);
2184 cpl_image_delete(tmp_image);
2185
2186 // Potentiating the filtered image before comparing to the original
2187 if (cpl_image_exponential(smxy_image, CPL_MATH_E) != CPL_ERROR_NONE)
2188 cpl_msg_error(__func__, "Cannot exponentiate the smxy_image");
2189 #endif
2190
2191 #ifdef CR2RES_UNUSED
2192
2193
2194 double *smxy_data;
2195 double *img_column;
2196 int options[3];
2197 cpl_size icol, ncols, irow, nrows;
2198 int log, opt_filter;
2199 /* Flags. TODO: decide whether to expose these to caller and/or user */
2200 log=1;
2201 opt_filter=0;
2202
2203 if (log) { // Filter log image instead of the original
2204 /* Shift image to counts >1 so that log works */
2205 double img_min = cpl_image_get_min(smx_image)-1.0;
2206 cpl_image_subtract_scalar(smx_image, img_min);
2207 smxy_image = cpl_image_logarithm_create(smx_image, CPL_MATH_E);
2208 } else {
2209 smxy_image = cpl_image_duplicate(smx_image);
2210 }
2211
2212 if (opt_filter) { /* Vertical filtering is done using optimal filter */
2213
2214 cpl_mask *smxy_mask;
2215 cpl_binary *smxy_mskdata;
2216 double *wgt_column;
2217 // TODO: Move filter preparation into own function and call this instead
2218 /* Number of columns */
2219 ncols = cpl_image_get_size_x(image);
2220 nrows = cpl_image_get_size_y(image);
2221 /* Set options */
2222 options[0]=options[2]=0;
2223 options[1]=1;
2224 smxy_mask = cpl_image_get_bpm(smxy_image);
2225 smxy_mskdata = cpl_mask_get_data(smxy_mask);
2226 smxy_data = cpl_image_get_data_double(smxy_image);
2227 img_column = (double *)cpl_malloc(nrows*sizeof(double));
2228 wgt_column = (double *)cpl_malloc(nrows*sizeof(double));
2229
2230 for (icol=0; icol<ncols; icol++) {
2231 for (irow=0; irow<nrows; irow++) {
2232 img_column[irow] = smxy_data[icol+irow*ncols];
2233 wgt_column[irow] = !smxy_mskdata[icol+irow*ncols];
2234 }
2235 if (cr2res_util_optimal_filter_1d(img_column, (double)smooth_y,
2236 img_column, nrows, options,
2237 NULL, wgt_column, 0.) != CPL_ERROR_NONE) {
2238 cpl_msg_error(__func__, "Cannot filter the image");
2239 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
2240 cpl_image_delete(smx_image);
2241 cpl_image_delete(smxy_image);
2242 cpl_free(img_column);
2243 cpl_free(wgt_column);
2244 return NULL;
2245 }
2246 for (irow=0; irow<nrows; irow++)
2247 smxy_data[icol+irow*ncols] = img_column[irow];
2248 }
2249 cpl_free(img_column);
2250 cpl_free(wgt_column);
2251 }
2252 else { // Boxcar average instead of optimal filter
2253 cpl_image *tmp_image;
2254 kernel = cpl_mask_new(1, kernel_y);
2255 cpl_mask_not(kernel);
2256 tmp_image = cpl_image_duplicate(smxy_image);
2257 if (cpl_image_filter_mask(smxy_image, tmp_image, kernel,
2258 CPL_FILTER_AVERAGE_FAST,
2259 CPL_BORDER_FILTER) != CPL_ERROR_NONE) {
2260 cpl_msg_error(__func__, "Cannot filter the image");
2261 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
2262 cpl_mask_delete(kernel);
2263 cpl_image_delete(smx_image);
2264 cpl_image_delete(tmp_image);
2265 return NULL;
2266 }
2267 cpl_mask_delete(kernel);
2268 cpl_image_delete(tmp_image);
2269 }
2270
2271 if (log) {
2272 // Potentiating the filtered image before comparing to the original
2273 if (cpl_image_exponential(smxy_image, CPL_MATH_E) != CPL_ERROR_NONE)
2274 cpl_msg_error(__func__, "Cannot exponentiate the smxy_image");
2275 }
2276 #endif
2277
2278 /* Subtract x-smoothed image from xy-smoothed */
2279 cpl_image_subtract(smx_image, smxy_image);
2280
2281 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
2282 if (cpl_image_save(smxy_image, "debug_smxyimage.fits", CPL_TYPE_DOUBLE,
2283 NULL, CPL_IO_CREATE) != CPL_ERROR_NONE)
2284 cpl_error_reset();
2285 if (cpl_image_save(smx_image, "debug_smximage.fits", CPL_TYPE_DOUBLE,
2286 NULL, CPL_IO_CREATE) != CPL_ERROR_NONE)
2287 cpl_error_reset();
2288 }
2289
2290 /* Wanted pixels are where input image exceeds sm_image by thresh */
2291 mask = cpl_mask_threshold_image_create(smx_image, thresh, DBL_MAX);
2292 cpl_image_delete(smx_image);
2293 cpl_image_delete(smxy_image);
2294
2295 return mask ;
2296}
2297
2298/*----------------------------------------------------------------------------*/
2308/*----------------------------------------------------------------------------*/
2309static cpl_table * cr2res_trace_restore_edge_traces(
2310 cpl_table * trace_table)
2311{
2312 cpl_table * restored_trace_table ;
2313 const cpl_array * coeffs_upper ;
2314 const cpl_array * coeffs_lower ;
2315 cpl_array * new_trace ;
2316 cpl_vector * heights ;
2317 cpl_vector * heights_tmp ;
2318 double height_med, threshold, lowest_pos,
2319 uppest_pos;
2320 cpl_size ntraces, i, lowest_idx, uppest_idx ;
2321
2322 /* Check entries */
2323 if (trace_table == NULL) return NULL ;
2324
2325 /* Initialise */
2326 lowest_idx = uppest_idx = -1 ;
2327 lowest_pos = 2048.0 ;
2328 uppest_pos = 0.0 ;
2329
2330 /* Compute the median height of the traces */
2331 ntraces = cpl_table_get_nrow(trace_table) ;
2332 heights = cpl_vector_new(ntraces) ;
2333 for (i=0 ; i<ntraces ; i++) {
2334 cpl_polynomial * poly_upper ;
2335 cpl_polynomial * poly_lower ;
2336 double height;
2337 double curr_pos;
2338 /* Get the Upper polynomial*/
2339 coeffs_upper = cpl_table_get_array(trace_table, CR2RES_COL_UPPER, i) ;
2340 poly_upper = cr2res_convert_array_to_poly(coeffs_upper) ;
2341
2342 /* Get the Lower polynomial*/
2343 coeffs_lower = cpl_table_get_array(trace_table, CR2RES_COL_LOWER, i) ;
2344 poly_lower = cr2res_convert_array_to_poly(coeffs_lower) ;
2345
2346 /* Keep track of the uppest and lowest */
2347 curr_pos = cpl_polynomial_eval_1d(poly_lower, CR2RES_DETECTOR_SIZE/2.0,
2348 NULL) ;
2349 if (curr_pos < lowest_pos) {
2350 lowest_pos = curr_pos ;
2351 lowest_idx = i ;
2352 }
2353 if (curr_pos > uppest_pos) {
2354 uppest_pos = curr_pos ;
2355 uppest_idx = i ;
2356 }
2357
2358 /* Compute the height */
2359 height = cr2res_trace_compute_height(poly_upper, poly_lower,
2360 CR2RES_DETECTOR_SIZE);
2361 cpl_polynomial_delete(poly_upper) ;
2362 cpl_polynomial_delete(poly_lower) ;
2363 cpl_vector_set(heights, i, height) ;
2364 }
2365
2366 /* Heights statistics */
2367 heights_tmp = cpl_vector_duplicate(heights) ;
2368 height_med = cpl_vector_get_median(heights_tmp) ;
2369 cpl_vector_delete(heights_tmp) ;
2370 threshold = 0.95 * height_med ;
2371 cpl_msg_debug(__func__, "Height Median / Threshold: %g / %g",
2372 height_med, threshold) ;
2373
2374 /* Fix wrong traces */
2375 restored_trace_table = cpl_table_duplicate(trace_table) ;
2376 for (i=0 ; i<ntraces ; i++) {
2377 if (cpl_vector_get(heights, i) < threshold) {
2378 coeffs_upper=cpl_table_get_array(trace_table, CR2RES_COL_UPPER, i) ;
2379 coeffs_lower=cpl_table_get_array(trace_table, CR2RES_COL_LOWER, i) ;
2380 if (i == uppest_idx) {
2381 cpl_msg_warning(__func__, "Restore Upper trace") ;
2382 new_trace = cpl_array_duplicate(coeffs_lower) ;
2383 cpl_array_set(new_trace, 0, cpl_array_get(coeffs_lower,
2384 0, NULL) + height_med);
2385 cpl_table_set_array(restored_trace_table, CR2RES_COL_UPPER, i,
2386 new_trace);
2387 cpl_array_set(new_trace, 0, cpl_array_get(coeffs_lower,
2388 0, NULL) + height_med/2.0);
2389 cpl_table_set_array(restored_trace_table, CR2RES_COL_ALL, i,
2390 new_trace);
2391 cpl_array_delete(new_trace) ;
2392 } else if (i == lowest_idx) {
2393 cpl_msg_warning(__func__, "Restore Lower trace") ;
2394 new_trace = cpl_array_duplicate(coeffs_upper) ;
2395 cpl_array_set(new_trace, 0, cpl_array_get(coeffs_upper,
2396 0, NULL) - height_med);
2397 cpl_table_set_array(restored_trace_table, CR2RES_COL_LOWER, i,
2398 new_trace);
2399 cpl_array_set(new_trace, 0, cpl_array_get(coeffs_upper,
2400 0, NULL) - height_med/2.0);
2401 cpl_table_set_array(restored_trace_table, CR2RES_COL_ALL, i,
2402 new_trace);
2403 cpl_array_delete(new_trace) ;
2404 } else {
2405 cpl_msg_warning(__func__,
2406 "Incomplete traces only expected on the lower or upper zones");
2407 }
2408 }
2409 }
2410 cpl_vector_delete(heights) ;
2411 return restored_trace_table ;
2412}
2413
2414/*----------------------------------------------------------------------------*/
2428/*----------------------------------------------------------------------------*/
2429static cpl_table * cr2res_trace_fit_traces(
2430 cpl_table * clustertable,
2431 int degree)
2432{
2433 cpl_table * traces_table;
2434 cpl_table * edge_upper_table = NULL;
2435 cpl_table * edge_lower_table = NULL;
2436 int i, nclusters;
2437
2438 /* Check entries */
2439 if (clustertable == NULL) return NULL ;
2440 if (degree < 0) return NULL;
2441 if (cpl_table_get_nrow(clustertable) == 0) return NULL;
2442 if (cpl_table_has_column(clustertable, CR2RES_COL_CLUSTERS) == 0) return NULL;
2443
2444 /* Create the output table */
2445 nclusters = cpl_table_get_column_max(clustertable, CR2RES_COL_CLUSTERS);
2446
2447 traces_table = cpl_table_new(nclusters);
2448 cpl_table_new_column_array(traces_table, CR2RES_COL_ALL, CPL_TYPE_DOUBLE,
2449 degree+1) ;
2450 cpl_table_new_column_array(traces_table, CR2RES_COL_UPPER, CPL_TYPE_DOUBLE,
2451 degree+1) ;
2452 cpl_table_new_column_array(traces_table, CR2RES_COL_LOWER, CPL_TYPE_DOUBLE,
2453 degree+1) ;
2454
2455 /* Loop on the clusters */
2456 for (i=1 ; i<=nclusters ; i++) {
2457
2458 cpl_array * fitparams_all;
2459 cpl_array * fitparams_upper;
2460 cpl_array * fitparams_lower;
2461 cpl_table * trace_table;
2462 cpl_size nclusters_cur;
2463 /* Select the pixels of the current cluster */
2464 nclusters_cur = cpl_table_and_selected_int(clustertable,
2465 CR2RES_COL_CLUSTERS, CPL_EQUAL_TO, i);
2466 cpl_msg_debug(__func__, "Cluster %d has %"CPL_SIZE_FORMAT" pixels",
2467 i, nclusters_cur);
2468
2469 /* Extract the table with the current trace pixels */
2470 trace_table = cpl_table_extract_selected(clustertable);
2471
2472 /* Fit the current trace */
2473 fitparams_all = cr2res_trace_fit_trace(trace_table, degree);
2474 cpl_table_set_array(traces_table, "All", i-1, fitparams_all);
2475 cpl_array_delete(fitparams_all);
2476
2477 /* Extract the edges of the current trace pixels */
2478 cr2res_trace_extract_edges(trace_table, &edge_lower_table,
2479 &edge_upper_table) ;
2480
2481 /* Fit the upper edge of the current trace */
2482 fitparams_upper = cr2res_trace_fit_trace(edge_upper_table, degree);
2483 cpl_table_delete(edge_upper_table);
2484 cpl_table_set_array(traces_table, CR2RES_COL_UPPER, i-1,
2485 fitparams_upper);
2486 cpl_array_delete(fitparams_upper);
2487
2488 /* Fit the lower edge of the current trace */
2489 fitparams_lower = cr2res_trace_fit_trace(edge_lower_table, degree);
2490 cpl_table_delete(edge_lower_table);
2491 cpl_table_set_array(traces_table, CR2RES_COL_LOWER, i-1,
2492 fitparams_lower);
2493 cpl_array_delete(fitparams_lower);
2494
2495 cpl_table_delete(trace_table);
2496
2497 /* Reset the selection */
2498 cpl_table_select_all(clustertable);
2499 }
2500 return traces_table;
2501}
2502
2503/*----------------------------------------------------------------------------*/
2517/*----------------------------------------------------------------------------*/
2518static cpl_array * cr2res_trace_fit_trace(
2519 cpl_table * table,
2520 int degree)
2521{
2522 cpl_matrix * x ;
2523 cpl_vector * y ;
2524 cpl_polynomial * poly1 ;
2525 cpl_array * result ;
2526 int * xs;
2527 int * ys;
2528 int x_min, x_max ;
2529 cpl_size i, degree_local, n ;
2530
2531 /* Check Entries */
2532 if (table == NULL || degree < 0) return NULL ;
2533
2534 /* Initialise */
2535 n = cpl_table_get_nrow(table) ;
2536 degree_local = (cpl_size)degree ;
2537 x_min = x_max = -1 ;
2538
2539 /* Create Objects */
2540 x = cpl_matrix_new(1, n) ;
2541 y = cpl_vector_new(n) ;
2542
2543 xs = cpl_table_get_data_int(table, CR2RES_COL_XS);
2544 ys = cpl_table_get_data_int(table, CR2RES_COL_YS);
2545 for (i=0 ; i<n ; i++) {
2546 /* Compute x_min and x_max */
2547 if (x_min < 0 || xs[i] < x_min) x_min = xs[i] ;
2548 if (x_max < 0 || xs[i] > x_max) x_max = xs[i] ;
2549
2550 /* Fill the objects used for fitting */
2551 cpl_matrix_set(x, 0, i, xs[i]) ;
2552 cpl_vector_set(y, i, (double)ys[i]) ;
2553 }
2554
2555 /* If the xs range is too small, reduce the degree */
2556 /* This case corresponds to the traces that appear on the image corner */
2557 if (x_max - x_min < 1500) degree_local = 1 ;
2558
2559 /* Apply the fit */
2560 poly1 = cpl_polynomial_new(1) ;
2561 if (cpl_polynomial_fit(poly1, x, NULL, y, NULL, CPL_FALSE, NULL,
2562 &degree_local) != CPL_ERROR_NONE) {
2563 cpl_msg_error(__func__, "Cannot fit the data") ;
2564 cpl_matrix_delete(x);
2565 cpl_vector_delete(y);
2566 cpl_polynomial_delete(poly1);
2567 cpl_error_reset();
2568 return NULL;
2569 }
2570 cpl_matrix_delete(x);
2571 cpl_vector_delete(y);
2572
2573 /* Store the result */
2574 result = cr2res_convert_poly_to_array(poly1, degree+1) ;
2575 cpl_polynomial_delete(poly1);
2576 return result;
2577}
2578
2579/*----------------------------------------------------------------------------*/
2589/*----------------------------------------------------------------------------*/
2590static cpl_table * cr2res_trace_convert_labels_to_cluster(cpl_image * labels)
2591{
2592 const int * plabels ;
2593 cpl_table * clustertable ;
2594 int nb_table_entries, nx, ny, i, j ;
2595
2596
2597 if (labels == NULL) return NULL;
2598 /* Count the number of pixels that are not 0 */
2599 nb_table_entries = 0 ;
2600 plabels = cpl_image_get_data_int_const(labels) ;
2601 nx = cpl_image_get_size_x(labels) ;
2602 ny = cpl_image_get_size_y(labels) ;
2603 for (i=0 ; i<nx*ny ; i++)
2604 if (plabels[i] > 0.5) nb_table_entries ++ ;
2605 cpl_msg_debug(__func__, "Number of table entries: %d", nb_table_entries) ;
2606
2607 /* Create the output table */
2608 clustertable = cpl_table_new(nb_table_entries);
2609 cpl_table_new_column(clustertable, CR2RES_COL_XS, CPL_TYPE_INT) ;
2610 cpl_table_new_column(clustertable, CR2RES_COL_YS, CPL_TYPE_INT) ;
2611 cpl_table_new_column(clustertable, CR2RES_COL_CLUSTERS, CPL_TYPE_INT) ;
2612 nb_table_entries = 0 ;
2613 for (j=0 ; j<ny ; j++) {
2614 for (i=0 ; i<nx ; i++) {
2615 if (plabels[i+j*nx] > 0.5) {
2616 cpl_table_set_int(clustertable, CR2RES_COL_XS, nb_table_entries,
2617 i+1) ;
2618 cpl_table_set_int(clustertable, CR2RES_COL_YS, nb_table_entries,
2619 j+1) ;
2620 cpl_table_set_int(clustertable, CR2RES_COL_CLUSTERS,
2621 nb_table_entries, plabels[i+j*nx]) ;
2622 nb_table_entries ++ ;
2623 }
2624 }
2625 }
2626 return clustertable ;
2627}
2628
2629/*----------------------------------------------------------------------------*/
2636/*----------------------------------------------------------------------------*/
2637static cpl_mask * cr2res_trace_clean_blobs(
2638 cpl_mask * mask,
2639 int min_cluster)
2640{
2641 cpl_mask * new_mask ;
2642 cpl_image * labels ;
2643 cpl_size nlabels ;
2644 cpl_binary * pnew_mask ;
2645 const int * plabels ;
2646 int i, curr_label, npix ;
2647
2648 /* Check entries */
2649 if (mask == NULL) return NULL ;
2650 if (min_cluster < 0) return NULL;
2651
2652 /* Labelise */
2653 if ((labels = cpl_image_labelise_mask_create(mask, &nlabels)) == NULL) {
2654 cpl_msg_error(__func__, "Failed to labelise") ;
2655 return NULL ;
2656 }
2657 if (nlabels > 10000) {
2658 cpl_msg_error(__func__, "Too many labels resulting from mask") ;
2659 cpl_image_delete(labels) ;
2660 return NULL ;
2661 }
2662 plabels = cpl_image_get_data_int_const(labels) ;
2663
2664 /* Number of pixels */
2665 npix = cpl_mask_get_size_x(mask) * cpl_mask_get_size_y(mask) ;
2666
2667 /* Create Output mask */
2668 new_mask=cpl_mask_new(cpl_mask_get_size_x(mask),cpl_mask_get_size_y(mask));
2669 pnew_mask = cpl_mask_get_data(new_mask) ;
2670
2671 /* Loop on the labels */
2672 for (curr_label=1 ; curr_label<=nlabels ; curr_label++) {
2673 int pix_count;
2674 pix_count = 0 ;
2675
2676 /* Count occurrences of current label */
2677 for (i=0 ; i<npix ; i++) {
2678 if (plabels[i] == curr_label) pix_count++ ;
2679 if (pix_count >= min_cluster) break;
2680 }
2681
2682 /* Blob big enough ? */
2683 if (pix_count >= min_cluster) {
2684 /* Fill the new mask */
2685 for (i=0 ; i<npix ; i++)
2686 if (plabels[i] == curr_label) pnew_mask[i] = CPL_BINARY_1 ;
2687 }
2688 }
2689 cpl_image_delete(labels) ;
2690
2691 return new_mask ;
2692}
2693
2694/*----------------------------------------------------------------------------*/
2705/*----------------------------------------------------------------------------*/
2706static int cr2res_trace_extract_edges(
2707 cpl_table * pixels_table,
2708 cpl_table ** edge_lower_table,
2709 cpl_table ** edge_upper_table)
2710{
2711 cpl_table * upper_sel ;
2712 cpl_table * lower_sel ;
2713 const int * pxs ;
2714 const int * pys ;
2715 int * min_y ;
2716 int * max_y ;
2717 int max_x, i ;
2718
2719 /* Check entries */
2720 if (pixels_table == NULL || edge_lower_table == NULL ||
2721 edge_upper_table == NULL) return -1 ;
2722
2723 /* Initialise */
2724 pxs = cpl_table_get_data_int_const(pixels_table, CR2RES_COL_XS) ;
2725 pys = cpl_table_get_data_int_const(pixels_table, CR2RES_COL_YS) ;
2726
2727 /* Get the maximum x position */
2728 max_x = (int)cpl_table_get_column_max(pixels_table, CR2RES_COL_XS) ;
2729
2730 /* Allocate */
2731 min_y = cpl_malloc(max_x * sizeof(int)) ;
2732 max_y = cpl_malloc(max_x * sizeof(int)) ;
2733 for (i=0 ; i<max_x ; i++) min_y[i] = max_y[i] = -1 ;
2734
2735 /* Loop over the pixels table to compute the edges positions */
2736 for (i=0 ; i<cpl_table_get_nrow(pixels_table) ; i++) {
2737 if (pys[i] < min_y[pxs[i]-1] || min_y[pxs[i]-1] < 0)
2738 min_y[pxs[i]-1] = pys[i] ;
2739 if (pys[i] > max_y[pxs[i]-1] || max_y[pxs[i]-1] < 0)
2740 max_y[pxs[i]-1] = pys[i] ;
2741 }
2742
2743 /* Upper Edge extraction */
2744 upper_sel = cpl_table_duplicate(pixels_table) ;
2745 cpl_table_unselect_all(upper_sel) ;
2746 pxs = cpl_table_get_data_int_const(upper_sel, CR2RES_COL_XS) ;
2747 pys = cpl_table_get_data_int_const(upper_sel, CR2RES_COL_YS) ;
2748 for (i=0 ; i<cpl_table_get_nrow(upper_sel) ; i++)
2749 if (max_y[pxs[i]-1] == pys[i])
2750 cpl_table_select_row(upper_sel, i) ;
2751 cpl_free(max_y) ;
2752 *edge_upper_table = cpl_table_extract_selected(upper_sel) ;
2753 cpl_table_delete(upper_sel) ;
2754
2755 /* Lower Edge extraction */
2756 lower_sel = cpl_table_duplicate(pixels_table) ;
2757 cpl_table_unselect_all(lower_sel) ;
2758 pxs = cpl_table_get_data_int_const(lower_sel, CR2RES_COL_XS) ;
2759 pys = cpl_table_get_data_int_const(lower_sel, CR2RES_COL_YS) ;
2760 for (i=0 ; i<cpl_table_get_nrow(lower_sel) ; i++)
2761 if (min_y[pxs[i]-1] == pys[i])
2762 cpl_table_select_row(lower_sel, i) ;
2763 cpl_free(min_y) ;
2764 *edge_lower_table = cpl_table_extract_selected(lower_sel) ;
2765 cpl_table_delete(lower_sel) ;
2766
2767 return CPL_ERROR_NONE ;
2768}
2769
2770/*----------------------------------------------------------------------------*/
2777/*----------------------------------------------------------------------------*/
2778static int cr2res_trace_check_slit_fraction(const cpl_array * slit_fraction)
2779{
2780 double low, mid, up ;
2781
2782 /* Check entries */
2783 if (slit_fraction == NULL) return -1;
2784
2785 /* Get the values */
2786 low = cpl_array_get(slit_fraction, 0, NULL) ;
2787 mid = cpl_array_get(slit_fraction, 1, NULL) ;
2788 up = cpl_array_get(slit_fraction, 2, NULL) ;
2789
2790 if (cpl_error_get_code() != CPL_ERROR_NONE) return -1 ;
2791
2792 if (up<0.0 || low<0.0 || mid<0.0 || up>1.0 || low>1.0 || mid>1.0)
2793 return 0 ;
2794 if (low>mid || mid > up)
2795 return 0 ;
2796 return 1 ;
2797}
2798
2799/*----------------------------------------------------------------------------*/
2813/*----------------------------------------------------------------------------*/
2814static int cr2res_trace_new_trace(
2815 const cpl_array * slit_fraction_in,
2816 const cpl_array ** trace_in,
2817 const int nb_traces,
2818 const cpl_array * slit_fraction_wished,
2819 cpl_array ** trace_all_new,
2820 cpl_array ** trace_upper_new,
2821 cpl_array ** trace_lower_new)
2822{
2823 cpl_polynomial ** poly_in ;
2824 cpl_polynomial * poly_slit;
2825 cpl_polynomial * poly_upper_out ;
2826 cpl_polynomial * poly_lower_out ;
2827 cpl_polynomial * poly_all_out ;
2828 const cpl_size power = 0 ;
2829 cpl_array * trace_all_out ;
2830 cpl_array * trace_upper_out ;
2831 cpl_array * trace_lower_out ;
2832 cpl_matrix * sf_matrix;
2833 cpl_error_code error;
2834 cpl_size fitdeg;
2835 const double * sf_in;
2836 cpl_vector * pix_in;
2837 double sf_out_l, sf_out_m, sf_out_u, pix_out_l, pix_out_u,
2838 pix_out_m, new_coeff ;
2839
2840 /* Check entries */
2841 if (slit_fraction_in==NULL || trace_in==NULL || slit_fraction_wished==NULL
2842 || trace_all_new==NULL || trace_upper_new==NULL
2843 || trace_lower_new==NULL || nb_traces <= 0) return -1;
2844
2845 // Both in and output slit fractions need to have 3 components
2846 // (3 per trace for input)
2847 if (cpl_array_get_size(slit_fraction_in) != 3 * nb_traces ||
2848 cpl_array_get_size(slit_fraction_wished) != 3) return -1;
2849
2850
2851
2852 /* Get wished slit positions in arcseconds */
2853 sf_out_l = cpl_array_get(slit_fraction_wished, 0, NULL) ;
2854 sf_out_m = cpl_array_get(slit_fraction_wished, 1, NULL) ;
2855 sf_out_u = cpl_array_get(slit_fraction_wished, 2, NULL) ;
2856
2857 // Allocate memory
2858 poly_in = cpl_malloc(3 * nb_traces * sizeof(cpl_polynomial*));
2859 for (cpl_size i = 0; i < nb_traces * 3; i++) poly_in[i] = NULL;
2860 pix_in = cpl_vector_new(3 * nb_traces);
2861
2862 /* Get input slit positions in pixels from middle of the traces */
2863 for(cpl_size i = 0; i < nb_traces * 3; i++)
2864 {
2865 poly_in[i] = cr2res_convert_array_to_poly(trace_in[i]);
2866 cpl_vector_set(pix_in, i, cpl_polynomial_eval_1d(poly_in[i],
2867 (double)(CR2RES_DETECTOR_SIZE/2.0), NULL));
2868 }
2869
2870 // Fit a 2nd order polynomial to all points
2871 poly_slit = cpl_polynomial_new(1);
2872 /* Get input slit positions in arcseconds */
2873 sf_in = cpl_array_get_data_double_const(slit_fraction_in);
2874 sf_matrix = cpl_matrix_wrap(1, nb_traces * 3, (double*)sf_in);
2875 fitdeg = 2;
2876 error = cpl_polynomial_fit(poly_slit, sf_matrix, NULL, pix_in, NULL,
2877 CPL_FALSE, NULL, &fitdeg);
2878 cpl_matrix_unwrap(sf_matrix);
2879
2880 // in case something went wrong
2881 if (error != CPL_ERROR_NONE){
2882 cpl_polynomial_delete(poly_slit);
2883 for(cpl_size i = 0; i < nb_traces*3; i++)
2884 {
2885 cpl_polynomial_delete(poly_in[i]);
2886 }
2887 cpl_free(poly_in);
2888 cpl_vector_delete(pix_in);
2889 cpl_error_reset();
2890 return -1;
2891 }
2892
2893 /* Compute the Pixel positions on the wished slit fraction */
2894 pix_out_l = cpl_polynomial_eval_1d(poly_slit, sf_out_l, NULL);
2895 pix_out_m = cpl_polynomial_eval_1d(poly_slit, sf_out_m, NULL);
2896 pix_out_u = cpl_polynomial_eval_1d(poly_slit, sf_out_u, NULL);
2897
2898 /* Debug Message */
2899 cpl_msg_debug(__func__,
2900 "Slit fraction: [%g-%g-%g]->[%g-%g-%g] - Pixel positions: [%g-%g-%g]->[%g-%g-%g]",
2901 sf_in[0], sf_in[1], sf_in[2], sf_out_l, sf_out_m, sf_out_u,
2902 cpl_vector_get(pix_in, 0), cpl_vector_get(pix_in, 1),
2903 cpl_vector_get(pix_in, 2), pix_out_l, pix_out_m, pix_out_u) ;
2904
2905 /* Correct the polynomials */
2906 poly_upper_out = cpl_polynomial_duplicate(poly_in[2]) ;
2907 poly_lower_out = cpl_polynomial_duplicate(poly_in[0]) ;
2908 poly_all_out = cpl_polynomial_duplicate(poly_in[1]) ;
2909
2910 new_coeff = cpl_polynomial_get_coeff(poly_upper_out, &power) + pix_out_u
2911 - cpl_vector_get(pix_in, 2) ;
2912 cpl_polynomial_set_coeff(poly_upper_out, &power, new_coeff) ;
2913 new_coeff = cpl_polynomial_get_coeff(poly_lower_out, &power) + pix_out_l
2914 - cpl_vector_get(pix_in, 0) ;
2915 cpl_polynomial_set_coeff(poly_lower_out, &power, new_coeff) ;
2916 new_coeff = cpl_polynomial_get_coeff(poly_all_out, &power) + pix_out_m
2917 - cpl_vector_get(pix_in, 1) ;
2918 cpl_polynomial_set_coeff(poly_all_out, &power, new_coeff) ;
2919
2920 for(cpl_size i = 0; i < nb_traces*3; i++)
2921 {
2922 cpl_polynomial_delete(poly_in[i]);
2923 }
2924 cpl_free(poly_in);
2925 cpl_vector_delete(pix_in);
2926 cpl_polynomial_delete(poly_slit);
2927
2928
2929 /* Convert to arrays */
2930 trace_all_out = cr2res_convert_poly_to_array(poly_all_out,
2931 cpl_array_get_size(trace_in[1]));
2932 trace_upper_out = cr2res_convert_poly_to_array(poly_upper_out,
2933 cpl_array_get_size(trace_in[2]));
2934 trace_lower_out = cr2res_convert_poly_to_array(poly_lower_out,
2935 cpl_array_get_size(trace_in[0]));
2936 cpl_polynomial_delete(poly_all_out) ;
2937 cpl_polynomial_delete(poly_upper_out) ;
2938 cpl_polynomial_delete(poly_lower_out) ;
2939
2940 /* Check */
2941 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2942 cpl_array_delete(trace_all_out) ;
2943 cpl_array_delete(trace_upper_out) ;
2944 cpl_array_delete(trace_lower_out) ;
2945 return -1 ;
2946 }
2947
2948 /* Return */
2949 *trace_all_new = trace_all_out ;
2950 *trace_upper_new = trace_upper_out ;
2951 *trace_lower_new = trace_lower_out ;
2952 return 0 ;
2953}
2954
2955/*----------------------------------------------------------------------------*/
2975/*----------------------------------------------------------------------------*/
2976static int cr2res_trace_get_subtrace(
2977 cpl_table * trace_wave,
2978 double slit_pos,
2979 double height,
2980 int order_idx,
2981 cpl_array ** bottom,
2982 cpl_array ** center,
2983 cpl_array ** top,
2984 cpl_array ** fraction,
2985 cpl_array ** wave)
2986{
2987 // check input values
2988 if (slit_pos < 0 || slit_pos > 1) return -1;
2989 if (bottom != NULL && *bottom == NULL) return -1;
2990 if (center != NULL && *center == NULL) return -1;
2991 if (top != NULL && *top == NULL) return -1;
2992 if (fraction != NULL && *fraction == NULL) return -1;
2993 if (wave != NULL && *wave == NULL) return -1;
2994
2995 // get trace numbers
2996 int nb_traces;
2997 int * traces;
2998 traces = cr2res_get_trace_numbers(trace_wave, order_idx, &nb_traces);
2999 if (traces == NULL) return -1;
3000
3001 const cpl_array * bounds[3], *old_fraction;
3002 double res;
3003 cpl_size i, j, k, ndegree;
3004
3005 cpl_matrix * samppos;
3006 cpl_vector *fitvals;
3007 cpl_polynomial * poly;
3008
3009 // Each trace has 3 components, so we can always fit a 2nd order polynomial
3010 cpl_size maxdeg = 2;
3011 cpl_error_code error = CPL_ERROR_NONE;
3012
3013 // interpolate order tracing
3014 ndegree = cpl_table_get_column_dimension(trace_wave, CR2RES_COL_ALL, 0);
3015 samppos = cpl_matrix_new(1, 3 * nb_traces);
3016 fitvals = cpl_vector_new(3 * nb_traces);
3017 poly = cpl_polynomial_new(1);
3018
3019 for (i = 0; i < ndegree; i++){
3020 for (k = 0; k < nb_traces; k++){
3021 j = cr2res_get_trace_table_index(trace_wave, order_idx, traces[k]);
3022
3023 bounds[0] = cpl_table_get_array(trace_wave, CR2RES_COL_LOWER, j);
3024 bounds[1] = cpl_table_get_array(trace_wave, CR2RES_COL_ALL, j);
3025 bounds[2] = cpl_table_get_array(trace_wave, CR2RES_COL_UPPER, j);
3026 old_fraction = cpl_table_get_array(trace_wave,
3027 CR2RES_COL_SLIT_FRACTION, j);
3028
3029 for (j = 0; j < 3; j++){
3030 res = cpl_array_get_double(old_fraction, j, NULL);
3031 if (res == -1) res = 0.5 * j; // bottom: 0, center: 0.5, top: 1
3032 cpl_matrix_set(samppos, 0, k * 3 + j, res);
3033 cpl_vector_set(fitvals, k * 3 + j,
3034 cpl_array_get_double(bounds[j], i, NULL));
3035 }
3036 }
3037
3038 error = cpl_polynomial_fit(poly, samppos, NULL, fitvals, NULL, 1,
3039 NULL, &maxdeg);
3040
3041 if (center != NULL){
3042 res = cpl_polynomial_eval_1d(poly, slit_pos, NULL);
3043 cpl_array_set_double(*center, i, res);
3044 }
3045
3046 if (top != NULL){
3047 res = cpl_polynomial_eval_1d(poly, slit_pos + height, NULL);
3048 cpl_array_set_double(*top, i, res);
3049 }
3050
3051 if (bottom != NULL){
3052 res = cpl_polynomial_eval_1d(poly, slit_pos - height, NULL);
3053 cpl_array_set_double(*bottom, i, res);
3054 }
3055
3056 }
3057 cpl_matrix_delete(samppos);
3058 cpl_vector_delete(fitvals);
3059 cpl_polynomial_delete(poly);
3060
3061 if (fraction != NULL){
3062 cpl_array_set_double(*fraction, 0, slit_pos-height);
3063 cpl_array_set_double(*fraction, 1, slit_pos);
3064 cpl_array_set_double(*fraction, 2, slit_pos+height);
3065 }
3066
3067 // interpolate wavelength solution, if we have more than one trace
3068 if (wave != NULL){
3069 const cpl_array *old_wave;
3070 if (nb_traces == 1){
3071 j = cr2res_get_trace_table_index(trace_wave, order_idx, traces[0]);
3072 old_wave = cpl_table_get_array(trace_wave, CR2RES_COL_WAVELENGTH, j);
3073 cpl_array_copy_data_double(*wave,
3074 cpl_array_get_data_double_const(old_wave));
3075 } else {
3076 ndegree = cpl_table_get_column_dimension(trace_wave, CR2RES_COL_WAVELENGTH, 0);
3077 maxdeg = min(2, nb_traces - 1);
3078 samppos = cpl_matrix_new(1, nb_traces);
3079 fitvals = cpl_vector_new(nb_traces);
3080 poly = cpl_polynomial_new(1);
3081 for (i = 0; i < ndegree; i++){
3082 for (k = 0; k < nb_traces; k++){
3083 j = cr2res_get_trace_table_index(trace_wave, order_idx,
3084 traces[k]);
3085 old_fraction = cpl_table_get_array(trace_wave,
3086 CR2RES_COL_SLIT_FRACTION, j);
3087 old_wave = cpl_table_get_array(trace_wave,
3088 CR2RES_COL_WAVELENGTH, j);
3089
3090 res = cpl_array_get_double(old_fraction, j, NULL);
3091 if (res == -1) res = 0.5 * j; // bottom: 0, center: 0.5, top: 1
3092
3093 cpl_matrix_set(samppos, 0, k, res);
3094 cpl_vector_set(fitvals, k, cpl_array_get_double(old_wave, i,
3095 NULL));
3096 }
3097 error = cpl_polynomial_fit(poly, samppos, NULL, fitvals, NULL, 1,
3098 NULL, &maxdeg);
3099 res = cpl_polynomial_eval_1d(poly, slit_pos, NULL);
3100 cpl_array_set_double(*wave, i, res);
3101 }
3102 cpl_matrix_delete(samppos);
3103 cpl_vector_delete(fitvals);
3104 cpl_polynomial_delete(poly);
3105 }
3106 }
3107 cpl_free(traces);
3108
3109 if (error != CPL_ERROR_NONE){
3110 cpl_error_reset();
3111 return -1;
3112 }
3113 return 0;
3114}
3115
3116/*----------------------------------------------------------------------------*/
3123/*----------------------------------------------------------------------------*/
3124static int cr2res_trace_filter_keep(
3125 const char * setting,
3126 int real_order)
3127{
3128 int first, last ;
3129 if (setting == NULL) return -1 ;
3130
3131 cpl_msg_debug(__func__, "Real order : %d setting : %s",real_order,setting) ;
3132
3133 /* Misunderstanding - at the end, they do not want to filter any more ! */
3134 cpl_msg_debug(__func__, "Filtering not implemented - Keep everything") ;
3135 return 1 ;
3136
3137 if (!strcmp(setting, "H1559")) { first = 10 ; last = 20 ; }
3138 else if (!strcmp(setting, "H1567")) { first = 10 ; last = 20 ; }
3139 else if (!strcmp(setting, "H1575")) { first = 10 ; last = 20 ; }
3140 else if (!strcmp(setting, "H1582")) { first = 10 ; last = 20 ; }
3141 else if (!strcmp(setting, "J1226")) { first = 10 ; last = 20 ; }
3142 else if (!strcmp(setting, "J1228")) { first = 10 ; last = 20 ; }
3143 else if (!strcmp(setting, "J1232")) { first = 10 ; last = 20 ; }
3144 else if (!strcmp(setting, "K2148")) { first = 10 ; last = 20 ; }
3145 else if (!strcmp(setting, "K2166")) { first = 10 ; last = 20 ; }
3146 else if (!strcmp(setting, "K2192")) { first = 10 ; last = 20 ; }
3147 else if (!strcmp(setting, "K2217")) { first = 10 ; last = 20 ; }
3148 else if (!strcmp(setting, "L3244")) { first = 10 ; last = 20 ; }
3149 else if (!strcmp(setting, "L3262")) { first = 10 ; last = 20 ; }
3150 else if (!strcmp(setting, "L3302")) { first = 10 ; last = 20 ; }
3151 else if (!strcmp(setting, "L3340")) { first = 10 ; last = 20 ; }
3152 else if (!strcmp(setting, "L3377")) { first = 10 ; last = 20 ; }
3153 else if (!strcmp(setting, "L3412")) { first = 10 ; last = 20 ; }
3154 else if (!strcmp(setting, "L3426")) { first = 10 ; last = 20 ; }
3155 else if (!strcmp(setting, "M4187")) { first = 10 ; last = 20 ; }
3156 else if (!strcmp(setting, "M4211")) { first = 10 ; last = 20 ; }
3157 else if (!strcmp(setting, "M4266")) { first = 10 ; last = 20 ; }
3158 else if (!strcmp(setting, "M4318")) { first = 10 ; last = 20 ; }
3159 else if (!strcmp(setting, "M4368")) { first = 10 ; last = 20 ; }
3160 else if (!strcmp(setting, "M4416")) { first = 10 ; last = 20 ; }
3161 else if (!strcmp(setting, "M4461")) { first = 10 ; last = 20 ; }
3162 else if (!strcmp(setting, "M4504")) { first = 10 ; last = 20 ; }
3163 else if (!strcmp(setting, "M4519")) { first = 10 ; last = 20 ; }
3164 else if (!strcmp(setting, "Y1028")) { first = 10 ; last = 20 ; }
3165 else if (!strcmp(setting, "Y1029")) { first = 10 ; last = 20 ; }
3166 else return 1 ;
3167 if (real_order >= first && real_order <= last) return 1 ;
3168 return 0 ;
3169}
int cr2res_dfs_check_traces_table(const cpl_table *traces)
Check completeness of trace table.
Definition: cr2res_dfs.c:581
hdrl_imagelist * cr2res_io_load_image_list_from_set(const cpl_frameset *in, int detector)
Load an hdrl image list from an images frameset.
Definition: cr2res_io.c:808
int cr2res_io_get_ext_idx(const char *filename, int detector, int data)
Get the wished extension number for a detector.
Definition: cr2res_io.c:644
cr2res_decker cr2res_pfits_get_decker_position(const cpl_propertylist *plist)
find out the decker position
Definition: cr2res_pfits.c:467
int cr2res_pfits_get_order_idx(const cpl_propertylist *plist, double yposition)
find out the order_idx closest to the passed y position
Definition: cr2res_pfits.c:412
cpl_vector * cr2res_trace_get_ycen(const cpl_table *trace, int order_idx, int trace_nb, int size)
Retrieves the middle (All) polynomial from trace table and evaluates.
Definition: cr2res_trace.c:769
cpl_vector * cr2res_trace_compute_middle(cpl_polynomial *trace1, cpl_polynomial *trace2, int vector_size)
Computes the positions between 2 trace polynomials.
Definition: cr2res_trace.c:851
cpl_table * cr2res_trace_filter(const cpl_table *tw, const char *setting, int zp_order)
Only keep the predefined orders of the setting.
cpl_image * cr2res_trace_gen_image(cpl_table *trace, int nx, int ny)
Make an image out of the trace solution.
Definition: cr2res_trace.c:362
cpl_size cr2res_get_nb_traces(const cpl_table *trace_wave, int order_idx)
Get the number of traces for a specified order_idx.
Definition: cr2res_trace.c:486
double cr2res_trace_get_trace_ypos(const cpl_table *traces, int idx)
Compute the y position of the trace.
Definition: cr2res_trace.c:923
int cr2res_trace_get_height(const cpl_table *trace, cpl_size order_idx, cpl_size trace_nb)
Computes the average height (pix) of an order, from trace polys.
Definition: cr2res_trace.c:805
cpl_table * cr2res_trace_split(cpl_table *trace_wave, int order_idx, int nb_subtraces)
Splits full slit traces into several sub traces.
cr2res_decker cr2res_trace_slit_fraction_info(const cpl_array *slit_frac, int *up_or_down)
Get a standard slit fraction information.
cpl_table * cr2res_trace(cpl_image *ima, int smooth_x, int smooth_y, double threshold, int opening, int degree, int min_cluster)
Main function for running all parts of the trace algorithm.
Definition: cr2res_trace.c:163
cpl_size cr2res_get_trace_table_index(const cpl_table *trace_wave, int order_idx, int trace_nb)
Get the index in a TRACE_WAVE table.
Definition: cr2res_trace.c:652
cpl_table * cr2res_trace_new_slit_fraction(const cpl_table *traces, const cpl_array *new_slit_fraction)
Recompute the traces at a newly specified slit fraction.
int cr2res_trace_compute_height(cpl_polynomial *trace1, cpl_polynomial *trace2, int vector_size)
Computes extraction height between 2 trace polynomials.
Definition: cr2res_trace.c:886
int * cr2res_get_trace_numbers(const cpl_table *trace_wave, int order_idx, int *nb_traces)
Get the trace numbers for a specified order_idx.
Definition: cr2res_trace.c:517
cpl_polynomial * cr2res_get_trace_wave_poly(const cpl_table *trace_wave, const char *poly_column, int order_idx, int trace_nb)
Get a polynomial from a TRACE_WAVE table.
Definition: cr2res_trace.c:685
cpl_vector * cr2res_trace_get_wl(const cpl_table *trace_wave, int order_idx, int trace_nb, int size)
Get the Wavelength vector from a TRACE_WAVE table.
Definition: cr2res_trace.c:730
cpl_mask * cr2res_trace_clean(cpl_mask *mask, int opening, int min_cluster)
Clean small blobs.
Definition: cr2res_trace.c:292
int cr2res_trace_add_extra_columns(cpl_table *traces, const char *infile, int det_nr)
Add extra columns to the plain trace table.
Definition: cr2res_trace.c:972
int * cr2res_trace_get_order_idx_values(const cpl_table *trace, int *nb_order_idx_values)
Count and return the different order_idx values from a TW table.
Definition: cr2res_trace.c:431
cpl_array * cr2res_trace_slit_fraction_create(cr2res_decker decker_position, int up_or_down)
Get a standard slit fraction.
cpl_table * cr2res_trace_merge(const cpl_table *trace_wave1, const cpl_table *trace_wave2)
Merge 2 trace_wave tables.
Definition: cr2res_trace.c:592
cpl_polynomial * cr2res_convert_array_to_poly(const cpl_array *arr)
Convert an array to polynomial.
int cr2res_order_idx_to_real(int order_idx, int order_zp)
Convert the order_idx into order_real.
Definition: cr2res_utils.c:89
cpl_array * cr2res_convert_poly_to_array(const cpl_polynomial *poly, int size)
Convert a polynomial to array.
cpl_array * cr2res_wave_get_estimate(const char *filename, int detector, int order)
Compute the wavelength estimate.
Definition: cr2res_wave.c:1527
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379
cpl_error_code hdrl_imagelist_collapse_mean(const hdrl_imagelist *himlist, hdrl_image **out, cpl_image **contrib)
Mean collapsing of image list.
void hdrl_imagelist_delete(hdrl_imagelist *himlist)
Free all memory used by a hdrl_imagelist object including the images.
double fraction(double x, double y, double r_out)
Fraction of pixel bounded.