111 #include <uves_orderpos_hough.h>
113 #include <uves_utils.h>
114 #include <uves_utils_wrappers.h>
115 #include <uves_error.h>
116 #include <uves_msg.h>
126 #define SLOPE(hx) ( MINSLOPE + ( ((double)(hx)) / SLOPERES ) ) * (MAXSLOPE - MINSLOPE)
127 #define SLOPEINV(a) \
128 uves_round_double( SLOPERES * ( ((double)(a)) - MINSLOPE ) / (MAXSLOPE - MINSLOPE))
131 #define INTERSEPT(hy) (minintersept + hy)
132 #define INTERSEPTINV(b) (b - minintersept)
139 static cpl_table *
detect_lines(cpl_image *htrans,
int minintersept,
140 const cpl_image *inputimage,
141 int NORDERS,
bool norders_is_guess,
int SAMPLEWIDTH,
142 double PTHRES,
double MINSLOPE,
double MAXSLOPE,
int SLOPERES,
144 static cpl_error_code
delete_peak(cpl_image *htrans,
int minintersept,
int hxmax,
int hymax,
145 int SPACING,
int imagewidth,
int SAMPLEWIDTH,
146 double MINSLOPE,
double MAXSLOPE,
int SLOPERES);
147 static int firsttrace(
int nx,
int SAMPLEWIDTH);
149 static double autocorr(
const cpl_image *image,
int x,
int shift);
150 static cpl_error_code
update_max(
const cpl_image *htrans,
194 cpl_table *
uves_hough(
const cpl_image *image,
int ymin,
int ymax,
int NORDERS,
195 bool norders_is_guess,
196 int SAMPLEWIDTH,
double PTHRES,
double MINSLOPE,
double MAXSLOPE,
197 int SLOPERES,
bool consecutive,
198 cpl_image **htrans, cpl_image **htrans_original)
201 cpl_table *ordertable = NULL;
205 int minintersept = 0;
207 int maxintersept = 0;
209 const double *image_data = NULL;
210 double *htrans_data = NULL;
213 *htrans_original = NULL;
217 assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE, CPL_ERROR_INVALID_TYPE,
218 "Input image has wrong type. Must be of type double");
219 assure( 0 <= MINSLOPE, CPL_ERROR_ILLEGAL_INPUT,
220 "minslope = %f must be non-negative", MINSLOPE);
221 assure( 0 <= MAXSLOPE, CPL_ERROR_ILLEGAL_INPUT,
222 "maxslope = %f must be non-negative", MAXSLOPE);
223 assure( MINSLOPE < MAXSLOPE, CPL_ERROR_INCOMPATIBLE_INPUT,
"minslope = %f; maxslope = %f",
225 assure( 0 < SLOPERES, CPL_ERROR_ILLEGAL_INPUT,
226 "Hough image width = %d, must be positive", SLOPERES);
230 assure (cpl_image_count_rejected(image) == 0,
231 CPL_ERROR_UNSUPPORTED_MODE,
"Input image has %" CPL_SIZE_FORMAT
" bad pixels",
232 cpl_image_count_rejected(image));
238 "Results might be unreliable", MAXSLOPE);
241 nx = cpl_image_get_size_x(image);
242 ny = cpl_image_get_size_y(image);
244 assure( 1 <= ymin && ymin <= ymax && ymax <= ny, CPL_ERROR_ILLEGAL_INPUT,
245 "Illegal y-range: %d - %d (image height is %d)", ymin, ymax, ny);
251 minintersept = uves_round_double(0 - nx*MAXSLOPE);
254 check( *htrans = cpl_image_new(SLOPERES,
255 maxintersept - minintersept,
257 "Could not create image");
259 check_nomsg( image_data = cpl_image_get_data_double_const(image) );
260 check_nomsg( htrans_data = cpl_image_get_data_double(*htrans) );
262 uves_msg(
"Calculating Hough transform");
272 for (y = ymin; y <= ymax; y += 1)
280 for (x = firstcol; x <= nx; x += SAMPLEWIDTH)
286 for (hx = 1; hx <= SLOPERES; hx++)
288 check_nomsg(hy = INTERSEPTINV(uves_round_double(y - x*SLOPE(hx))));
294 check_nomsg(pixelvalue = image_data[(x-1) + (y-1)*nx]);
307 check_nomsg(htrans_data[(hx-1) + (hy-1)*SLOPERES] += pixelvalue);
315 check( *htrans_original = cpl_image_duplicate(*htrans),
"Error copying hough image");
329 "Could not detect lines in hough image");
331 passure( cpl_table_get_ncol(ordertable) == 4,
"%" CPL_SIZE_FORMAT
"", cpl_table_get_ncol(ordertable));
332 passure( cpl_table_has_column(ordertable,
"Slope"),
" ");
333 passure( cpl_table_has_column(ordertable,
"Intersept"),
" ");
334 passure( cpl_table_has_column(ordertable,
"Spacing"),
" ");
335 passure( cpl_table_has_column(ordertable,
"Order"),
" ");
338 if (cpl_error_get_code() != CPL_ERROR_NONE)
340 uves_free_image(htrans);
341 uves_free_image(htrans_original);
342 uves_free_table(&ordertable);
399 const cpl_image *inputimage,
int NORDERS,
400 bool norders_is_guess,
401 int SAMPLEWIDTH,
double PTHRES,
double MINSLOPE,
402 double MAXSLOPE,
int SLOPERES,
405 cpl_table *results = NULL;
408 cpl_stats *stats = NULL;
411 bool automatic =
false;
413 double intensity = 0;
414 double prev_intensity = 0;
415 int norders_detected = 0;
421 passure( inputimage != NULL,
" ");
422 passure( NORDERS >= 0,
"%d", NORDERS);
423 passure( SAMPLEWIDTH > 0,
"%d", SAMPLEWIDTH);
424 passure( 0 <= PTHRES && PTHRES <= 1,
"%f", PTHRES);
425 passure( SLOPERES > 0,
"%d", SLOPERES);
431 uves_msg(
"Could not find information about predicted number of orders. "
432 "Entering automatic mode (threshold = %f)", PTHRES);
437 uves_msg(
"Searching for %d (%s) order lines",
438 NORDERS, (norders_is_guess) ?
"or less" :
"exactly");
447 tablesize = cpl_image_get_size_y(inputimage);
455 check(( results = cpl_table_new(tablesize),
456 cpl_table_new_column(results,
"Slope", CPL_TYPE_DOUBLE),
457 cpl_table_new_column(results,
"Intersept", CPL_TYPE_DOUBLE),
458 cpl_table_new_column(results,
"Spacing", CPL_TYPE_INT)),
459 "Could not initialize order table");
462 check( stats = cpl_stats_new_from_image(htrans, CPL_STATS_MAX | CPL_STATS_MAXPOS),
463 "Could not get statistics on Hough image");
469 check( globmax = cpl_stats_get_max(stats),
470 "Could not locate first maximum in hough image" );
472 prev_intensity = globmax;
477 while ( (!automatic &&
478 (norders_detected < NORDERS &&
479 (!norders_is_guess || cpl_stats_get_max(stats) >= PTHRES*prev_intensity)))
481 && cpl_stats_get_max(stats) >= PTHRES*prev_intensity)
489 norders_detected += 1;
490 check((intensity = cpl_stats_get_max(stats),
491 xmax = cpl_stats_get_max_x(stats),
492 ymax = cpl_stats_get_max_y(stats)),
493 "Could not locate maximum");
497 norders_detected, intensity/globmax * 100);
500 if (intensity < PTHRES * prev_intensity)
503 "%f %% of %d. line. Detecting too many orders?",
504 norders_detected, intensity / prev_intensity * 100,
505 norders_detected - 1);
507 prev_intensity = intensity;
510 if (norders_detected == 1)
514 SPACING = uves_round_double(
515 cpl_image_get_size_y(inputimage) / NORDERS );
522 "Could not estimate interorder spacing");
525 uves_msg(
"Estimated order spacing is %d pixels", SPACING);
533 cpl_image_get_size_x(inputimage),
537 SLOPERES),
"Could not update peak position");
540 minintersept, xmax, ymax, SPACING,
541 cpl_image_get_size_x(inputimage),
543 MINSLOPE, MAXSLOPE, SLOPERES),
544 "Could not delete peak in hough image");
547 isept = minintersept + ymax;
550 assure( norders_detected <= tablesize, CPL_ERROR_ILLEGAL_OUTPUT,
551 "%d orders detected. This is way too many. "
552 "Try to decrease NORDERS (from %d) or increase PTHRES (from %f)",
553 norders_detected, NORDERS, PTHRES);
555 check(( cpl_table_set_double(results,
"Slope" , norders_detected - 1, slope),
556 cpl_table_set_double(results,
"Intersept" , norders_detected - 1, isept),
557 cpl_table_set_int (results,
"Spacing" , norders_detected - 1, SPACING)),
558 "Could add order line to order table");
561 check(( uves_free_stats(&stats),
562 stats = cpl_stats_new_from_image(htrans, CPL_STATS_MAX | CPL_STATS_MAXPOS)),
563 "Could not get statistics on hough image");
566 uves_msg(
"The intensity of the faintest line is %f of "
567 "the intensity of the brightest line", intensity / globmax);
568 uves_msg(
"Intensity of next (undetected) line is %f of the "
569 "intensity of the brightest line", cpl_stats_get_max(stats)/globmax);
571 if ( cpl_stats_get_max(stats) > 0.5 * intensity )
574 "of faintest line. Detecting too few orders?",
575 cpl_stats_get_max(stats) / intensity * 100);
579 check( cpl_table_set_size(results, norders_detected),
580 "Could not remove extra rows from order table");
584 check( uves_sort_table_1(results,
"Intersept",
false),
585 "Could not sort order table");
590 cpl_table_new_column(results,
"Order", CPL_TYPE_INT);
591 for (i = 0; i < cpl_table_get_nrow(results); i++)
593 cpl_table_set_int(results,
"Order", i, i+1);
604 int minorder, maxorder;
609 for (i = cpl_table_get_nrow(results)/2;
610 i <= cpl_table_get_nrow(results) - 2 && maxorder < 0;
613 if (i == cpl_table_get_nrow(results)/2)
617 cpl_table_get_double(results,
"Intersept", i+1, NULL)-
618 cpl_table_get_double(results,
"Intersept", i, NULL);
623 cpl_table_get_double(results,
"Intersept", i+1, NULL)-
624 cpl_table_get_double(results,
"Intersept", i, NULL);
627 cpl_table_get_int(results,
"Order", i, NULL),
628 cpl_table_get_int(results,
"Order", i+1, NULL),
631 if (0.5*dist <= new_dist && new_dist <= 1.5*dist)
638 maxorder = cpl_table_get_int(results,
"Order", i, NULL);
641 "%.2f pixels. Discarding order(s) %d and above",
650 for (i = cpl_table_get_nrow(results)/2;
651 i >= 1 && minorder < 0;
654 if (i == cpl_table_get_nrow(results)/2)
658 cpl_table_get_double(results,
"Intersept", i, NULL)-
659 cpl_table_get_double(results,
"Intersept", i-1, NULL);
664 cpl_table_get_double(results,
"Intersept", i, NULL)-
665 cpl_table_get_double(results,
"Intersept", i-1, NULL);
668 cpl_table_get_int(results,
"Order", i-1, NULL),
669 cpl_table_get_int(results,
"Order", i, NULL),
672 if (0.5*dist <= new_dist && new_dist <= 1.5*dist)
679 minorder = cpl_table_get_int(results,
"Order", i, NULL);
682 "%.2f pixels. Discarding order(s) %d and below",
692 check_nomsg( n_removed += uves_erase_table_rows(results,
"Order",
693 CPL_GREATER_THAN, maxorder));
697 check_nomsg( n_removed += uves_erase_table_rows(results,
"Order",
698 CPL_LESS_THAN, minorder));
702 norders_detected -= n_removed;
708 for (i = 0; i < cpl_table_get_nrow(results); i++)
710 cpl_table_set_int(results,
"Order", i, i+1);
714 uves_msg(
"Hough transform detected %d orders", norders_detected);
716 passure( norders_detected == cpl_table_get_nrow(results),
"%d %" CPL_SIZE_FORMAT
"",
717 norders_detected, cpl_table_get_nrow(results));
720 uves_free_stats(&stats);
721 uves_free_propertylist(&pl);
722 if (cpl_error_get_code() != CPL_ERROR_NONE)
724 uves_free_table(&results);
766 const int nx = cpl_image_get_size_x(htrans);
767 const int ny = cpl_image_get_size_y(htrans);
768 const int slope = -imagewidth/2;
769 const double numberoftraces = 1 + imagewidth/SAMPLEWIDTH;
773 double threshold = (1 - 0.5 / numberoftraces) *
774 cpl_image_get(htrans, *xmax, *ymax, &pis_rejected);
775 if (threshold < 0.99) threshold = 0.99;
777 assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
778 "Could not read Hough image data");
785 for (hx = 1; hx <= SLOPERES; hx++)
789 *ymax + slope*(hx - *xmax)/((
double)SLOPERES)*(MAXSLOPE - MINSLOPE));
796 for (hy = rowcenter - 0*SPACING/2; hy <= rowcenter + 0*SPACING/2; hy++)
798 if (1 <= hx && hx <= nx &&
801 double pixelvalue = cpl_image_get(
802 htrans, hx, hy, &pis_rejected);
803 if (!pis_rejected && pixelvalue >= threshold)
814 uves_msg_debug(
"Peak position in Hough space changed from (%d, %d)", *xmax, *ymax);
815 *xmax = uves_round_double(mx/sum);
816 *ymax = uves_round_double(my/sum);
821 return cpl_error_get_code();
840 double autoc =
autocorr(image, x, shift);
842 assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
843 "Could not calculate autocorrelation function");
851 "Could not calculate autocorrelation function");
853 }
while (autoc <= previous);
856 return 2*(shift - 1);
875 static double autocorr(
const cpl_image *image,
const int x,
const int shift)
878 const int ny = cpl_image_get_size_y(image);
879 assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
880 "Could not read image dimensions");
882 if( shift >= ny )
return 0;
887 int number_of_points = 0;
888 for (y = 1; y <= ny - shift; y++){
892 pixelvalue = cpl_image_get(image, x, y, &pis_rejected) *
893 cpl_image_get(image, x, y + shift, &pis_rejected);
897 number_of_points += 1;
900 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
901 "Error reading image pixel values");
903 if (number_of_points > 0)
905 result = sum / number_of_points;
934 while(result - SAMPLEWIDTH >= 1)
936 result -= SAMPLEWIDTH;
966 static cpl_error_code
delete_peak(cpl_image *htrans,
int minintersept,
967 int hxmax,
int hymax,
968 int SPACING,
int imagewidth,
int SAMPLEWIDTH,
969 double MINSLOPE,
double MAXSLOPE,
int SLOPERES)
971 const int ny = cpl_image_get_size_y(htrans);
973 int firstcol =
firsttrace(imagewidth, SAMPLEWIDTH);
975 assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
976 "Could not read hough image data");
979 for (tracecol = firstcol; tracecol <= imagewidth; tracecol += SAMPLEWIDTH){
981 double slope = SLOPE(hxmax);
982 double intersept = minintersept + hymax;
983 double imagey = intersept + slope*tracecol;
988 for (hx = 1; hx <= SLOPERES; hx++){
990 intersept = imagey - slope*tracecol;
991 for (hy = (intersept - minintersept) - SPACING/3;
992 hy <= (intersept - minintersept) + SPACING/3;
994 if (0 < hy && hy <= ny) {
995 check( cpl_image_set(htrans, hx, hy, 0),
996 "Could not write pixel at (%d, %d)", hx, hy);
1003 return cpl_error_get_code();
1023 cpl_stats *stats = NULL;
1029 passure( ordertable != NULL,
" ");
1030 passure( cpl_table_has_column(ordertable,
"Intersept"),
" ");
1031 passure( cpl_table_has_column(ordertable,
"Slope" ),
" ");
1033 nx = cpl_image_get_size_x(image);
1034 ny = cpl_image_get_size_y(image);
1037 check( stats = cpl_stats_new_from_image(image, CPL_STATS_MAX),
1038 "Could not get statistics on input image");
1039 check( penvalue = 2*cpl_stats_get_max(stats),
1040 "Could not find image maximum value" );
1043 check ( nrows = cpl_table_get_nrow(ordertable),
1044 "Could not read number of rows in ordertable");
1045 for (i = 0; i < nrows; i++)
1048 double intersept, slope;
1050 check(( intersept = cpl_table_get_double(ordertable,
"Intersept", i, NULL),
1051 slope = cpl_table_get_double(ordertable,
"Slope", i, NULL)),
1052 "Could not read 'Intersept' and 'Slope' from ordertable");
1054 for (x = 1; x <= nx; x++){
1055 double yd = intersept + x * slope;
1056 int y = uves_round_double(yd);
1058 if (0 < y && y <= ny)
1060 cpl_image_set(image, x, y, penvalue);
1063 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
1064 "Could not draw order in table row #%d", i);
1068 uves_free_stats(&stats);
1069 return cpl_error_get_code();
#define uves_msg_warning(...)
Print an warning message.
static cpl_table * detect_lines(cpl_image *htrans, int minintersept, const cpl_image *inputimage, int NORDERS, bool norders_is_guess, int SAMPLEWIDTH, double PTHRES, double MINSLOPE, double MAXSLOPE, int SLOPERES, bool consecutive)
Detect order lines from the Hough image.
cpl_table * uves_hough(const cpl_image *image, int ymin, int ymax, int NORDERS, bool norders_is_guess, int SAMPLEWIDTH, double PTHRES, double MINSLOPE, double MAXSLOPE, int SLOPERES, bool consecutive, cpl_image **htrans, cpl_image **htrans_original)
Compute Hough transform and detect lines.
#define passure(BOOL,...)
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
static cpl_error_code update_max(const cpl_image *htrans, int *xmax, int *ymax, int SPACING, int imagewidth, int SAMPLEWIDTH, double MINSLOPE, double MAXSLOPE, int SLOPERES)
Improve position of a peak in the Hough image.
static double autocorr(const cpl_image *image, int x, int shift)
Calculate auto-correlation function of image column.
#define uves_msg_debug(...)
Print a debug message.
cpl_error_code uves_draw_orders(const cpl_table *ordertable, cpl_image *image)
Draw detected order lines.
#define assure_nomsg(BOOL, CODE)
static int firsttrace(int nx, int SAMPLEWIDTH)
Get the first trace column.
static cpl_error_code delete_peak(cpl_image *htrans, int minintersept, int hxmax, int hymax, int SPACING, int imagewidth, int SAMPLEWIDTH, double MINSLOPE, double MAXSLOPE, int SLOPERES)
Delete peak in Hough image.
static int calculate_spacing(const cpl_image *, int x)
Estimate spacing of order lines.