diff options
author | gfb21 <gfb21@bf6ca9ba-c028-0410-8290-897cf20841d1> | 2007-02-06 17:49:07 +0000 |
---|---|---|
committer | gfb21 <gfb21@bf6ca9ba-c028-0410-8290-897cf20841d1> | 2007-02-06 17:49:07 +0000 |
commit | 8bf5f5847dd88d812daebc245e07a6f1fb79035c (patch) | |
tree | 956f30476b1d5665f3cfc06ee964c751f21696b9 /src | |
parent | b290377fce94078fa4cf8271eb5e8f5174225da4 (diff) |
Added iterative peaksearch method
git-svn-id: svn://cook.msm.cam.ac.uk:745/diff-tomo/dtr@3 bf6ca9ba-c028-0410-8290-897cf20841d1
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.in | 92 | ||||
-rw-r--r-- | src/control.h | 3 | ||||
-rw-r--r-- | src/itrans.c | 26 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/peakdetect.c | 449 | ||||
-rw-r--r-- | src/peakdetect.h | 19 |
7 files changed, 552 insertions, 41 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1e532f1..1b29a7a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS = dtr -dtr_SOURCES = main.c displaywindow.c trackball.c reflections.c readpng.c mrc.c imagedisplay.c utils.c itrans.c qdrp.c ipr.c +dtr_SOURCES = main.c displaywindow.c trackball.c reflections.c readpng.c mrc.c imagedisplay.c utils.c itrans.c qdrp.c ipr.c peakdetect.c dtr_LDADD = @LIBS@ @GTK_LIBS@ -lm @GTKGLEXT_LIBS@ -lgsl -lgslcblas AM_CFLAGS = -Wall -g @CFLAGS@ @GTK_CFLAGS@ @GTKGLEXT_CFLAGS@ AM_CPPFLAGS = -DDATADIR=\""$(datadir)"\" diff --git a/src/Makefile.in b/src/Makefile.in index d07e5be..d6994f2 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.6 from Makefile.am. +# Makefile.in generated by automake 1.10 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -14,15 +14,11 @@ @SET_MAKE@ -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c @@ -50,10 +46,11 @@ PROGRAMS = $(bin_PROGRAMS) am_dtr_OBJECTS = main.$(OBJEXT) displaywindow.$(OBJEXT) \ trackball.$(OBJEXT) reflections.$(OBJEXT) readpng.$(OBJEXT) \ mrc.$(OBJEXT) imagedisplay.$(OBJEXT) utils.$(OBJEXT) \ - itrans.$(OBJEXT) qdrp.$(OBJEXT) ipr.$(OBJEXT) + itrans.$(OBJEXT) qdrp.$(OBJEXT) ipr.$(OBJEXT) \ + peakdetect.$(OBJEXT) dtr_OBJECTS = $(am_dtr_OBJECTS) dtr_DEPENDENCIES = -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ @@ -66,8 +63,6 @@ ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -91,6 +86,7 @@ GTKGLEXT_CFLAGS = @GTKGLEXT_CFLAGS@ GTKGLEXT_LIBS = @GTKGLEXT_LIBS@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_LIBS = @GTK_LIBS@ +INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -101,6 +97,7 @@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -114,9 +111,11 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -124,6 +123,7 @@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ +builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ @@ -147,9 +147,12 @@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ -dtr_SOURCES = main.c displaywindow.c trackball.c reflections.c readpng.c mrc.c imagedisplay.c utils.c itrans.c qdrp.c ipr.c +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +dtr_SOURCES = main.c displaywindow.c trackball.c reflections.c readpng.c mrc.c imagedisplay.c utils.c itrans.c qdrp.c ipr.c peakdetect.c dtr_LDADD = @LIBS@ @GTK_LIBS@ -lm @GTKGLEXT_LIBS@ -lgsl -lgslcblas AM_CFLAGS = -Wall -g @CFLAGS@ @GTK_CFLAGS@ @GTKGLEXT_CFLAGS@ AM_CPPFLAGS = -DDATADIR=\""$(datadir)"\" @@ -188,7 +191,7 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ @@ -211,7 +214,7 @@ clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) dtr$(EXEEXT): $(dtr_OBJECTS) $(dtr_DEPENDENCIES) @rm -f dtr$(EXEEXT) - $(LINK) $(dtr_LDFLAGS) $(dtr_OBJECTS) $(dtr_LDADD) $(LIBS) + $(LINK) $(dtr_OBJECTS) $(dtr_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -225,6 +228,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/itrans.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mrc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peakdetect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qdrp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readpng.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reflections.Po@am__quote@ @@ -232,19 +236,18 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ .c.o: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` -uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -295,22 +298,21 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ @@ -326,7 +328,7 @@ check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(mkdir_p) "$$dir"; \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am @@ -374,12 +376,20 @@ info-am: install-data-am: +install-dvi: install-dvi-am + install-exec-am: install-binPROGRAMS +install-html: install-html-am + install-info: install-info-am install-man: +install-pdf: install-pdf-am + +install-ps: install-ps-am + installcheck-am: maintainer-clean: maintainer-clean-am @@ -399,18 +409,22 @@ ps: ps-am ps-am: -uninstall-am: uninstall-binPROGRAMS uninstall-info-am +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-exec install-exec-am \ - install-info install-info-am install-man install-strip \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS uninstall-info-am + uninstall-am uninstall-binPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/control.h b/src/control.h index 0493757..d557f41 100644 --- a/src/control.h +++ b/src/control.h @@ -32,7 +32,8 @@ typedef enum { PEAKSEARCH_THRESHOLD, PEAKSEARCH_ADAPTIVE_THRESHOLD, PEAKSEARCH_LSQ, - PEAKSEARCH_ZAEFFERER + PEAKSEARCH_ZAEFFERER, + PEAKSEARCH_ITERATIVE } PeakSearchMode; typedef enum { diff --git a/src/itrans.c b/src/itrans.c index 0480f3f..1b66915 100644 --- a/src/itrans.c +++ b/src/itrans.c @@ -17,6 +17,7 @@ #include "control.h" #include "imagedisplay.h" #include "utils.h" +#include "peakdetect.h" #define MAX_LSQ_ITERATIONS 100 #define PEAK_WINDOW_SIZE 20 @@ -499,6 +500,30 @@ static unsigned int itrans_peaksearch_lsq(int16_t *image, ControlContext *ctx, d return n_reflections; } +static unsigned int itrans_peaksearch_iterative(int16_t *image, ControlContext *ctx, double tilt_degrees, ImageDisplay *imagedisplay) { + printf("Starting itrans_peaksearch_iterative\n"); + int n_reflections; + gsl_matrix *m; + gsl_matrix *p; + printf("Calling createImageMatrix\n"); + m = createImageMatrix(ctx,image); + printf("Calling iterate\n"); + p = iterate(m, &n_reflections); + int i; + double px,py; + printf("Found %d reflections\n",n_reflections); + for (i=0;i<n_reflections;i++) { + px = gsl_matrix_get(p,0,i); + py = gsl_matrix_get(p,1,i); + printf("Reflection %d (%lf,%lf)\n",i,px,py); + reflection_add_from_dp(ctx, (px-ctx->x_centre), (py-ctx->y_centre), tilt_degrees, 1.); + if (ctx->first_image) imagedisplay_mark_point(imagedisplay, (unsigned int)px, (unsigned int)py); + } + gsl_matrix_free(m); + gsl_matrix_free(p); + return (unsigned)n_reflections; +} + void itrans_process_image(int16_t *image, ControlContext *ctx, double tilt_degrees) { unsigned int n_reflections; @@ -514,6 +539,7 @@ void itrans_process_image(int16_t *image, ControlContext *ctx, double tilt_degre case PEAKSEARCH_ADAPTIVE_THRESHOLD : n_reflections = itrans_peaksearch_adaptive_threshold(image, ctx, tilt_degrees, imagedisplay); break; case PEAKSEARCH_LSQ : n_reflections = itrans_peaksearch_lsq(image, ctx, tilt_degrees, imagedisplay); break; case PEAKSEARCH_ZAEFFERER : n_reflections = itrans_peaksearch_zaefferer(image, ctx, tilt_degrees, imagedisplay); break; + case PEAKSEARCH_ITERATIVE : n_reflections = itrans_peaksearch_iterative(image, ctx, tilt_degrees, imagedisplay); break; default: n_reflections = 0; } @@ -45,6 +45,7 @@ static gint main_method_window_response(GtkWidget *method_window, gint response, case 1 : ctx->psmode = PEAKSEARCH_ADAPTIVE_THRESHOLD; break; case 2 : ctx->psmode = PEAKSEARCH_LSQ; break; case 3 : ctx->psmode = PEAKSEARCH_ZAEFFERER; break; + case 4 : ctx->psmode = PEAKSEARCH_ITERATIVE; break; default: abort(); } @@ -113,6 +114,7 @@ void main_method_dialog_open(ControlContext *ctx) { gtk_combo_box_append_text(GTK_COMBO_BOX(ctx->combo_peaksearch), "Adaptive Thresholding"); gtk_combo_box_append_text(GTK_COMBO_BOX(ctx->combo_peaksearch), "Least-Squares Fit"); gtk_combo_box_append_text(GTK_COMBO_BOX(ctx->combo_peaksearch), "Zaefferer Gradient Search"); + gtk_combo_box_append_text(GTK_COMBO_BOX(ctx->combo_peaksearch), "Iterative Statistical"); gtk_combo_box_set_active(GTK_COMBO_BOX(ctx->combo_peaksearch), 3); gtk_table_attach_defaults(GTK_TABLE(table), ctx->combo_peaksearch, 2, 3, 2, 3); diff --git a/src/peakdetect.c b/src/peakdetect.c new file mode 100644 index 0000000..666e23f --- /dev/null +++ b/src/peakdetect.c @@ -0,0 +1,449 @@ +/* + * peakdetect.c + * + * Peakdetection routines, utilities and automation + * + * (c) 2007 Gordon Ball <gfb21@cam.ac.uk> + * dtr - Diffraction Tomography Reconstruction + * + */ + +#include <math.h> +#include "reflections.h" +#include "control.h" +#include "imagedisplay.h" +#include "utils.h" +#include "peakdetect.h" + +/* + * Renormalise a gsl_matrix to 0->1 + * Re-written to use gsl_matrix native functions + */ +void renormalise(gsl_matrix *m) { + double max,min; + gsl_matrix_minmax(m,&min,&max); + printf("Renormalising min=%lf max=%lf\n",min,max); + gsl_matrix_add_constant(m,0.-min); + gsl_matrix_scale(m,1./(max-min)); +} + +/* + * Create a gsl_matrix for performing image operations on + * from a raw image and control context + * Converting to gsl_matrix because many of the required operations + * can be done as matrices to save effort + * Renormalises matrix to 0->1 + */ +gsl_matrix* createImageMatrix(ControlContext *ctx, int16_t *image) { + gsl_matrix *raw; + raw = gsl_matrix_alloc(ctx->width,ctx->height); + + int i,j; + for ( i=0; i<raw->size1;i++) { + for (j=0; j<raw->size2;j++) { + gsl_matrix_set(raw,i,j,(double)image[i+j*ctx->width]); + } + } + printf("Created %dx%d matrix\n",ctx->width,ctx->height); + renormalise(raw); + return raw; +} + + + +/* + * Find and return the mean value of the matrix + */ +double image_mean(gsl_matrix *m) { + double mean=0.; + int i,j; + for (i=0;i<m->size1;i++) { + for (j=0;j<m->size2;j++) { + mean += gsl_matrix_get(m,i,j); + } + } + return mean / (m->size1 * m->size2); +} + +/* + * Return the standard deviation, sigma, of the matrix values + * \sqrt(\sum((x-mean)^2)/n) + */ +double image_sigma(gsl_matrix *m, double mean) { + double diff2=0; + int i,j; + for (i=0;i<m->size1;i++) { + for (j=0;j<m->size2;j++) { + diff2 += (gsl_matrix_get(m,i,j)-mean)*(gsl_matrix_get(m,i,j)-mean); + } + } + return sqrt(diff2/(m->size1 * m->size2)); +} + +/* + * Filter all pixels with value < mean + k*sigma to 0 + * Set all matching pixels to 1 + */ +void sigma_filter(gsl_matrix *m, double k) { + double mean,sigma; + int i,j; + mean = image_mean(m); + sigma = image_sigma(m,mean); + for (i=0;i<m->size1;i++) { + for (j=0;j<m->size2;j++) { + if (gsl_matrix_get(m,i,j) >= mean+k*sigma) { + gsl_matrix_set(m,i,j,1.); + } else { + gsl_matrix_set(m,i,j,0.); + } + } + } +} + +/* + * Calculate the mean within a circle centred (x,y) of radius r + * + * TODO: Use a mask instead of calculating valid points + */ +double circle_mean(gsl_matrix *m, int x, int y, int r, gsl_matrix *mask) { + double mean=0.; + int i,j,n=0; + for (i=x-r;i<=x+r;i++) { + for (j=y-r;j<=y+r;j++) { + //printf("cm: ij=(%d,%d) mask=(%d,%d)\n",i,j,i-x+r,j-y+r); + if (gsl_matrix_get(mask,i-x+r,j-y+r)>0.) { + mean += gsl_matrix_get(m,i,j); + //printf("cm: (%d,%d) mean=%lf val=%lf\n",i,j,mean,gsl_matrix_get(m,i,j)); + n++; + } + } + } + //printf("cm: (%d,%d) summean=%lf n=%d\n",x,y,mean,n); + return mean/n; +} + +/* + * Calculate sigma within a circle centred (x,y) of radius r + * + * TODO: Use a mask instead of calculating valid points + */ +double circle_sigma(gsl_matrix *m, int x, int y, int r, gsl_matrix *mask, double mean) { + double diff2=0.; + int i,j,n=0; + for (i=x-r;i<=x+r;i++) { + for (j=y-r;j<=y+r;j++) { + if (gsl_matrix_get(mask,i-x+r,j-y+r)>0) { + diff2 += (gsl_matrix_get(m,i,j)-mean)*(gsl_matrix_get(m,i,j)-mean); + n++; + } + } + } + return sqrt(diff2/n); +} + +/* + * Calculate a circular mask to save recalculating it every time + */ +gsl_matrix* circle_mask(int r) { + gsl_matrix *m; + m = gsl_matrix_calloc(2*r+1,2*r+1); + int i,j; + for (i=0;i<2*r+1;i++) { + for (j=0;j<2*r+1;j++) { + if (sqrt((r-i)*(r-i)+(r-j)*(r-j))<=(double)r) { + gsl_matrix_set(m,i,j,1.); + } + + } + } + return m; +} + +/* + * Variation on the above filter where instead of using + * sigma and mean for the whole image, it is found for a local + * circle of radius r pixels. + * The central point is also calculated as an approximately gaussian + * average over local pixels rather than just a single pixel. + * This takes a long time - 20-30 seconds for a 1024^2 image and r=10, + * obviously large values of r will make it even slower. + * The appropriate r value needs to be considered carefully - it needs to + * be somewhat smaller than the average inter-reflection seperation. + * 10 pixels worked well for the sapphire.mrc images, but this might + * not be the case for other images. Images for which this would be very + * large probably need to be resampled to a lower resolution. + * + * TODO: Pass a mask to the ancilliary functions instead of having + * them calculate several hundred million sqrts + * + * self-referencing problem being dealt with - output being written onto the array before the next point it computed + * problem carried over from the OO version where a new object was created by each operation + */ + +void local_sigma_filter(gsl_matrix *m, int r, double k) { + //printf("lsf: starting\n"); + double mean,sigma; + double local; + //printf("lsf: generating circle mask\n"); + gsl_matrix *mask = circle_mask(r); + gsl_matrix *new; + new = gsl_matrix_alloc(m->size1,m->size2); + int i,j; + int interval = (m->size1-r)/20; + //printf("lsf: starting loop\n"); + printf("lsf: "); + //for (i=r;i<m->size1-r;i++) { + // for (j=r;j<m->size2-r;j++) { + for (i=0;i<m->size1;i++) { + for (j=0;j<m->size2;j++) { + if ((i>=r && i<m->size1-r) && (j>=r && j<m->size2-r)) { + //printf("lsf: evaluating (%d,%d)\n",i,j); + mean = circle_mean(m,i,j,r,mask); + //printf("lsf: mean=%lf",mean); + sigma = circle_sigma(m,i,j,r,mask,mean); + //printf(" sigma=%lf",sigma); + local = gsl_matrix_get(m,i,j); + local += gsl_matrix_get(m,i+1,j) + gsl_matrix_get(m,i-1,j) + gsl_matrix_get(m,i,j+1) + gsl_matrix_get(m,i,j-1); + local += .5*(gsl_matrix_get(m,i+1,j+1) + gsl_matrix_get(m,i-1,j+1) + gsl_matrix_get(m,i+1,j-1) + gsl_matrix_get(m,i-1,j-1)); + local /= 7.; + //printf(" local=%lf\n",local); + if (local > mean+k*sigma) { + gsl_matrix_set(new,i,j,1.); + } else { + gsl_matrix_set(new,i,j,0.); + } + } else { + gsl_matrix_set(new,i,j,0.); + } + } + if (i % interval == 0) printf("."); + } + printf("done\n"); + gsl_matrix_memcpy(m,new); + gsl_matrix_free(new); +} + + + +/* + * Apply an arbitary kernel to the image - each point takes the value + * of the sum of the kernel convolved with the surrounding pixels. + * The kernel needs to be a (2n+1)^2 array (centred on (n,n)). It needs + * to be square and should probably be normalised. + * Don't do daft things like rectangular kernels or kernels larger + * than the image - this doesn't check such things and will cry. + * + * Also suffers from self-reference problem + */ +void apply_kernel(gsl_matrix *m, gsl_matrix *kernel) { + int size = kernel->size1; + int half = (size-1)/2; + gsl_matrix *l; + gsl_matrix_view lv; + gsl_matrix *new; + new = gsl_matrix_calloc(m->size1,m->size2); + double val; + int i,j,x,y; + for (i=0;i<m->size1;i++) { + for (j=0;j<m->size2;j++) { + if ((i>=half && i<m->size1-half) && (j>=half && j<m->size2-half)) { + lv = gsl_matrix_submatrix(m,i-half,j-half,size,size); + l = &lv.matrix; + val = 0.; + for (x=0;x<size;x++) { + for (y=0;y<size;y++) { + val += gsl_matrix_get(l,x,y)*gsl_matrix_get(kernel,x,y); + } + } + //gsl_matrix_free(l); + gsl_matrix_set(new,i,j,val); + } + } + } + gsl_matrix_memcpy(m,new); + gsl_matrix_free(new); +} + +/* + * Generate the simplist possible kernel - a flat one + */ +gsl_matrix* generate_flat_kernel(int half) { + gsl_matrix *k; + k = gsl_matrix_alloc(2*half+1,2*half+1); + gsl_matrix_set_all(k,1./((2*half+1)*(2*half+1))); + return k; +} + +/* + * expands or contracts a gsl_matrix by copying the columns to a new one + */ +gsl_matrix* matrix_expand(gsl_matrix *m, int oldsize, int newsize) { + gsl_matrix *new; + + printf("me: %d->%d\n",oldsize,newsize); + + new = gsl_matrix_calloc(2,newsize); + //printf("me: calloc(2,%d)\n",newsize); + int j; + for (j = 0; j < oldsize; j++) { + if (j < newsize) { + //printf("me: copying col %d\n",j); + gsl_matrix_set(new,0,j,gsl_matrix_get(m,0,j)); + gsl_matrix_set(new,1,j,gsl_matrix_get(m,1,j)); + } + } + //printf("me: freeing old matrix\n"); + gsl_matrix_free(m); + //printf("me: new s1=%d s2=%d\n",new->size1,new->size2); + return new; + //printf("me: m s1=%d s2=%d\n",m->size1,m->size2); +} + +/* + * Stack-based flood-fill iteration routine + * have to return a pointer to com each time because if the matrix size has to be changed then we need to keep + * track of the location of the resized instance + */ + +gsl_matrix* do_ff(int i, int j, int* mask, double threshold, gsl_matrix *m, gsl_matrix *com, int *com_n, int *com_size) { + if (i>=0 && i<m->size1) { + if (j>=0 && j<m->size2) { + if (mask[i+j*m->size1]==0) { + if (gsl_matrix_get(m,i,j)>threshold) { + //printf("dff: found valid point (%d,%d)\n",i,j); + gsl_matrix_set(com,0,*com_n,(double)i); + gsl_matrix_set(com,1,*com_n,(double)j); + *com_n=*com_n+1; + if (*com_n == *com_size) { + com = matrix_expand(com,*com_size,*com_size*2); + *com_size *= 2; + } + mask[i+j*m->size1]=1; + com = do_ff(i+1,j,mask,threshold,m,com,com_n,com_size); + com = do_ff(i-1,j,mask,threshold,m,com,com_n,com_size); + com = do_ff(i,j+1,mask,threshold,m,com,com_n,com_size); + com = do_ff(i,j-1,mask,threshold,m,com,com_n,com_size); + } + } + } + } + return com; +} + +/* + * Find points by floodfilling all pixels above threshold + * Implements a stack-based flood-filling method which may + * cause stack overflows if the blocks are extremely large - + * dependent on implementation (default 4MiB stack for unix?) + * Implements a crude variable-sized array method which hopefully works + * Returns a gsl_matrix with x coordinates in row 0 and y + * coordinates in row 1, which should be of the right length + * Variable count is set to the number of points found + */ + +gsl_matrix* floodfill(gsl_matrix *m, double threshold, int *count) { + //printf("ff: starting\n"); + int *mask; + mask = calloc(m->size1*m->size2,sizeof(int)); + + int size=32,com_size; + int i,j,k,n=0; + int com_n; + gsl_matrix *p; + gsl_matrix *com; + p = gsl_matrix_calloc(2,size); + + double com_x,com_y; + printf("ff: starting loop\n"); + for (i=0;i<m->size1;i++) { + for (j=0;j<m->size2;j++) { + if (gsl_matrix_get(m,i,j)>threshold) { + if (mask[i+j*m->size1]==0) { + //printf("ff: found starting point (%d,%d)\n",i,j); + com_size=32; + com_n=0; + com_x = com_y = 0.; + com = gsl_matrix_calloc(2,com_size); //this is going to hold the points found for this location + //printf("ff: starting floodfill stack\n"); + com = do_ff(i, j, mask, threshold, m, com, &com_n, &com_size); + //printf("ff: ended floodfill stack\n"); + for (k=0;k<com_n;k++) { + com_x += gsl_matrix_get(com,0,k); + com_y += gsl_matrix_get(com,1,k); + } + com_x /= com_n; + com_y /= com_n; + printf("ff: point CoM (%lf,%lf)\n",com_x,com_y); + gsl_matrix_set(p,0,n,com_x); + gsl_matrix_set(p,1,n,com_y); + n++; + if (n==size) { + p = matrix_expand(p,size,size*2); + size *= 2; + } + } + } + } + } + printf("ff: ending loop, found %d\n",n); + *count = n; + printf("pcheck s1=%d s2=%d\n",p->size1,p->size2); + p = matrix_expand(p,size,n); + printf("pcheck s1=%d s2=%d\n",p->size1,p->size2); + return p; +} + + + +/* + * implements the iteration based automatic method + * returns a gsl_matrix formatted as described in flood-fill + */ +gsl_matrix* iterate(gsl_matrix *m, int *count) { + printf("Iterate: starting\n"); + int old = m->size1*m->size2; + int cur; + double k; + double mean,sigma; + gsl_matrix *p; + gsl_matrix *kernel; + + mean = image_mean(m); + sigma = image_sigma(m,mean); + printf("Iterate: mean=%lf sigma=%lf\n",mean,sigma); + + + printf("Iterate: generating kernel\n"); + kernel = generate_flat_kernel(1); + printf("Iterate: performing local_sigma_filter\n"); + local_sigma_filter(m,10,1.); + + mean = image_mean(m); + sigma = image_sigma(m,mean); + printf("Iterate: mean=%lf sigma=%lf\n",mean,sigma); + + + printf("Iterate: starting loop\n"); + while (1) { + printf("Iterate: smoothing"); + apply_kernel(m,kernel); + printf(" (1)"); + apply_kernel(m,kernel); + printf(" (2)\n"); + mean = image_mean(m); + sigma = image_sigma(m,mean); + printf("Iterate: mean=%lf sigma=%lf\n",mean,sigma); + k = (0.5-mean)/sigma; + printf("Iterate: applying sigma_filter(%lf)\n",k); + sigma_filter(m,k); + printf("Iterate: floodfilling\n"); + p = floodfill(m,0,&cur); + printf("Iterate: %d points found\n",cur); + if (old < 1.05*cur) break; + old = cur; + } + gsl_matrix_free(kernel); + printf("Iterate: finished\n"); + *count = cur; + return p; +} diff --git a/src/peakdetect.h b/src/peakdetect.h new file mode 100644 index 0000000..13837d1 --- /dev/null +++ b/src/peakdetect.h @@ -0,0 +1,19 @@ +/* + * peakdetect.h + */ + +#include <gsl/gsl_matrix.h> + +extern gsl_matrix* createImageMatrix(ControlContext *ctx, int16_t *image); + +extern void sigma_filter(gsl_matrix *m, double k); + +extern void local_sigma_filter(gsl_matrix *m, int r, double k); + +extern void apply_kernel(gsl_matrix *m, gsl_matrix *kernel); + +extern gsl_matrix* generate_flat_kernel(int half); + +extern gsl_matrix* floodfill(gsl_matrix *m, double threshold, int* count); + +extern gsl_matrix* iterate(gsl_matrix *m, int* count); |