49 #include "irplib_slitpos.h"
50 #include "irplib_flat.h"
57 #ifndef CPL_SIZE_FORMAT
58 #define CPL_SIZE_FORMAT "d"
63 #ifndef IRPLIB_SLITPOS_KERNEL_SIZE_Y
64 #define IRPLIB_SLITPOS_KERNEL_SIZE_Y 5
67 #ifndef IRPLIB_SLITPOS_MAX_EROSION
68 #define IRPLIB_SLITPOS_MAX_EROSION 1024
75 static cpl_error_code irplib_slitpos_find_edges_one_line(
const cpl_image *,
77 static cpl_error_code irplib_slitpos_find_vert_slit_ends(
const cpl_image *,
79 static cpl_error_code irplib_slitpos_find_vert_pos(
const cpl_image *,
int,
81 static cpl_error_code irplib_image_filter_background_line(cpl_image *,
123 const int size_x = cpl_image_get_size_x(imslit);
124 const int size_y = cpl_image_get_size_y(imslit);
127 cpl_image * filtered;
139 cpl_error_code error = CPL_ERROR_NONE;
142 if (slit_flux != NULL) *slit_flux = 0.0 ;
145 mask = cpl_mask_new(3, 3) ;
147 filtered = cpl_image_new(size_x, size_y, cpl_image_get_type(imslit));
148 error = cpl_image_filter_mask(filtered, imslit, mask,
149 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
150 cpl_mask_delete(mask);
153 cpl_image_delete(filtered);
154 cpl_ensure(0, cpl_error_get_code(), NULL);
159 error = irplib_image_filter_background_line(filtered, NULL, slit_max_width,
163 cpl_image_delete(filtered) ;
164 cpl_ensure(0, cpl_error_get_code(), NULL);
168 if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
169 cpl_image_delete(filtered);
170 cpl_msg_error(cpl_func,
"Could not find the slit position");
171 cpl_ensure(0, cpl_error_get_code(), NULL);
175 thin_im = cpl_image_extract(filtered, slit_pos-slit_max_width/2, 1,
176 slit_pos+slit_max_width/2, size_y);
177 if (thin_im == NULL) {
178 cpl_msg_error(cpl_func,
"Could not extract the %d pixel thin image "
179 "around position %"CPL_SIZE_FORMAT,
180 slit_max_width, slit_pos);
181 cpl_image_delete(filtered);
182 cpl_ensure(0, cpl_error_get_code(), NULL);
186 error = irplib_slitpos_find_vert_slit_ends(thin_im,
187 IRPLIB_SLITPOS_KERNEL_SIZE_Y,
190 cpl_image_delete(thin_im);
192 cpl_image_delete(filtered);
193 cpl_ensure(0, cpl_error_get_code(), NULL);
197 thin_im = cpl_image_extract(filtered,
198 slit_pos-slit_max_width/2,
200 slit_pos+slit_max_width/2,
202 cpl_image_delete(filtered);
204 cpl_ensure(thin_im != NULL, cpl_error_get_code(), NULL);
206 slit_length = 1 + slit_top_y - slit_bot_y;
209 slit_y = cpl_malloc(slit_length *
sizeof(
double));
210 slit_x_l = cpl_malloc(slit_length *
sizeof(
double));
211 slit_x_r = cpl_malloc(slit_length *
sizeof(
double));
214 for (i=0 ; i<slit_length ; i++) {
218 if (irplib_slitpos_find_edges_one_line(thin_im,
222 cpl_msg_error(cpl_func,
"cannot find the edges of the [%d]th line",
224 cpl_image_delete(thin_im);
229 if (slit_flux != NULL) {
230 *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
231 i+1, right_pos+1, i+1) ;
235 slit_x_l[i] = (double)left_pos;
236 slit_x_r[i] = (double)right_pos;
237 slit_y[i] = (double)(i+slit_bot_y-1);
239 cpl_image_delete(thin_im);
249 self = cpl_table_new(slit_length);
250 error |= cpl_table_new_column(
self,
"SLIT_Y", CPL_TYPE_INT);
251 error |= cpl_table_new_column(
self,
"SLIT_LEFT", CPL_TYPE_DOUBLE);
252 error |= cpl_table_new_column(
self,
"SLIT_CENTER", CPL_TYPE_DOUBLE);
253 error |= cpl_table_new_column(
self,
"SLIT_RIGHT", CPL_TYPE_DOUBLE);
255 error |= cpl_table_set_column_unit(
self,
"SLIT_Y",
"pixel");
256 error |= cpl_table_set_column_unit(
self,
"SLIT_LEFT",
"pixel");
257 error |= cpl_table_set_column_unit(
self,
"SLIT_CENTER",
"pixel");
258 error |= cpl_table_set_column_unit(
self,
"SLIT_RIGHT",
"pixel");
260 cpl_ensure(!error, cpl_error_get_code(), NULL);
263 for (i=0 ; i < slit_length ; i++) {
264 const int islity = i + slit_bot_y;
265 const double dslit = slit_pos - slit_max_width / 2.0;
266 const double dleft = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
267 const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
268 const double dcent = 0.5 * (dleft + dright);
270 if (cpl_table_set_int(
self,
"SLIT_Y", i, islity))
break;
271 if (cpl_table_set_double(
self,
"SLIT_LEFT", i, dleft))
break;
272 if (cpl_table_set_double(
self,
"SLIT_RIGHT", i, dright))
break;
273 if (cpl_table_set_double(
self,
"SLIT_CENTER", i, dcent))
break;
279 if (i != slit_length) {
280 cpl_table_delete(
self);
281 cpl_ensure(0, cpl_error_get_code(), NULL);
302 static cpl_error_code irplib_slitpos_find_edges_one_line(
const cpl_image *
self,
307 const int size_x = cpl_image_get_size_x(
self);
312 cpl_ensure_code(
self != NULL, CPL_ERROR_NULL_INPUT);
313 cpl_ensure_code(cpl_image_get_type(
self) == CPL_TYPE_FLOAT,
314 CPL_ERROR_INVALID_TYPE);
316 pself = cpl_image_get_data_float_const(
self);
319 threshold = cpl_image_get_mean_window(
self, 1, line_pos+1, size_x,
324 while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
329 while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
332 return CPL_ERROR_NONE;
348 cpl_error_code irplib_slitpos_find_vert_slit_ends(
const cpl_image *
self,
354 cpl_mask * copy = NULL;
356 cpl_image * label_image;
359 const int size_x = cpl_image_get_size_x(
self);
360 const int size_y = cpl_image_get_size_y(
self);
361 const int npix = size_x * size_y;
362 const cpl_binary * pbinary;
363 const cpl_binary * pfind;
367 cpl_ensure_code(size_x > 0, cpl_error_get_code());
368 cpl_ensure_code(kernel_size > 0, cpl_error_get_code());
371 binary = cpl_mask_threshold_image_create(
self, cpl_image_get_mean(
self),
372 cpl_image_get_max(
self));
373 cpl_ensure_code(binary != NULL, cpl_error_get_code());
376 label_image = cpl_image_labelise_mask_create(binary, &nobj);
377 cpl_image_delete(label_image);
379 if (label_image == NULL) {
380 cpl_mask_delete(binary);
381 cpl_ensure_code(0, cpl_error_get_code());
385 kernel = cpl_mask_new(kernel_size, 1);
386 cpl_mask_not(kernel);
387 copy = cpl_mask_wrap(size_x, size_y, cpl_malloc(size_x * size_y *
388 sizeof(cpl_binary)));
389 for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
392 cpl_mask_copy(copy, binary, 1, 1);
393 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_EROSION,
394 CPL_BORDER_ZERO))
break;
396 label_image = cpl_image_labelise_mask_create(binary, &nobj);
397 if (label_image == NULL)
break;
398 cpl_image_delete(label_image);
402 cpl_mask_delete(binary);
403 cpl_mask_delete(copy);
404 cpl_mask_delete(kernel);
405 if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
406 cpl_msg_error(cpl_func,
"Number of erosions reached a limit of %d "
407 "with %"CPL_SIZE_FORMAT
" possible slits left",
408 IRPLIB_SLITPOS_MAX_EROSION, nobj);
409 cpl_ensure_code(0, CPL_ERROR_CONTINUE);
411 cpl_ensure_code(0, cpl_error_get_code());
412 }
else if (nobj < 1) {
413 cpl_mask_delete(binary);
414 cpl_mask_delete(copy);
415 cpl_mask_delete(kernel);
416 if (erosions_nb == 0)
417 cpl_msg_error(cpl_func,
"No slit could be detected across %d "
420 cpl_msg_error(cpl_func,
"The last of %d erosions removed all the "
421 "possible slits", erosions_nb);
422 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
426 for (i=0 ; i < erosions_nb ; i++) {
427 cpl_mask_copy(copy, binary, 1, 1);
428 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_DILATION,
429 CPL_BORDER_ZERO))
break;
431 cpl_mask_delete(copy);
432 cpl_mask_delete(kernel);
434 if (i != erosions_nb) {
435 cpl_msg_error(cpl_func,
"Dilation number %d out of %d failed",
437 cpl_mask_delete(binary);
438 cpl_ensure_code(0, cpl_error_get_code());
442 pbinary = cpl_mask_get_data(binary);
443 assert( pbinary != NULL );
445 pfind = memchr(pbinary, CPL_BINARY_1, (
size_t)npix);
446 assert( pfind != NULL );
448 ibot = (int)(pfind - pbinary);
450 #if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
452 pfind = memrchr(pfind, CPL_BINARY_1, (
size_t)(npix - ibot));
453 assert( pfind != NULL );
455 itop = (int)(pfind - pbinary);
459 while (itop > ibot && pbinary[itop] == CPL_BINARY_0) itop--;
463 *bot_slit_y = 1 + ibot / size_x;
464 *top_slit_y = 1 + itop / size_x;
466 cpl_msg_info(cpl_func,
467 "Detected %"CPL_SIZE_FORMAT
"-pixel slit from pixel %d to %d "
468 "using %d erosions/dilations", cpl_mask_count(binary),
469 *bot_slit_y, *top_slit_y, erosions_nb);
471 cpl_mask_delete(binary);
474 cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
476 return CPL_ERROR_NONE;
490 static cpl_error_code irplib_slitpos_find_vert_pos(
const cpl_image *
self,
494 const int size_x = cpl_image_get_size_x(
self);
497 cpl_error_code error;
501 image1D = cpl_image_collapse_create(
self, 0);
503 cpl_ensure_code(image1D != NULL, cpl_error_get_code());
506 error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
509 cpl_image_delete(image1D);
511 cpl_ensure_code(!error, error);
513 return CPL_ERROR_NONE;
531 static cpl_error_code irplib_image_filter_background_line(cpl_image *
self,
532 const cpl_image * other,
534 cpl_boolean vertical)
536 const int nx = cpl_image_get_size_x(
self);
537 const int ny = cpl_image_get_size_y(
self);
538 const int msize = 1 + 2 * hsize;
540 cpl_image * background;
541 cpl_error_code error = CPL_ERROR_NONE;
543 cpl_ensure_code(
self != NULL, CPL_ERROR_NULL_INPUT);
544 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
546 if (other == NULL) other =
self;
548 mask = vertical ? cpl_mask_new(msize, 1) : cpl_mask_new(1, msize);
550 error |= cpl_mask_not(mask);
552 background = cpl_image_new(nx, ny, cpl_image_get_type(other));
554 error |= cpl_image_filter_mask(background, other, mask, CPL_FILTER_MEDIAN,
556 cpl_mask_delete(mask);
559 error |= cpl_image_copy(
self, other, 1, 1);
562 error |= cpl_image_subtract(
self, background);
563 cpl_image_delete(background);
565 return error ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;