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