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
00052
00053
00054
00055
00056 #ifndef IRPLIB_SLITPOS_KERNEL_SIZE_Y
00057 #define IRPLIB_SLITPOS_KERNEL_SIZE_Y 5
00058 #endif
00059
00060 #ifndef IRPLIB_SLITPOS_MAX_EROSION
00061 #define IRPLIB_SLITPOS_MAX_EROSION 1024
00062 #endif
00063
00064
00065
00066
00067
00068 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image *,
00069 int, int *, int *);
00070 static cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image *,
00071 int, int *, int *);
00072 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image *, int,
00073 int *);
00074
00075
00079
00080
00082
00108
00109 cpl_table * irplib_slitpos_analysis(const cpl_image * imslit,
00110 int slit_max_width,
00111 double * slit_flux)
00112 {
00113 const int slit_size = cpl_image_get_size_y(imslit);
00114 int slit_length;
00115 int slit_pos;
00116 cpl_image * filtered;
00117 cpl_matrix * kernel;
00118 cpl_image * thin_im;
00119 int slit_top_y = 0;
00120 int slit_bot_y = 0;
00121 cpl_table * self;
00122 double * slit_y,
00123 * slit_x_l,
00124 * slit_x_r;
00125 double * coeff_r;
00126 double * coeff_l;
00127 int i;
00128 cpl_error_code error = CPL_ERROR_NONE;
00129
00130
00131 if (slit_flux != NULL) *slit_flux = 0.0 ;
00132
00133
00134 kernel = cpl_matrix_new(3, 3);
00135 cpl_ensure(!cpl_matrix_fill(kernel, 1.0), cpl_error_get_code(), NULL);
00136
00137 filtered = cpl_image_filter_median(imslit, kernel);
00138 cpl_matrix_delete(kernel);
00139
00140 if (filtered == NULL) {
00141 cpl_msg_error(cpl_func, "Could not filter the image");
00142 cpl_ensure(0, cpl_error_get_code(), NULL);
00143 }
00144
00145
00146 if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
00147 cpl_image_delete(filtered);
00148 cpl_msg_error(cpl_func, "Could not find the slit position");
00149 cpl_ensure(0, cpl_error_get_code(), NULL);
00150 }
00151
00152
00153 if ((thin_im = cpl_image_extract(filtered,
00154 slit_pos-slit_max_width/2,
00155 1,
00156 slit_pos+slit_max_width/2,
00157 slit_size)) == NULL) {
00158 cpl_msg_error(cpl_func, "Could not extract the %d pixel thin image "
00159 "around position %d", slit_max_width, slit_pos);
00160 cpl_image_delete(filtered);
00161 cpl_ensure(0, cpl_error_get_code(), NULL);
00162 }
00163
00164
00165 if ((irplib_slitpos_find_vert_slit_ends(thin_im,
00166 IRPLIB_SLITPOS_KERNEL_SIZE_Y,
00167 &slit_bot_y,
00168 &slit_top_y))) {
00169 cpl_msg_error(cpl_func, "Could not find the ends of the slit at %s",
00170 cpl_error_get_where());
00171 cpl_image_delete(filtered);
00172 cpl_image_delete(thin_im);
00173 cpl_ensure(0, cpl_error_get_code(), NULL);
00174 }
00175 cpl_image_delete(thin_im);
00176
00177
00178 thin_im = cpl_image_extract(filtered,
00179 slit_pos-slit_max_width/2,
00180 slit_bot_y,
00181 slit_pos+slit_max_width/2,
00182 slit_top_y);
00183 cpl_image_delete(filtered);
00184
00185 if (thin_im == NULL) {
00186 cpl_msg_error(cpl_func, "Could not extract the thin image from %d to %d",
00187 slit_bot_y, slit_top_y);
00188 cpl_ensure(0, cpl_error_get_code(), NULL);
00189 }
00190
00191 slit_length = 1 + slit_top_y - slit_bot_y;
00192
00193
00194 slit_y = cpl_malloc(slit_length * sizeof(double));
00195 slit_x_l = cpl_malloc(slit_length * sizeof(double));
00196 slit_x_r = cpl_malloc(slit_length * sizeof(double));
00197
00198
00199 for (i=0 ; i<slit_length ; i++) {
00200 int right_pos = 0;
00201 int left_pos = 0;
00202
00203 if (irplib_slitpos_find_edges_one_line(thin_im,
00204 i,
00205 &left_pos,
00206 &right_pos)) {
00207 cpl_msg_error(cpl_func, "cannot find the edges of the [%d]th line",
00208 i+1);
00209 cpl_image_delete(thin_im);
00210 return NULL;
00211 }
00212
00213
00214 if (slit_flux != NULL) {
00215 *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
00216 i+1, right_pos+1, i+1) ;
00217 }
00218
00219
00220 slit_x_l[i] = (double)left_pos;
00221 slit_x_r[i] = (double)right_pos;
00222 slit_y[i] = (double)(i+slit_bot_y-1);
00223 }
00224 cpl_image_delete(thin_im);
00225
00226
00227 coeff_l = irplib_flat_fit_slope_robust(slit_y, slit_x_l, slit_length);
00228 coeff_r = irplib_flat_fit_slope_robust(slit_y, slit_x_r, slit_length);
00229 cpl_free(slit_y);
00230 cpl_free(slit_x_l);
00231 cpl_free(slit_x_r);
00232
00233
00234 self = cpl_table_new(slit_length);
00235 error |= cpl_table_new_column(self, "SLIT_Y", CPL_TYPE_INT);
00236 error |= cpl_table_new_column(self, "SLIT_LEFT", CPL_TYPE_DOUBLE);
00237 error |= cpl_table_new_column(self, "SLIT_CENTER", CPL_TYPE_DOUBLE);
00238 error |= cpl_table_new_column(self, "SLIT_RIGHT", CPL_TYPE_DOUBLE);
00239
00240 error |= cpl_table_set_column_unit(self, "SLIT_Y", "pixel");
00241 error |= cpl_table_set_column_unit(self, "SLIT_LEFT", "pixel");
00242 error |= cpl_table_set_column_unit(self, "SLIT_CENTER", "pixel");
00243 error |= cpl_table_set_column_unit(self, "SLIT_RIGHT", "pixel");
00244
00245 cpl_ensure(!error, cpl_error_get_code(), NULL);
00246
00247
00248 for (i=0 ; i < slit_length ; i++) {
00249 const int islity = i + slit_bot_y;
00250 const double dslit = slit_pos - slit_max_width / 2.0;
00251 const double dleft = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
00252 const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
00253 const double dcent = 0.5 * (dleft + dright);
00254
00255 if (cpl_table_set_int(self, "SLIT_Y", i, islity)) break;
00256 if (cpl_table_set_double(self, "SLIT_LEFT", i, dleft)) break;
00257 if (cpl_table_set_double(self, "SLIT_RIGHT", i, dright)) break;
00258 if (cpl_table_set_double(self, "SLIT_CENTER", i, dcent)) break;
00259 }
00260
00261 cpl_free(coeff_r);
00262 cpl_free(coeff_l);
00263
00264 if (i != slit_length) {
00265 cpl_table_delete(self);
00266 cpl_ensure(0, cpl_error_get_code(), NULL);
00267 }
00268
00269 return self;
00270 }
00271
00274
00286
00287 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image * self,
00288 int line_pos,
00289 int * left_pos,
00290 int * right_pos)
00291 {
00292 const int size_x = cpl_image_get_size_x(self);
00293 const float * pself;
00294 double threshold;
00295 int i;
00296
00297 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00298 cpl_ensure_code(cpl_image_get_type(self) == CPL_TYPE_FLOAT,
00299 CPL_ERROR_INVALID_TYPE);
00300
00301 pself = cpl_image_get_data_float_const(self);
00302
00303
00304 threshold = cpl_image_get_mean_window(self, 1, line_pos+1, size_x,
00305 line_pos+1);
00306
00307
00308 i = 0;
00309 while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
00310 *left_pos = i;
00311
00312
00313 i = size_x - 1;
00314 while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
00315 *right_pos = i;
00316
00317 return CPL_ERROR_NONE;
00318 }
00319
00320
00331
00332 static cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image * self,
00333 int kernel_size,
00334 int * bot_slit_y,
00335 int * top_slit_y)
00336 {
00337 cpl_mask * binary;
00338 cpl_matrix * kernel;
00339 cpl_image * label_image;
00340 int nobj, erosions_nb;
00341 const int size_x = cpl_image_get_size_x(self);
00342 const int npix = size_x * cpl_image_get_size_y(self);
00343 const cpl_binary * pbinary;
00344 const cpl_binary * pfind;
00345 int i, itop, ibot;
00346
00347
00348 cpl_ensure_code(size_x > 0, cpl_error_get_code());
00349
00350
00351 binary = cpl_mask_threshold_image_create(self, cpl_image_get_mean(self),
00352 cpl_image_get_max(self));
00353 cpl_ensure_code(binary != NULL, cpl_error_get_code());
00354
00355
00356 kernel = cpl_matrix_new(kernel_size, 1);
00357
00358
00359 label_image = cpl_image_labelise_mask_create(binary, &nobj);
00360 cpl_image_delete(label_image);
00361
00362 if (label_image == NULL || kernel == NULL || cpl_matrix_fill(kernel, 1.0)) {
00363 cpl_mask_delete(binary);
00364 cpl_matrix_delete(kernel);
00365 cpl_ensure_code(0, cpl_error_get_code());
00366 }
00367
00368 for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
00369 erosions_nb++) {
00370
00371
00372 if (cpl_mask_erosion(binary, kernel)) break;
00373
00374 label_image = cpl_image_labelise_mask_create(binary, &nobj);
00375 if (label_image == NULL) break;
00376 cpl_image_delete(label_image);
00377 }
00378
00379 if (nobj > 1) {
00380 cpl_mask_delete(binary);
00381 cpl_matrix_delete(kernel);
00382 if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
00383 cpl_msg_error(cpl_func, "Number of erosions reached a limit of %d "
00384 "with %d possible slits left",
00385 IRPLIB_SLITPOS_MAX_EROSION, nobj);
00386 cpl_ensure_code(0, CPL_ERROR_CONTINUE);
00387 }
00388 cpl_ensure_code(0, cpl_error_get_code());
00389 } else if (nobj < 1) {
00390 cpl_mask_delete(binary);
00391 cpl_matrix_delete(kernel);
00392 if (erosions_nb == 0)
00393 cpl_msg_error(cpl_func, "No slit could be detected across %d "
00394 "pixels", size_x);
00395 else
00396 cpl_msg_error(cpl_func, "The last of %d erosions removed all the "
00397 "possible slits", erosions_nb);
00398 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
00399 }
00400
00401
00402 for (i=0 ; i < erosions_nb ; i++) {
00403 if (cpl_mask_dilation(binary, kernel)) break;
00404 }
00405 cpl_matrix_delete(kernel);
00406
00407 if (i != erosions_nb) {
00408 cpl_msg_error(cpl_func, "Dilation number %d out of %d failed",
00409 i, erosions_nb);
00410 cpl_mask_delete(binary);
00411 cpl_ensure_code(0, cpl_error_get_code());
00412 }
00413
00414
00415 pbinary = cpl_mask_get_data(binary);
00416 assert( pbinary != NULL );
00417
00418 pfind = memchr(pbinary, CPL_BINARY_1, (size_t)npix);
00419 assert( pfind != NULL );
00420
00421 ibot = (int)(pfind - pbinary);
00422
00423 #if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
00424
00425 pfind = memrchr(pfind, CPL_BINARY_1, (size_t)(npix - ibot));
00426 assert( pfind != NULL );
00427
00428 itop = (int)(pfind - pbinary);
00429 #else
00430
00431 itop = npix - 1;
00432 while (itop > ibot && pbinary[itop] != CPL_BINARY_1) itop--;
00433
00434 #endif
00435
00436 *bot_slit_y = 1 + ibot / size_x;
00437 *top_slit_y = 1 + itop / size_x;
00438
00439 cpl_msg_info(cpl_func, "Detected %d-pixel slit from pixel %d to %d "
00440 "using %d erosions/dilations", cpl_mask_count(binary),
00441 *bot_slit_y, *top_slit_y, erosions_nb);
00442
00443 cpl_mask_delete(binary);
00444
00445
00446 cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
00447
00448 return CPL_ERROR_NONE;
00449 }
00450
00451
00461
00462 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image * self,
00463 int xwidth,
00464 int * slit_pos)
00465 {
00466 const int size_x = cpl_image_get_size_x(self);
00467 cpl_image * image1D;
00468 int yone;
00469 cpl_error_code error;
00470
00471
00472
00473 image1D = cpl_image_collapse_create(self, 0);
00474
00475 cpl_ensure_code(image1D != NULL, cpl_error_get_code());
00476
00477
00478 error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
00479 1, slit_pos, &yone);
00480
00481 cpl_image_delete(image1D);
00482
00483 cpl_ensure_code(!error, error);
00484
00485 return CPL_ERROR_NONE;
00486 }