36 #include "irplib_slitpos.h"
37 #include "irplib_flat.h"
49 #ifndef IRPLIB_SLITPOS_KERNEL_SIZE_Y
50 #define IRPLIB_SLITPOS_KERNEL_SIZE_Y 5
53 #ifndef IRPLIB_SLITPOS_MAX_EROSION
54 #define IRPLIB_SLITPOS_MAX_EROSION 1024
61 static cpl_error_code irplib_slitpos_find_edges_one_line(
const cpl_image *,
63 static cpl_error_code irplib_slitpos_find_vert_slit_ends(
const cpl_image *,
65 static cpl_error_code irplib_slitpos_find_vert_pos(
const cpl_image *,
int,
67 static cpl_error_code irplib_image_filter_background_line(cpl_image *,
109 const int size_x = cpl_image_get_size_x(imslit);
110 const int size_y = cpl_image_get_size_y(imslit);
113 cpl_image * filtered;
125 cpl_error_code error = CPL_ERROR_NONE;
128 if (slit_flux != NULL) *slit_flux = 0.0 ;
131 mask = cpl_mask_new(3, 3) ;
133 filtered = cpl_image_new(size_x, size_y, cpl_image_get_type(imslit));
134 error = cpl_image_filter_mask(filtered, imslit, mask,
135 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
136 cpl_mask_delete(mask);
139 cpl_image_delete(filtered);
140 cpl_ensure(0, cpl_error_get_code(), NULL);
145 error = irplib_image_filter_background_line(filtered, NULL, slit_max_width,
149 cpl_image_delete(filtered) ;
150 cpl_ensure(0, cpl_error_get_code(), NULL);
154 if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
155 cpl_image_delete(filtered);
156 cpl_msg_error(cpl_func,
"Could not find the slit position");
157 cpl_ensure(0, cpl_error_get_code(), NULL);
161 thin_im = cpl_image_extract(filtered, slit_pos-slit_max_width/2, 1,
162 slit_pos+slit_max_width/2, size_y);
163 if (thin_im == NULL) {
164 cpl_msg_error(cpl_func,
"Could not extract the %d pixel thin image "
165 "around position %"CPL_SIZE_FORMAT,
166 slit_max_width, slit_pos);
167 cpl_image_delete(filtered);
168 cpl_ensure(0, cpl_error_get_code(), NULL);
172 error = irplib_slitpos_find_vert_slit_ends(thin_im,
173 IRPLIB_SLITPOS_KERNEL_SIZE_Y,
176 cpl_image_delete(thin_im);
178 cpl_image_delete(filtered);
179 cpl_ensure(0, cpl_error_get_code(), NULL);
183 thin_im = cpl_image_extract(filtered,
184 slit_pos-slit_max_width/2,
186 slit_pos+slit_max_width/2,
188 cpl_image_delete(filtered);
190 cpl_ensure(thin_im != NULL, cpl_error_get_code(), NULL);
192 slit_length = 1 + slit_top_y - slit_bot_y;
195 slit_y = cpl_malloc(slit_length *
sizeof(
double));
196 slit_x_l = cpl_malloc(slit_length *
sizeof(
double));
197 slit_x_r = cpl_malloc(slit_length *
sizeof(
double));
200 for (i=0 ; i<slit_length ; i++) {
204 if (irplib_slitpos_find_edges_one_line(thin_im,
208 cpl_msg_error(cpl_func,
"cannot find the edges of the [%d]th line",
210 cpl_image_delete(thin_im);
215 if (slit_flux != NULL) {
216 *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
217 i+1, right_pos+1, i+1) ;
221 slit_x_l[i] = (double)left_pos;
222 slit_x_r[i] = (double)right_pos;
223 slit_y[i] = (double)(i+slit_bot_y-1);
225 cpl_image_delete(thin_im);
235 self = cpl_table_new(slit_length);
236 error |= cpl_table_new_column(
self,
"SLIT_Y", CPL_TYPE_INT);
237 error |= cpl_table_new_column(
self,
"SLIT_LEFT", CPL_TYPE_DOUBLE);
238 error |= cpl_table_new_column(
self,
"SLIT_CENTER", CPL_TYPE_DOUBLE);
239 error |= cpl_table_new_column(
self,
"SLIT_RIGHT", CPL_TYPE_DOUBLE);
241 error |= cpl_table_set_column_unit(
self,
"SLIT_Y",
"pixel");
242 error |= cpl_table_set_column_unit(
self,
"SLIT_LEFT",
"pixel");
243 error |= cpl_table_set_column_unit(
self,
"SLIT_CENTER",
"pixel");
244 error |= cpl_table_set_column_unit(
self,
"SLIT_RIGHT",
"pixel");
246 cpl_ensure(!error, cpl_error_get_code(), NULL);
249 for (i=0 ; i < slit_length ; i++) {
250 const int islity = i + slit_bot_y;
251 const double dslit = slit_pos - slit_max_width / 2.0;
252 const double dleft = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
253 const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
254 const double dcent = 0.5 * (dleft + dright);
256 if (cpl_table_set_int(
self,
"SLIT_Y", i, islity))
break;
257 if (cpl_table_set_double(
self,
"SLIT_LEFT", i, dleft))
break;
258 if (cpl_table_set_double(
self,
"SLIT_RIGHT", i, dright))
break;
259 if (cpl_table_set_double(
self,
"SLIT_CENTER", i, dcent))
break;
265 if (i != slit_length) {
266 cpl_table_delete(
self);
267 cpl_ensure(0, cpl_error_get_code(), NULL);
288 static cpl_error_code irplib_slitpos_find_edges_one_line(
const cpl_image *
self,
293 const int size_x = cpl_image_get_size_x(
self);
298 cpl_ensure_code(
self != NULL, CPL_ERROR_NULL_INPUT);
299 cpl_ensure_code(cpl_image_get_type(
self) == CPL_TYPE_FLOAT,
300 CPL_ERROR_INVALID_TYPE);
302 pself = cpl_image_get_data_float_const(
self);
305 threshold = cpl_image_get_mean_window(
self, 1, line_pos+1, size_x,
310 while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
315 while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
318 return CPL_ERROR_NONE;
334 cpl_error_code irplib_slitpos_find_vert_slit_ends(
const cpl_image *
self,
340 cpl_mask * copy = NULL;
342 cpl_image * label_image;
345 const int size_x = cpl_image_get_size_x(
self);
346 const int size_y = cpl_image_get_size_y(
self);
347 const int npix = size_x * size_y;
348 const cpl_binary * pbinary;
349 const cpl_binary * pfind;
353 cpl_ensure_code(size_x > 0, cpl_error_get_code());
354 cpl_ensure_code(kernel_size > 0, cpl_error_get_code());
357 binary = cpl_mask_threshold_image_create(
self, cpl_image_get_mean(
self),
358 cpl_image_get_max(
self));
359 cpl_ensure_code(binary != NULL, cpl_error_get_code());
362 label_image = cpl_image_labelise_mask_create(binary, &nobj);
363 cpl_image_delete(label_image);
365 if (label_image == NULL) {
366 cpl_mask_delete(binary);
367 cpl_ensure_code(0, cpl_error_get_code());
371 kernel = cpl_mask_new(kernel_size, 1);
372 cpl_mask_not(kernel);
373 copy = cpl_mask_wrap(size_x, size_y, cpl_malloc(size_x * size_y *
374 sizeof(cpl_binary)));
375 for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
378 cpl_mask_copy(copy, binary, 1, 1);
379 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_EROSION,
380 CPL_BORDER_ZERO))
break;
382 label_image = cpl_image_labelise_mask_create(binary, &nobj);
383 if (label_image == NULL)
break;
384 cpl_image_delete(label_image);
388 cpl_mask_delete(binary);
389 cpl_mask_delete(copy);
390 cpl_mask_delete(kernel);
391 if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
392 cpl_msg_error(cpl_func,
"Number of erosions reached a limit of %d "
393 "with %"CPL_SIZE_FORMAT
" possible slits left",
394 IRPLIB_SLITPOS_MAX_EROSION, nobj);
395 cpl_ensure_code(0, CPL_ERROR_CONTINUE);
397 cpl_ensure_code(0, cpl_error_get_code());
398 }
else if (nobj < 1) {
399 cpl_mask_delete(binary);
400 cpl_mask_delete(copy);
401 cpl_mask_delete(kernel);
402 if (erosions_nb == 0)
403 cpl_msg_error(cpl_func,
"No slit could be detected across %d "
406 cpl_msg_error(cpl_func,
"The last of %d erosions removed all the "
407 "possible slits", erosions_nb);
408 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
412 for (i=0 ; i < erosions_nb ; i++) {
413 cpl_mask_copy(copy, binary, 1, 1);
414 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_DILATION,
415 CPL_BORDER_ZERO))
break;
417 cpl_mask_delete(copy);
418 cpl_mask_delete(kernel);
420 if (i != erosions_nb) {
421 cpl_msg_error(cpl_func,
"Dilation number %d out of %d failed",
423 cpl_mask_delete(binary);
424 cpl_ensure_code(0, cpl_error_get_code());
428 pbinary = cpl_mask_get_data(binary);
429 assert( pbinary != NULL );
431 pfind = memchr(pbinary, CPL_BINARY_1, (
size_t)npix);
432 assert( pfind != NULL );
434 ibot = (int)(pfind - pbinary);
436 #if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
438 pfind = memrchr(pfind, CPL_BINARY_1, (
size_t)(npix - ibot));
439 assert( pfind != NULL );
441 itop = (int)(pfind - pbinary);
445 while (itop > ibot && pbinary[itop] == CPL_BINARY_0) itop--;
449 *bot_slit_y = 1 + ibot / size_x;
450 *top_slit_y = 1 + itop / size_x;
452 cpl_msg_info(cpl_func,
453 "Detected %"CPL_SIZE_FORMAT
"-pixel slit from pixel %d to %d "
454 "using %d erosions/dilations", cpl_mask_count(binary),
455 *bot_slit_y, *top_slit_y, erosions_nb);
457 cpl_mask_delete(binary);
460 cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
462 return CPL_ERROR_NONE;
476 static cpl_error_code irplib_slitpos_find_vert_pos(
const cpl_image *
self,
480 const int size_x = cpl_image_get_size_x(
self);
483 cpl_error_code error;
487 image1D = cpl_image_collapse_create(
self, 0);
489 cpl_ensure_code(image1D != NULL, cpl_error_get_code());
492 error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
495 cpl_image_delete(image1D);
497 cpl_ensure_code(!error, error);
499 return CPL_ERROR_NONE;
517 static cpl_error_code irplib_image_filter_background_line(cpl_image *
self,
518 const cpl_image * other,
520 cpl_boolean vertical)
522 const int nx = cpl_image_get_size_x(
self);
523 const int ny = cpl_image_get_size_y(
self);
524 const int msize = 1 + 2 * hsize;
526 cpl_image * background;
527 cpl_error_code error = CPL_ERROR_NONE;
529 cpl_ensure_code(
self != NULL, CPL_ERROR_NULL_INPUT);
530 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
532 if (other == NULL) other =
self;
534 mask = vertical ? cpl_mask_new(msize, 1) : cpl_mask_new(1, msize);
536 error |= cpl_mask_not(mask);
538 background = cpl_image_new(nx, ny, cpl_image_get_type(other));
540 error |= cpl_image_filter_mask(background, other, mask, CPL_FILTER_MEDIAN,
542 cpl_mask_delete(mask);
545 error |= cpl_image_copy(
self, other, 1, 1);
548 error |= cpl_image_subtract(
self, background);
549 cpl_image_delete(background);
551 return error ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
double * irplib_flat_fit_slope_robust(double *x, double *y, int np)
Fit a slope to a list of points (robust fit).
cpl_table * irplib_slitpos_analysis(const cpl_image *imslit, int slit_max_width, double *slit_flux)
Detect the slit position, detect its ends, extract a thin image containing only the slit and find its...