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
62irplib_slitpos_find_edges_one_line(
const cpl_image *,
int,
int *,
int *);
64irplib_slitpos_find_vert_slit_ends(
const cpl_image *,
int,
int *,
int *);
66irplib_slitpos_find_vert_pos(
const cpl_image *,
int, cpl_size *);
67static cpl_error_code irplib_image_filter_background_line(cpl_image *,
111 const int size_x = cpl_image_get_size_x(imslit);
112 const int size_y = cpl_image_get_size_y(imslit);
121 double *slit_y, *slit_x_l, *slit_x_r;
125 cpl_error_code error = CPL_ERROR_NONE;
128 if (slit_flux != NULL)
132 mask = cpl_mask_new(3, 3);
134 filtered = cpl_image_new(size_x, size_y, cpl_image_get_type(imslit));
135 error = cpl_image_filter_mask(filtered, imslit, mask, CPL_FILTER_MEDIAN,
137 cpl_mask_delete(mask);
140 cpl_image_delete(filtered);
141 (void)cpl_error_set_where(cpl_func);
147 error = irplib_image_filter_background_line(filtered, NULL, slit_max_width,
151 cpl_image_delete(filtered);
152 (void)cpl_error_set_where(cpl_func);
157 if (irplib_slitpos_find_vert_pos(filtered, slit_max_width / 2, &slit_pos)) {
158 cpl_image_delete(filtered);
159 cpl_msg_error(cpl_func,
"Could not find the slit position");
160 (void)cpl_error_set_where(cpl_func);
165 thin_im = cpl_image_extract(filtered, slit_pos - slit_max_width / 2, 1,
166 slit_pos + slit_max_width / 2, size_y);
167 if (thin_im == NULL) {
168 cpl_msg_error(cpl_func,
169 "Could not extract the %d pixel thin image "
170 "around position %" CPL_SIZE_FORMAT,
171 slit_max_width, slit_pos);
172 cpl_image_delete(filtered);
173 (void)cpl_error_set_where(cpl_func);
178 error = irplib_slitpos_find_vert_slit_ends(thin_im,
179 IRPLIB_SLITPOS_KERNEL_SIZE_Y,
180 &slit_bot_y, &slit_top_y);
181 cpl_image_delete(thin_im);
183 cpl_image_delete(filtered);
184 (void)cpl_error_set_where(cpl_func);
190 cpl_image_extract(filtered, slit_pos - slit_max_width / 2, slit_bot_y,
191 slit_pos + slit_max_width / 2, slit_top_y);
192 cpl_image_delete(filtered);
194 cpl_ensure(thin_im != NULL, cpl_error_get_code(), NULL);
196 slit_length = 1 + slit_top_y - slit_bot_y;
199 slit_y = cpl_malloc(slit_length *
sizeof(
double));
200 slit_x_l = cpl_malloc(slit_length *
sizeof(
double));
201 slit_x_r = cpl_malloc(slit_length *
sizeof(
double));
204 for (i = 0; i < slit_length; i++) {
208 if (irplib_slitpos_find_edges_one_line(thin_im, i, &left_pos,
210 cpl_msg_error(cpl_func,
"cannot find the edges of the [%d]th line",
212 cpl_image_delete(thin_im);
220 if (slit_flux != NULL) {
222 cpl_image_get_flux_window(thin_im, left_pos + 1, i + 1,
223 right_pos + 1, i + 1);
227 slit_x_l[i] = (double)left_pos;
228 slit_x_r[i] = (double)right_pos;
229 slit_y[i] = (double)(i + slit_bot_y - 1);
231 cpl_image_delete(thin_im);
241 self = cpl_table_new(slit_length);
242 error |= cpl_table_new_column(self,
"SLIT_Y", CPL_TYPE_INT);
243 error |= cpl_table_new_column(self,
"SLIT_LEFT", CPL_TYPE_DOUBLE);
244 error |= cpl_table_new_column(self,
"SLIT_CENTER", CPL_TYPE_DOUBLE);
245 error |= cpl_table_new_column(self,
"SLIT_RIGHT", CPL_TYPE_DOUBLE);
247 error |= cpl_table_set_column_unit(self,
"SLIT_Y",
"pixel");
248 error |= cpl_table_set_column_unit(self,
"SLIT_LEFT",
"pixel");
249 error |= cpl_table_set_column_unit(self,
"SLIT_CENTER",
"pixel");
250 error |= cpl_table_set_column_unit(self,
"SLIT_RIGHT",
"pixel");
252 cpl_ensure(!error, cpl_error_get_code(), NULL);
255 for (i = 0; i < slit_length; i++) {
256 const int islity = i + slit_bot_y;
257 const double dslit = slit_pos - slit_max_width / 2.0;
258 const double dleft = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
259 const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
260 const double dcent = 0.5 * (dleft + dright);
262 if (cpl_table_set_int(self,
"SLIT_Y", i, islity))
264 if (cpl_table_set_double(self,
"SLIT_LEFT", i, dleft))
266 if (cpl_table_set_double(self,
"SLIT_RIGHT", i, dright))
268 if (cpl_table_set_double(self,
"SLIT_CENTER", i, dcent))
275 if (i != slit_length) {
276 cpl_table_delete(self);
277 cpl_ensure(0, cpl_error_get_code(), NULL);
299irplib_slitpos_find_edges_one_line(
const cpl_image *self,
304 const int size_x = cpl_image_get_size_x(self);
309 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
310 cpl_ensure_code(cpl_image_get_type(self) == CPL_TYPE_FLOAT,
311 CPL_ERROR_INVALID_TYPE);
313 pself = cpl_image_get_data_float_const(self);
317 cpl_image_get_mean_window(self, 1, line_pos + 1, size_x, line_pos + 1);
321 while (i < size_x && pself[line_pos * size_x + i] < threshold)
327 while (i >= 0 && pself[line_pos * size_x + i] < threshold)
331 return CPL_ERROR_NONE;
347irplib_slitpos_find_vert_slit_ends(
const cpl_image *self,
353 cpl_mask *copy = NULL;
355 cpl_image *label_image;
358 const int size_x = cpl_image_get_size_x(self);
359 const int size_y = cpl_image_get_size_y(self);
360 const int npix = size_x * size_y;
361 const cpl_binary *pbinary;
362 const cpl_binary *pfind;
366 cpl_ensure_code(size_x > 0, cpl_error_get_code());
367 cpl_ensure_code(kernel_size > 0, cpl_error_get_code());
370 binary = cpl_mask_threshold_image_create(self, cpl_image_get_mean(self),
371 cpl_image_get_max(self));
372 cpl_ensure_code(binary != NULL, cpl_error_get_code());
375 label_image = cpl_image_labelise_mask_create(binary, &nobj);
376 cpl_image_delete(label_image);
378 if (label_image == NULL) {
379 cpl_mask_delete(binary);
380 cpl_ensure_code(0, cpl_error_get_code());
384 kernel = cpl_mask_new(kernel_size, 1);
385 cpl_mask_not(kernel);
386 copy = cpl_mask_wrap(size_x, size_y,
387 cpl_malloc(size_x * size_y *
sizeof(cpl_binary)));
388 for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
391 cpl_mask_copy(copy, binary, 1, 1);
392 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_EROSION,
396 label_image = cpl_image_labelise_mask_create(binary, &nobj);
397 if (label_image == NULL)
399 cpl_image_delete(label_image);
403 cpl_mask_delete(binary);
404 cpl_mask_delete(copy);
405 cpl_mask_delete(kernel);
406 if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
407 cpl_msg_error(cpl_func,
408 "Number of erosions reached a limit of %d "
409 "with %" CPL_SIZE_FORMAT
" possible slits left",
410 IRPLIB_SLITPOS_MAX_EROSION, nobj);
411 cpl_ensure_code(0, CPL_ERROR_CONTINUE);
413 cpl_ensure_code(0, cpl_error_get_code());
416 cpl_mask_delete(binary);
417 cpl_mask_delete(copy);
418 cpl_mask_delete(kernel);
419 if (erosions_nb == 0)
420 cpl_msg_error(cpl_func,
421 "No slit could be detected across %d "
425 cpl_msg_error(cpl_func,
426 "The last of %d erosions removed all the "
429 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
433 for (i = 0; i < erosions_nb; i++) {
434 cpl_mask_copy(copy, binary, 1, 1);
435 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_DILATION,
439 cpl_mask_delete(copy);
440 cpl_mask_delete(kernel);
442 if (i != erosions_nb) {
443 cpl_msg_error(cpl_func,
"Dilation number %d out of %d failed", i,
445 cpl_mask_delete(binary);
446 cpl_ensure_code(0, cpl_error_get_code());
450 pbinary = cpl_mask_get_data(binary);
451 assert(pbinary != NULL);
453 pfind = memchr(pbinary, CPL_BINARY_1, (
size_t)npix);
454 assert(pfind != NULL);
456 ibot = (int)(pfind - pbinary);
458#if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
460 pfind = memrchr(pfind, CPL_BINARY_1, (
size_t)(npix - ibot));
461 assert(pfind != NULL);
463 itop = (int)(pfind - pbinary);
467 while (itop > ibot && pbinary[itop] == CPL_BINARY_0)
472 *bot_slit_y = 1 + ibot / size_x;
473 *top_slit_y = 1 + itop / size_x;
475 cpl_msg_info(cpl_func,
476 "Detected %" CPL_SIZE_FORMAT
"-pixel slit from pixel %d to %d "
477 "using %d erosions/dilations",
478 cpl_mask_count(binary), *bot_slit_y, *top_slit_y, erosions_nb);
480 cpl_mask_delete(binary);
483 cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
485 return CPL_ERROR_NONE;
500irplib_slitpos_find_vert_pos(
const cpl_image *self,
504 const int size_x = cpl_image_get_size_x(self);
507 cpl_error_code error;
511 image1D = cpl_image_collapse_create(self, 0);
513 cpl_ensure_code(image1D != NULL, cpl_error_get_code());
516 error = cpl_image_get_maxpos_window(image1D, 1 + xwidth, 1, size_x - xwidth,
519 cpl_image_delete(image1D);
521 cpl_ensure_code(!error, error);
523 return CPL_ERROR_NONE;
542irplib_image_filter_background_line(cpl_image *self,
543 const cpl_image *other,
545 cpl_boolean vertical)
547 const int nx = cpl_image_get_size_x(self);
548 const int ny = cpl_image_get_size_y(self);
549 const int msize = 1 + 2 * hsize;
551 cpl_image *background;
552 cpl_error_code error = CPL_ERROR_NONE;
554 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
555 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
560 mask = vertical ? cpl_mask_new(msize, 1) : cpl_mask_new(1, msize);
562 error |= cpl_mask_not(mask);
564 background = cpl_image_new(nx, ny, cpl_image_get_type(other));
566 error |= cpl_image_filter_mask(background, other, mask, CPL_FILTER_MEDIAN,
568 cpl_mask_delete(mask);
571 error |= cpl_image_copy(self, other, 1, 1);
574 error |= cpl_image_subtract(self, background);
575 cpl_image_delete(background);
577 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...