00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "irplib_slitpos.h"
00037 #include "irplib_flat.h"
00038
00039 #include <cpl.h>
00040
00041 #include <string.h>
00042 #include <math.h>
00043 #include <assert.h>
00044
00045
00046
00047
00048
00049 #ifndef IRPLIB_SLITPOS_KERNEL_SIZE_Y
00050 #define IRPLIB_SLITPOS_KERNEL_SIZE_Y 5
00051 #endif
00052
00053 #ifndef IRPLIB_SLITPOS_MAX_EROSION
00054 #define IRPLIB_SLITPOS_MAX_EROSION 1024
00055 #endif
00056
00057
00058
00059
00060
00061 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image *,
00062 int, int *, int *);
00063 static cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image *,
00064 int, int *, int *);
00065 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image *, int,
00066 cpl_size *);
00067 static cpl_error_code irplib_image_filter_background_line(cpl_image *,
00068 const cpl_image *,
00069 int, cpl_boolean) ;
00070
00071
00075
00076
00078
00104
00105 cpl_table * irplib_slitpos_analysis(const cpl_image * imslit,
00106 int slit_max_width,
00107 double * slit_flux)
00108 {
00109 const int size_x = cpl_image_get_size_x(imslit);
00110 const int size_y = cpl_image_get_size_y(imslit);
00111 int slit_length;
00112 cpl_size slit_pos;
00113 cpl_image * filtered;
00114 cpl_mask * mask;
00115 cpl_image * thin_im;
00116 int slit_top_y = 0;
00117 int slit_bot_y = 0;
00118 cpl_table * self;
00119 double * slit_y,
00120 * slit_x_l,
00121 * slit_x_r;
00122 double * coeff_r;
00123 double * coeff_l;
00124 int i;
00125 cpl_error_code error = CPL_ERROR_NONE;
00126
00127
00128 if (slit_flux != NULL) *slit_flux = 0.0 ;
00129
00130
00131 mask = cpl_mask_new(3, 3) ;
00132 cpl_mask_not(mask) ;
00133 filtered = cpl_image_new(size_x, size_y, cpl_image_get_type(imslit));
00134 error = cpl_image_filter_mask(filtered, imslit, mask,
00135 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
00136 cpl_mask_delete(mask);
00137
00138 if (error) {
00139 cpl_image_delete(filtered);
00140 cpl_ensure(0, cpl_error_get_code(), NULL);
00141 }
00142
00143
00144
00145 error = irplib_image_filter_background_line(filtered, NULL, slit_max_width,
00146 CPL_TRUE);
00147
00148 if (error) {
00149 cpl_image_delete(filtered) ;
00150 cpl_ensure(0, cpl_error_get_code(), NULL);
00151 }
00152
00153
00154 if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
00155 cpl_image_delete(filtered);
00156 cpl_msg_error(cpl_func, "Could not find the slit position");
00157 cpl_ensure(0, cpl_error_get_code(), NULL);
00158 }
00159
00160
00161 thin_im = cpl_image_extract(filtered, slit_pos-slit_max_width/2, 1,
00162 slit_pos+slit_max_width/2, size_y);
00163 if (thin_im == NULL) {
00164 cpl_msg_error(cpl_func, "Could not extract the %d pixel thin image "
00165 "around position %"CPL_SIZE_FORMAT,
00166 slit_max_width, slit_pos);
00167 cpl_image_delete(filtered);
00168 cpl_ensure(0, cpl_error_get_code(), NULL);
00169 }
00170
00171
00172 error = irplib_slitpos_find_vert_slit_ends(thin_im,
00173 IRPLIB_SLITPOS_KERNEL_SIZE_Y,
00174 &slit_bot_y,
00175 &slit_top_y);
00176 cpl_image_delete(thin_im);
00177 if (error) {
00178 cpl_image_delete(filtered);
00179 cpl_ensure(0, cpl_error_get_code(), NULL);
00180 }
00181
00182
00183 thin_im = cpl_image_extract(filtered,
00184 slit_pos-slit_max_width/2,
00185 slit_bot_y,
00186 slit_pos+slit_max_width/2,
00187 slit_top_y);
00188 cpl_image_delete(filtered);
00189
00190 cpl_ensure(thin_im != NULL, cpl_error_get_code(), NULL);
00191
00192 slit_length = 1 + slit_top_y - slit_bot_y;
00193
00194
00195 slit_y = cpl_malloc(slit_length * sizeof(double));
00196 slit_x_l = cpl_malloc(slit_length * sizeof(double));
00197 slit_x_r = cpl_malloc(slit_length * sizeof(double));
00198
00199
00200 for (i=0 ; i<slit_length ; i++) {
00201 int right_pos = 0;
00202 int left_pos = 0;
00203
00204 if (irplib_slitpos_find_edges_one_line(thin_im,
00205 i,
00206 &left_pos,
00207 &right_pos)) {
00208 cpl_msg_error(cpl_func, "cannot find the edges of the [%d]th line",
00209 i+1);
00210 cpl_image_delete(thin_im);
00211 cpl_free(slit_y);
00212 cpl_free(slit_x_l);
00213 cpl_free(slit_x_r);
00214 return NULL;
00215 }
00216
00217
00218 if (slit_flux != NULL) {
00219 *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
00220 i+1, right_pos+1, i+1) ;
00221 }
00222
00223
00224 slit_x_l[i] = (double)left_pos;
00225 slit_x_r[i] = (double)right_pos;
00226 slit_y[i] = (double)(i+slit_bot_y-1);
00227 }
00228 cpl_image_delete(thin_im);
00229
00230
00231 coeff_l = irplib_flat_fit_slope_robust(slit_y, slit_x_l, slit_length);
00232 coeff_r = irplib_flat_fit_slope_robust(slit_y, slit_x_r, slit_length);
00233 cpl_free(slit_y);
00234 cpl_free(slit_x_l);
00235 cpl_free(slit_x_r);
00236
00237
00238 self = cpl_table_new(slit_length);
00239 error |= cpl_table_new_column(self, "SLIT_Y", CPL_TYPE_INT);
00240 error |= cpl_table_new_column(self, "SLIT_LEFT", CPL_TYPE_DOUBLE);
00241 error |= cpl_table_new_column(self, "SLIT_CENTER", CPL_TYPE_DOUBLE);
00242 error |= cpl_table_new_column(self, "SLIT_RIGHT", CPL_TYPE_DOUBLE);
00243
00244 error |= cpl_table_set_column_unit(self, "SLIT_Y", "pixel");
00245 error |= cpl_table_set_column_unit(self, "SLIT_LEFT", "pixel");
00246 error |= cpl_table_set_column_unit(self, "SLIT_CENTER", "pixel");
00247 error |= cpl_table_set_column_unit(self, "SLIT_RIGHT", "pixel");
00248
00249 cpl_ensure(!error, cpl_error_get_code(), NULL);
00250
00251
00252 for (i=0 ; i < slit_length ; i++) {
00253 const int islity = i + slit_bot_y;
00254 const double dslit = slit_pos - slit_max_width / 2.0;
00255 const double dleft = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
00256 const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
00257 const double dcent = 0.5 * (dleft + dright);
00258
00259 if (cpl_table_set_int(self, "SLIT_Y", i, islity)) break;
00260 if (cpl_table_set_double(self, "SLIT_LEFT", i, dleft)) break;
00261 if (cpl_table_set_double(self, "SLIT_RIGHT", i, dright)) break;
00262 if (cpl_table_set_double(self, "SLIT_CENTER", i, dcent)) break;
00263 }
00264
00265 cpl_free(coeff_r);
00266 cpl_free(coeff_l);
00267
00268 if (i != slit_length) {
00269 cpl_table_delete(self);
00270 cpl_ensure(0, cpl_error_get_code(), NULL);
00271 }
00272
00273 return self;
00274 }
00275
00278
00290
00291 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image * self,
00292 int line_pos,
00293 int * left_pos,
00294 int * right_pos)
00295 {
00296 const int size_x = cpl_image_get_size_x(self);
00297 const float * pself;
00298 double threshold;
00299 int i;
00300
00301 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00302 cpl_ensure_code(cpl_image_get_type(self) == CPL_TYPE_FLOAT,
00303 CPL_ERROR_INVALID_TYPE);
00304
00305 pself = cpl_image_get_data_float_const(self);
00306
00307
00308 threshold = cpl_image_get_mean_window(self, 1, line_pos+1, size_x,
00309 line_pos+1);
00310
00311
00312 i = 0;
00313 while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
00314 *left_pos = i;
00315
00316
00317 i = size_x - 1;
00318 while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
00319 *right_pos = i;
00320
00321 return CPL_ERROR_NONE;
00322 }
00323
00324
00335
00336 static
00337 cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image * self,
00338 int kernel_size,
00339 int * bot_slit_y,
00340 int * top_slit_y)
00341 {
00342 cpl_mask * binary;
00343 cpl_mask * copy = NULL;
00344 cpl_mask * kernel;
00345 cpl_image * label_image;
00346 int erosions_nb;
00347 cpl_size nobj ;
00348 const int size_x = cpl_image_get_size_x(self);
00349 const int size_y = cpl_image_get_size_y(self);
00350 const int npix = size_x * size_y;
00351 const cpl_binary * pbinary;
00352 const cpl_binary * pfind;
00353 int i, itop, ibot;
00354
00355
00356 cpl_ensure_code(size_x > 0, cpl_error_get_code());
00357 cpl_ensure_code(kernel_size > 0, cpl_error_get_code());
00358
00359
00360 binary = cpl_mask_threshold_image_create(self, cpl_image_get_mean(self),
00361 cpl_image_get_max(self));
00362 cpl_ensure_code(binary != NULL, cpl_error_get_code());
00363
00364
00365 label_image = cpl_image_labelise_mask_create(binary, &nobj);
00366 cpl_image_delete(label_image);
00367
00368 if (label_image == NULL) {
00369 cpl_mask_delete(binary);
00370 cpl_ensure_code(0, cpl_error_get_code());
00371 }
00372
00373
00374 kernel = cpl_mask_new(kernel_size, 1);
00375 cpl_mask_not(kernel);
00376 copy = cpl_mask_wrap(size_x, size_y, cpl_malloc(size_x * size_y *
00377 sizeof(cpl_binary)));
00378 for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
00379 erosions_nb++) {
00380
00381 cpl_mask_copy(copy, binary, 1, 1);
00382 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_EROSION,
00383 CPL_BORDER_ZERO)) break;
00384
00385 label_image = cpl_image_labelise_mask_create(binary, &nobj);
00386 if (label_image == NULL) break;
00387 cpl_image_delete(label_image);
00388 }
00389
00390 if (nobj > 1) {
00391 cpl_mask_delete(binary);
00392 cpl_mask_delete(copy);
00393 cpl_mask_delete(kernel);
00394 if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
00395 cpl_msg_error(cpl_func, "Number of erosions reached a limit of %d "
00396 "with %"CPL_SIZE_FORMAT" possible slits left",
00397 IRPLIB_SLITPOS_MAX_EROSION, nobj);
00398 cpl_ensure_code(0, CPL_ERROR_CONTINUE);
00399 }
00400 cpl_ensure_code(0, cpl_error_get_code());
00401 } else if (nobj < 1) {
00402 cpl_mask_delete(binary);
00403 cpl_mask_delete(copy);
00404 cpl_mask_delete(kernel);
00405 if (erosions_nb == 0)
00406 cpl_msg_error(cpl_func, "No slit could be detected across %d "
00407 "pixels", size_x);
00408 else
00409 cpl_msg_error(cpl_func, "The last of %d erosions removed all the "
00410 "possible slits", erosions_nb);
00411 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
00412 }
00413
00414
00415 for (i=0 ; i < erosions_nb ; i++) {
00416 cpl_mask_copy(copy, binary, 1, 1);
00417 if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_DILATION,
00418 CPL_BORDER_ZERO)) break;
00419 }
00420 cpl_mask_delete(copy);
00421 cpl_mask_delete(kernel);
00422
00423 if (i != erosions_nb) {
00424 cpl_msg_error(cpl_func, "Dilation number %d out of %d failed",
00425 i, erosions_nb);
00426 cpl_mask_delete(binary);
00427 cpl_ensure_code(0, cpl_error_get_code());
00428 }
00429
00430
00431 pbinary = cpl_mask_get_data(binary);
00432 assert( pbinary != NULL );
00433
00434 pfind = memchr(pbinary, CPL_BINARY_1, (size_t)npix);
00435 assert( pfind != NULL );
00436
00437 ibot = (int)(pfind - pbinary);
00438
00439 #if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
00440
00441 pfind = memrchr(pfind, CPL_BINARY_1, (size_t)(npix - ibot));
00442 assert( pfind != NULL );
00443
00444 itop = (int)(pfind - pbinary);
00445 #else
00446
00447 itop = npix - 1;
00448 while (itop > ibot && pbinary[itop] == CPL_BINARY_0) itop--;
00449
00450 #endif
00451
00452 *bot_slit_y = 1 + ibot / size_x;
00453 *top_slit_y = 1 + itop / size_x;
00454
00455 cpl_msg_info(cpl_func,
00456 "Detected %"CPL_SIZE_FORMAT"-pixel slit from pixel %d to %d "
00457 "using %d erosions/dilations", cpl_mask_count(binary),
00458 *bot_slit_y, *top_slit_y, erosions_nb);
00459
00460 cpl_mask_delete(binary);
00461
00462
00463 cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
00464
00465 return CPL_ERROR_NONE;
00466 }
00467
00468
00478
00479 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image * self,
00480 int xwidth,
00481 cpl_size * slit_pos)
00482 {
00483 const int size_x = cpl_image_get_size_x(self);
00484 cpl_image * image1D;
00485 cpl_size yone;
00486 cpl_error_code error;
00487
00488
00489
00490 image1D = cpl_image_collapse_create(self, 0);
00491
00492 cpl_ensure_code(image1D != NULL, cpl_error_get_code());
00493
00494
00495 error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
00496 1, slit_pos, &yone);
00497
00498 cpl_image_delete(image1D);
00499
00500 cpl_ensure_code(!error, error);
00501
00502 return CPL_ERROR_NONE;
00503 }
00504
00505
00519
00520 static cpl_error_code irplib_image_filter_background_line(cpl_image * self,
00521 const cpl_image * other,
00522 int hsize,
00523 cpl_boolean vertical)
00524 {
00525 const int nx = cpl_image_get_size_x(self);
00526 const int ny = cpl_image_get_size_y(self);
00527 const int msize = 1 + 2 * hsize;
00528 cpl_mask * mask;
00529 cpl_image * background;
00530 cpl_error_code error = CPL_ERROR_NONE;
00531
00532 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00533 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
00534
00535 if (other == NULL) other = self;
00536
00537 mask = vertical ? cpl_mask_new(msize, 1) : cpl_mask_new(1, msize);
00538
00539 error |= cpl_mask_not(mask);
00540
00541 background = cpl_image_new(nx, ny, cpl_image_get_type(other));
00542
00543 error |= cpl_image_filter_mask(background, other, mask, CPL_FILTER_MEDIAN,
00544 CPL_BORDER_FILTER);
00545 cpl_mask_delete(mask);
00546
00547 if (self != other) {
00548 error |= cpl_image_copy(self, other, 1, 1);
00549 }
00550
00551 error |= cpl_image_subtract(self, background);
00552 cpl_image_delete(background);
00553
00554 return error ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
00555 }
00556
00557