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
61static cpl_error_code irplib_slitpos_find_edges_one_line(
const cpl_image *,
63static cpl_error_code irplib_slitpos_find_vert_slit_ends(
const cpl_image *,
65static cpl_error_code irplib_slitpos_find_vert_pos(
const cpl_image *,
int,
67static 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 (void)cpl_error_set_where(cpl_func);
146 error = irplib_image_filter_background_line(filtered, NULL, slit_max_width,
150 cpl_image_delete(filtered) ;
151 (void)cpl_error_set_where(cpl_func);
156 if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
157 cpl_image_delete(filtered);
158 cpl_msg_error(cpl_func,
"Could not find the slit position");
159 (void)cpl_error_set_where(cpl_func);
164 thin_im = cpl_image_extract(filtered, slit_pos-slit_max_width/2, 1,
165 slit_pos+slit_max_width/2, size_y);
166 if (thin_im == NULL) {
167 cpl_msg_error(cpl_func,
"Could not extract the %d pixel thin image "
168 "around position %"CPL_SIZE_FORMAT,
169 slit_max_width, slit_pos);
170 cpl_image_delete(filtered);
171 (void)cpl_error_set_where(cpl_func);
176 error = irplib_slitpos_find_vert_slit_ends(thin_im,
177 IRPLIB_SLITPOS_KERNEL_SIZE_Y,
180 cpl_image_delete(thin_im);
182 cpl_image_delete(filtered);
183 (void)cpl_error_set_where(cpl_func);
188 thin_im = cpl_image_extract(filtered,
189 slit_pos-slit_max_width/2,
191 slit_pos+slit_max_width/2,
193 cpl_image_delete(filtered);
195 cpl_ensure(thin_im != NULL, cpl_error_get_code(), NULL);
197 slit_length = 1 + slit_top_y - slit_bot_y;
200 slit_y = cpl_malloc(slit_length *
sizeof(
double));
201 slit_x_l = cpl_malloc(slit_length *
sizeof(
double));
202 slit_x_r = cpl_malloc(slit_length *
sizeof(
double));
205 for (i=0 ; i<slit_length ; i++) {
209 if (irplib_slitpos_find_edges_one_line(thin_im,
213 cpl_msg_error(cpl_func,
"cannot find the edges of the [%d]th line",
215 cpl_image_delete(thin_im);
223 if (slit_flux != NULL) {
224 *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
225 i+1, right_pos+1, i+1) ;
229 slit_x_l[i] = (double)left_pos;
230 slit_x_r[i] = (double)right_pos;
231 slit_y[i] = (double)(i+slit_bot_y-1);
233 cpl_image_delete(thin_im);
243 self = cpl_table_new(slit_length);
244 error |= cpl_table_new_column(self,
"SLIT_Y", CPL_TYPE_INT);
245 error |= cpl_table_new_column(self,
"SLIT_LEFT", CPL_TYPE_DOUBLE);
246 error |= cpl_table_new_column(self,
"SLIT_CENTER", CPL_TYPE_DOUBLE);
247 error |= cpl_table_new_column(self,
"SLIT_RIGHT", CPL_TYPE_DOUBLE);
249 error |= cpl_table_set_column_unit(self,
"SLIT_Y",
"pixel");
250 error |= cpl_table_set_column_unit(self,
"SLIT_LEFT",
"pixel");
251 error |= cpl_table_set_column_unit(self,
"SLIT_CENTER",
"pixel");
252 error |= cpl_table_set_column_unit(self,
"SLIT_RIGHT",
"pixel");
254 cpl_ensure(!error, cpl_error_get_code(), NULL);
257 for (i=0 ; i < slit_length ; i++) {
258 const int islity = i + slit_bot_y;
259 const double dslit = slit_pos - slit_max_width / 2.0;
260 const double dleft = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
261 const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
262 const double dcent = 0.5 * (dleft + dright);
264 if (cpl_table_set_int(self,
"SLIT_Y", i, islity))
break;
265 if (cpl_table_set_double(self,
"SLIT_LEFT", i, dleft))
break;
266 if (cpl_table_set_double(self,
"SLIT_RIGHT", i, dright))
break;
267 if (cpl_table_set_double(self,
"SLIT_CENTER", i, dcent))
break;
273 if (i != slit_length) {
274 cpl_table_delete(self);
275 cpl_ensure(0, cpl_error_get_code(), NULL);
296static cpl_error_code irplib_slitpos_find_edges_one_line(
const cpl_image * self,
301 const int size_x = cpl_image_get_size_x(self);
306 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
307 cpl_ensure_code(cpl_image_get_type(self) == CPL_TYPE_FLOAT,
308 CPL_ERROR_INVALID_TYPE);
310 pself = cpl_image_get_data_float_const(self);
313 threshold = cpl_image_get_mean_window(self, 1, line_pos+1, size_x,
318 while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
323 while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
326 return CPL_ERROR_NONE;
342cpl_error_code irplib_slitpos_find_vert_slit_ends(
const cpl_image * self,
348 cpl_mask * copy = NULL;
350 cpl_image * label_image;
353 const int size_x = cpl_image_get_size_x(self);
354 const int size_y = cpl_image_get_size_y(self);
355 const int npix = size_x * size_y;
356 const cpl_binary * pbinary;
357 const cpl_binary * pfind;
361 cpl_ensure_code(size_x > 0, cpl_error_get_code());
362 cpl_ensure_code(kernel_size > 0, cpl_error_get_code());
365 binary = cpl_mask_threshold_image_create(self, cpl_image_get_mean(self),
366 cpl_image_get_max(self));
367 cpl_ensure_code(binary != NULL, cpl_error_get_code());
370 label_image = cpl_image_labelise_mask_create(binary, &nobj);
371 cpl_image_delete(label_image);
373 if (label_image == NULL) {
374 cpl_mask_delete(binary);
375 cpl_ensure_code(0, cpl_error_get_code());
379 kernel = cpl_mask_new(kernel_size, 1);
380 cpl_mask_not(kernel);
381 copy = cpl_mask_wrap(size_x, size_y, cpl_malloc(size_x * size_y *
382 sizeof(cpl_binary)));
383 for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
386 cpl_mask_copy(copy, binary, 1, 1);
387 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_EROSION,
388 CPL_BORDER_ZERO))
break;
390 label_image = cpl_image_labelise_mask_create(binary, &nobj);
391 if (label_image == NULL)
break;
392 cpl_image_delete(label_image);
396 cpl_mask_delete(binary);
397 cpl_mask_delete(copy);
398 cpl_mask_delete(kernel);
399 if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
400 cpl_msg_error(cpl_func,
"Number of erosions reached a limit of %d "
401 "with %"CPL_SIZE_FORMAT
" possible slits left",
402 IRPLIB_SLITPOS_MAX_EROSION, nobj);
403 cpl_ensure_code(0, CPL_ERROR_CONTINUE);
405 cpl_ensure_code(0, cpl_error_get_code());
406 }
else if (nobj < 1) {
407 cpl_mask_delete(binary);
408 cpl_mask_delete(copy);
409 cpl_mask_delete(kernel);
410 if (erosions_nb == 0)
411 cpl_msg_error(cpl_func,
"No slit could be detected across %d "
414 cpl_msg_error(cpl_func,
"The last of %d erosions removed all the "
415 "possible slits", erosions_nb);
416 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
420 for (i=0 ; i < erosions_nb ; i++) {
421 cpl_mask_copy(copy, binary, 1, 1);
422 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_DILATION,
423 CPL_BORDER_ZERO))
break;
425 cpl_mask_delete(copy);
426 cpl_mask_delete(kernel);
428 if (i != erosions_nb) {
429 cpl_msg_error(cpl_func,
"Dilation number %d out of %d failed",
431 cpl_mask_delete(binary);
432 cpl_ensure_code(0, cpl_error_get_code());
436 pbinary = cpl_mask_get_data(binary);
437 assert( pbinary != NULL );
439 pfind = memchr(pbinary, CPL_BINARY_1, (
size_t)npix);
440 assert( pfind != NULL );
442 ibot = (int)(pfind - pbinary);
444#if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
446 pfind = memrchr(pfind, CPL_BINARY_1, (
size_t)(npix - ibot));
447 assert( pfind != NULL );
449 itop = (int)(pfind - pbinary);
453 while (itop > ibot && pbinary[itop] == CPL_BINARY_0) itop--;
457 *bot_slit_y = 1 + ibot / size_x;
458 *top_slit_y = 1 + itop / size_x;
460 cpl_msg_info(cpl_func,
461 "Detected %"CPL_SIZE_FORMAT
"-pixel slit from pixel %d to %d "
462 "using %d erosions/dilations", cpl_mask_count(binary),
463 *bot_slit_y, *top_slit_y, erosions_nb);
465 cpl_mask_delete(binary);
468 cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
470 return CPL_ERROR_NONE;
484static cpl_error_code irplib_slitpos_find_vert_pos(
const cpl_image * self,
488 const int size_x = cpl_image_get_size_x(self);
491 cpl_error_code error;
495 image1D = cpl_image_collapse_create(self, 0);
497 cpl_ensure_code(image1D != NULL, cpl_error_get_code());
500 error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
503 cpl_image_delete(image1D);
505 cpl_ensure_code(!error, error);
507 return CPL_ERROR_NONE;
525static cpl_error_code irplib_image_filter_background_line(cpl_image * self,
526 const cpl_image * other,
528 cpl_boolean vertical)
530 const int nx = cpl_image_get_size_x(self);
531 const int ny = cpl_image_get_size_y(self);
532 const int msize = 1 + 2 * hsize;
534 cpl_image * background;
535 cpl_error_code error = CPL_ERROR_NONE;
537 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
538 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
540 if (other == NULL) other = self;
542 mask = vertical ? cpl_mask_new(msize, 1) : cpl_mask_new(1, msize);
544 error |= cpl_mask_not(mask);
546 background = cpl_image_new(nx, ny, cpl_image_get_type(other));
548 error |= cpl_image_filter_mask(background, other, mask, CPL_FILTER_MEDIAN,
550 cpl_mask_delete(mask);
553 error |= cpl_image_copy(self, other, 1, 1);
556 error |= cpl_image_subtract(self, background);
557 cpl_image_delete(background);
559 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...