From 68449bef8912ad2fff85d559005b28f08cb26651 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Mon, 18 Oct 2021 17:24:03 +0300 Subject: [PATCH] some bugs fixed --- LocCorr/CMakeLists.txt | 11 +- LocCorr/DEBUG.log.analyze | 9 ++ LocCorr/basler.c | 7 +- LocCorr/binmorph.c | 119 ++++-------------- LocCorr/binmorph.h | 16 +-- LocCorr/cameracapture.c | 50 ++++---- LocCorr/cameracapture.h | 5 +- LocCorr/cmdlnopts.c | 4 +- LocCorr/config.c | 45 ++----- LocCorr/config.h | 4 +- LocCorr/debug.c | 57 +++++++++ LocCorr/debug.h | 53 ++++++++ LocCorr/dilation.h | 6 + LocCorr/draw.c | 31 ++++- LocCorr/draw.h | 14 +-- LocCorr/ec_filter.h | 6 + LocCorr/fc_filter.h | 6 + LocCorr/fits.c | 116 +++++++----------- LocCorr/fits.h | 24 +--- LocCorr/grasshopper.c | 16 ++- LocCorr/imagefile.c | 249 ++++++++++++++++++++++++-------------- LocCorr/imagefile.h | 28 ++++- LocCorr/improc.c | 76 +++++++----- LocCorr/improc.h | 3 +- LocCorr/inotify.c | 2 +- LocCorr/main.c | 9 +- LocCorr/median.c | 131 +++++--------------- LocCorr/median.h | 1 - LocCorr/pusirobo.c | 24 ++-- LocCorr/socket.c | 6 +- 30 files changed, 577 insertions(+), 551 deletions(-) create mode 100755 LocCorr/DEBUG.log.analyze create mode 100644 LocCorr/debug.c create mode 100644 LocCorr/debug.h diff --git a/LocCorr/CMakeLists.txt b/LocCorr/CMakeLists.txt index af8cd9b..1576b76 100644 --- a/LocCorr/CMakeLists.txt +++ b/LocCorr/CMakeLists.txt @@ -5,11 +5,10 @@ set(MID_VERSION "0") set(MAJOR_VERSION "0") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") -project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C) +project(${PROJ} VERSION ${VERSION} LANGUAGES C) # default flags -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=gnu99 -march=native -fdata-sections -ffunction-sections") -SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") set(CMAKE_COLOR_MAKEFILE ON) @@ -20,10 +19,12 @@ set(CMAKE_VERBOSE_MAKEFILE "ON") # cmake -DEBUG=1 -> debugging if(DEFINED EBUG AND EBUG EQUAL 1) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wall -Werror -W") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -ggdb -fno-builtin-strlen -Wextra -Wall -Werror -W") set(CMAKE_BUILD_TYPE DEBUG) add_definitions(-DEBUG) else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fdata-sections -ffunction-sections") + SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections") set(CMAKE_BUILD_TYPE RELEASE) endif() @@ -69,7 +70,7 @@ link_directories(${${PROJ}_LIBRARY_DIRS} ${FLYCAP_LIBRARY_DIRS} ${BASLER_LIBRARY add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\" -DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\" - -DMAJOR_VERSION=\"${MAJOR_VESION}\" -DTHREAD_NUMBER=${PROCESSOR_COUNT}) + -DMAJOR_VERSION=\"${MAJOR_VERSION}\" -DTHREAD_NUMBER=${PROCESSOR_COUNT}) # -l target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} ${FLYCAP_LIBRARIES} ${BASLER_LIBRARIES} -lm) diff --git a/LocCorr/DEBUG.log.analyze b/LocCorr/DEBUG.log.analyze new file mode 100755 index 0000000..4803787 --- /dev/null +++ b/LocCorr/DEBUG.log.analyze @@ -0,0 +1,9 @@ +#!/bin/sh + +ALLOC=$(grep ALLOCSZ DEBUG.log) +FREE=$(grep FREESZ DEBUG.log) + +echo "Total: $(echo "$ALLOC" | wc -l) allocations and $(echo "$FREE" | wc -l) frees" +AL=$(echo "$ALLOC" | sed 's/ALLOCSZ(\([[:digit:]]*\))/\1/' | awk 'BEGIN{x=0;} {x=x+$1;} END{print x;}') +FR=$(echo "$FREE" | sed 's/FREESZ(\([[:digit:]]*\))/\1/' | awk 'BEGIN{x=0;} {x=x+$1;} END{print x;}') +echo "Allocated: $AL bytes, Freed: $FR bytes, difference: $((AL - FR)) bytes" diff --git a/LocCorr/basler.c b/LocCorr/basler.c index aa7e7c0..bd65759 100644 --- a/LocCorr/basler.c +++ b/LocCorr/basler.c @@ -16,10 +16,10 @@ * along with this program. If not, see . */ -#include #include #include "basler.h" +#include "debug.h" #include "imagefile.h" static PYLON_DEVICE_HANDLE hDev; @@ -74,7 +74,6 @@ static void disconnect(){ isopened = FALSE; } -// get node & check it for read/write /** * @brief chkNode - get node & check it for read/write * @param phNode (io) - pointer to node @@ -144,6 +143,7 @@ static int setBoolean(char *featureName, _Bool val){ NODE_HANDLE hNode; if(!chkNode(&hNode, featureName, BooleanNode, TRUE)) return FALSE; PYLONFN(GenApiBooleanSetValue, hNode, val); + return TRUE; } static int setInt(char *featureName, int64_t val){ if(!isopened || !featureName) return FALSE; @@ -222,6 +222,7 @@ static Image *capture(){ float_values f; if(!getFloat("DeviceTemperature", &f)) WARNX("Can't get temperature"); else{ + LOGDBG("Basler temperature: %.1f", f.val); DBG("Temperature: %.1f", f.val); if(f.val > 80.){ WARNX("Device too hot"); @@ -230,7 +231,7 @@ static Image *capture(){ toohot = TRUE; } }else if(toohot && f.val < 75.){ - LOGMSG("Device temperature is normal"); + LOGDBG("Device temperature is normal"); toohot = FALSE; } } diff --git a/LocCorr/binmorph.c b/LocCorr/binmorph.c index 4719944..eb83c84 100644 --- a/LocCorr/binmorph.c +++ b/LocCorr/binmorph.c @@ -24,8 +24,9 @@ #include // memcpy #include #include -#include + #include "binmorph.h" +#include "debug.h" #include "imagefile.h" // global arrays for erosion/dilation masks @@ -67,7 +68,7 @@ uint8_t *filter4(uint8_t *image, int W, int H){ uint8_t *ret = MALLOC(uint8_t, W*H); int W0 = (W + 7) / 8; // width in bytes int w = W0-1, h = H-1; - {int y = 0; + { // top of image, y = 0 #define IM_UP #include "fc_filter.h" @@ -79,7 +80,6 @@ uint8_t *filter4(uint8_t *image, int W, int H){ } { // image bottom, y = h - int y = h; #define IM_DOWN #include "fc_filter.h" #undef IM_DOWN @@ -99,7 +99,7 @@ uint8_t *filter8(uint8_t *image, int W, int H){ uint8_t *ret = MALLOC(uint8_t, W*H); int W0 = (W + 7) / 8; // width in bytes int w = W0-1, h = H-1; - {int y = 0; + { #define IM_UP #include "ec_filter.h" #undef IM_UP @@ -108,7 +108,6 @@ uint8_t *filter8(uint8_t *image, int W, int H){ #include "ec_filter.h" } { - int y = h; #define IM_DOWN #include "ec_filter.h" #undef IM_DOWN @@ -130,7 +129,7 @@ uint8_t *dilation(uint8_t *image, int W, int H){ uint8_t lastmask = ~(1< oldval){ + assoc[newval] = oldval; + TEST("change %zd to %zd\n", newval, oldval); + }else{ + assoc[oldval] = newval; + TEST("change %zd to %zd\n", oldval, newval); + } +} + /** * label 4-connected components on image * (slow algorythm, but easy to parallel) @@ -340,22 +356,6 @@ uint8_t *substim(uint8_t *im1, uint8_t *im2, int W, int H){ */ size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){ size_t *assoc; - // check table and rename all "oldval" into "newval" - inline void remark(size_t newval, size_t oldval){ - TEST("\tnew = %zd, old=%zd; ", newval, oldval); - // find the least values - do{newval = assoc[newval];}while(assoc[newval] != newval); - do{oldval = assoc[oldval];}while(assoc[oldval] != oldval); - TEST("\trealnew = %zd, realold=%zd ", newval, oldval); - // now change larger value to smaller - if(newval > oldval){ - assoc[newval] = oldval; - TEST("change %zd to %zd\n", newval, oldval); - }else{ - assoc[oldval] = newval; - TEST("change %zd to %zd\n", oldval, newval); - } - } if(W < MINWIDTH || H < MINHEIGHT) return NULL; uint8_t *f = filter4(Img, W, H); // remove all non 4-connected pixels //DBG("convert to size_t"); @@ -375,7 +375,7 @@ size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){ if(found){ // there's a pixel to the left if(U && U != curmark){ // meet old mark -> remark one of them in assoc[] TEST("(%d, %d): remark %zd --> %zd\n", x, y, U, curmark); - remark(U, curmark); + remark(U, curmark, assoc); curmark = U; // change curmark to upper mark (to reduce further checks) } }else{ // new mark -> change curmark @@ -428,23 +428,6 @@ size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){ boxes[i].xmin = W; boxes[i].ymin = H; } - //nonOMP: 36.5ms -/* linear: - for(int y = 0; y < H; ++y){ - size_t *lptr = &labels[y*W]; - for(int x = 0; x < W; ++x, ++lptr){ - if(!*lptr) continue; - register size_t mark = indexes[*lptr]; - *lptr = mark; - Box *b = &boxes[mark]; - ++b->area; - if(b->xmax < x) b->xmax = x; - if(b->xmin > x) b->xmin = x; - if(b->ymax < y) b->ymax = y; - if(b->ymin > y) b->ymin = y; - } - }*/ -// parallel: #pragma omp parallel shared(boxes) { Box *l_boxes = MALLOC(Box, cidx); @@ -507,60 +490,6 @@ size_t *cclabel8(size_t *labels, int W, int H, size_t *Nobj){ } #endif - -#if 0 -/** - * Make connection-component labeling - * output image vould have uint16_t data - * @param img (i) - input image - * @param threshold (i) - threshold level in value of dynamic range (0,1) - * @param Nobj (o) - amount of object found (or NULL if not needed) - */ -IMAGE *cclabel4(IMAGE *img, double threshold, size_t *Nobj){ - /*if(N != 4 || N != 8){ - ERRX(_("Can work only for 4- or 8-connected components")); - }*/ - double thrval; - uint16_t *binary = binarize(img, threshold, &thrval); - if(!binary) return NULL; - int W_0; - uint8_t *Ima = u16tochar(binary, img->width, img->height, &W_0); - FREE(binary); - size_t N; - uint16_t *dat = _cclabel4(Ima, img->width, img->height, W_0, &N); - if(Nobj) *Nobj = N; - FREE(Ima); - IMAGE *ret = buildFITSfromdat(img->height, img->width, SHORT_IMG, (uint8_t*)dat); - FREE(dat); - char buf[80]; - snprintf(buf, 80, "COMMENT found %zd 4-connected components, threshold value %g", - N, (double)thrval); - list_add_record(&ret->keylist, buf); - snprintf(buf, 80, "COMMENT (%g%% fromdata range%s)", fabs(threshold)*100., - (threshold < 0.) ? ", inverted" : ""); - list_add_record(&ret->keylist, buf); - return ret; -} - -IMAGE *cclabel8(IMAGE *img, double threshold, size_t *Nobj){ - double thrval; - uint16_t *binary = binarize(img, threshold, &thrval); - if(!binary) return NULL; - size_t N; - _cclabel8(binary, img->width, img->height, &N); - if(Nobj) *Nobj = N; - IMAGE *ret = buildFITSfromdat(img->height, img->width, SHORT_IMG, (uint8_t*)binary); - FREE(binary); - char buf[80]; - snprintf(buf, 80, "COMMENT found %zd 8-connected components, threshold value %g", - N, (double)thrval); - list_add_record(&ret->keylist, buf); - snprintf(buf, 80, "COMMENT (%g%% fromdata range%s)", fabs(threshold)*100., - (threshold < 0.) ? ", inverted" : ""); - list_add_record(&ret->keylist, buf); - return ret; -} -#endif /* * <=================== CONNECTED COMPONENTS LABELING =================== */ diff --git a/LocCorr/binmorph.h b/LocCorr/binmorph.h index 933fae0..7902dc3 100644 --- a/LocCorr/binmorph.h +++ b/LocCorr/binmorph.h @@ -60,26 +60,12 @@ uint8_t *filter4(uint8_t *image, int W, int H); uint8_t *filter8(uint8_t *image, int W, int H); size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC); -size_t *cclabel8(uint8_t *Img, int W, int H, size_t *Nobj); #if 0 +size_t *cclabel8(uint8_t *Img, int W, int H, size_t *Nobj); // logical operations uint8_t *imand(uint8_t *im1, uint8_t *im2, int W, int H); uint8_t *substim(uint8_t *im1, uint8_t *im2, int W, int H); -/* -// conncomp -// this is a box structure containing one object; data is aligned by original image bytes! -typedef struct { - uint8_t *data; // pattern data in "packed" format - int x, // x coordinate of LU-pixel of box in "unpacked" image (by pixels) - y, // y -//- - x_0; // x coordinate in "packed" image (morph operations should work with it) - size_t N;// number of component, starting from 1 -} CCbox; -*/ - -IMAGE *cclabel4(IMAGE *I, double threshold, size_t *Nobj); -IMAGE *cclabel8(IMAGE *I, double threshold, size_t *Nobj); #endif #endif // BINMORPH_H__ diff --git a/LocCorr/cameracapture.c b/LocCorr/cameracapture.c index 0cf5cab..b545486 100644 --- a/LocCorr/cameracapture.c +++ b/LocCorr/cameracapture.c @@ -20,10 +20,10 @@ #include #include #include -#include #include "cmdlnopts.h" #include "config.h" +#include "debug.h" #include "fits.h" #include "grasshopper.h" #include "imagefile.h" @@ -132,31 +132,19 @@ static void recalcexp(Image *I){ exptime = theconf.maxexp; return; } - if(I->minval < 0. || I->maxval > 255.1){ - DBG("Bad image data: min=%g, max=%g", I->minval, I->maxval); + size_t *histogram = get_histogram(I); + if(!histogram){ + WARNX("Can't calculate histogram"); return; } - int wh = I->width * I->height; - int histogram[256] = {0}; - // algorythm works only with 8bit images! - #pragma omp parallel - { - int histogram_private[256] = {0}; - #pragma omp for nowait - for(int i = 0; i < wh; ++i){ - ++histogram_private[(int)I->data[i]]; - } - #pragma omp critical - { - for(int i=0; i<256; ++i) histogram[i] += histogram_private[i]; - } - } - int idx100, sum100 = 0; + int idx100; + size_t sum100 = 0; for(idx100 = 255; idx100 >= 0; --idx100){ sum100 += histogram[idx100]; if(sum100 > 100) break; } - DBG("Sum100=%d, idx100=%d", sum100, idx100); + FREE(histogram); + DBG("Sum100=%zd, idx100=%d", sum100, idx100); if(idx100 > 230 && idx100 < 253) return; // good values if(idx100 > 253){ // exposure too long calcexpgain(0.7*exptime); @@ -248,13 +236,25 @@ int camcapture(void (*process)(Image*)){ FREE(oIma->data); FREE(oIma); } + if(oIma){ + FREE(oIma->data); + FREE(oIma); + } camdisconnect(); DBG("CAMCAPTURE: out"); return 1; } -// return JSON with image status +/** + * @brief camstatus - return JSON with image status + * @param messageid - value of "messageid" + * @param buf - buffer for string + * @param buflen - length of `buf` + * @return buf + */ char *camstatus(const char *messageid, char *buf, int buflen){ + if(!buf || buflen < 2) return NULL; + if(!messageid) messageid = "unknown"; static char *impath = NULL; if(!impath){ if(!(impath = realpath(GP->outputjpg, impath))){ @@ -263,9 +263,13 @@ char *camstatus(const char *messageid, char *buf, int buflen){ } DBG("path: %s", impath); } + float xc, yc; + getcenter(&xc, &yc); snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"%sconnected\", \"impath\": \"%s\", \"imctr\": %llu, " - "\"fps\": %.3f, \"expmethod\": \"%s\", \"exposition\": %g, \"gain\": %g, \"brightness\": %g }\n", + "\"fps\": %.3f, \"expmethod\": \"%s\", \"exposition\": %g, \"gain\": %g, \"brightness\": %g, " + "\"xcenter\": %.1f, \"ycenter\": %.1f }\n", MESSAGEID, messageid, connected ? "" : "dis", impath, ImNumber, getFramesPerS(), - (theconf.expmethod == EXPAUTO) ? "auto" : "manual", exptime, gain, brightness); + (theconf.expmethod == EXPAUTO) ? "auto" : "manual", exptime, gain, brightness, + xc, yc); return buf; } diff --git a/LocCorr/cameracapture.h b/LocCorr/cameracapture.h index f58cd37..ae02b46 100644 --- a/LocCorr/cameracapture.h +++ b/LocCorr/cameracapture.h @@ -15,11 +15,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #pragma once #ifndef CAMERACAPTURE_H__ #define CAMERACAPTURE_H__ -#include "fits.h" // Image* + +#include "imagefile.h" // Image + // format of single frame typedef struct{ diff --git a/LocCorr/cmdlnopts.c b/LocCorr/cmdlnopts.c index 4a1c276..ea43f1c 100644 --- a/LocCorr/cmdlnopts.c +++ b/LocCorr/cmdlnopts.c @@ -23,10 +23,10 @@ #include #include #include -#include #include "cmdlnopts.h" #include "config.h" +#include "debug.h" #include "improc.h" /* @@ -69,7 +69,7 @@ static myoption cmdlnopts[] = { {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), _("file to save logs (default: none)")}, {"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")}, {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verb), _("increase verbosity level of log file (each -v increased by 1)")}, - {"input", NEED_ARG, NULL, 'i', arg_string, APTR(&G.inputname), _("file or directory name for monitoring (or grasshopper for capturing)")}, + {"input", NEED_ARG, NULL, 'i', arg_string, APTR(&G.inputname), _("file or directory name for monitoring (or grasshopper/basler for capturing)")}, {"blackp", NEED_ARG, NULL, 'b', arg_double, APTR(&G.throwpart), _("fraction of black pixels to throw away when make histogram eq")}, // {"radius", NEED_ARG, NULL, 'r', arg_int, APTR(&G.medradius), _("radius of median filter (r=1 -> 3x3, r=2 -> 5x5 etc.)")}, {"equalize", NO_ARGS, NULL, 'e', arg_int, APTR(&G.equalize), _("make historam equalization of saved jpeg")}, diff --git a/LocCorr/config.c b/LocCorr/config.c index 7abeccc..7576bcd 100644 --- a/LocCorr/config.c +++ b/LocCorr/config.c @@ -19,10 +19,10 @@ #include #include #include -#include #include "cmdlnopts.h" #include "config.h" +#include "debug.h" static char *conffile = NULL; // configuration file name @@ -192,12 +192,12 @@ static char *read_key(FILE *file, char value[128]){ char *line = NULL; size_t n = 0; int got = getline(&line, &n, file); + if(!line) return NULL; if(got < 0){ - FREE(line); + free(line); return NULL; } char *kv = get_keyval(line, value); - FREE(line); return kv; } @@ -267,7 +267,7 @@ confparam *chk_keyval(const char *key, const char *val, key_value *result){ */ int chkconfig(const char *confname){ DBG("Config name: %s", confname); - FREE(conffile); + if(conffile){ free(conffile); conffile = NULL; } conffile = strdup(confname); FILE *f = fopen(confname, "r"); int ret = TRUE; @@ -283,7 +283,8 @@ int chkconfig(const char *confname){ } while((key = read_key(f, val))){ if(*key == '#'){ - FREE(key); + free(key); + key = NULL; continue; // comment } //DBG("key: %s", key); @@ -291,7 +292,8 @@ int chkconfig(const char *confname){ par = chk_keyval(key, val, &kv); if(!par){ WARNX("Parameter '%s' is wrong or out of range", key); - FREE(key); + free(key); + key = NULL; continue; } switch(par->type){ @@ -303,7 +305,8 @@ int chkconfig(const char *confname){ break; } ++par->got; - FREE(key); + free(key); + key = NULL; } fclose(f); int found = 0; @@ -321,34 +324,6 @@ int chkconfig(const char *confname){ } ++found; ++par; } -#if 0 - int Nchecked = 0; - if(theconf.maxUsteps >= MINSTEPS && theconf.maxUsteps <= MAXSTEPS) ++Nchecked; - if(theconf.maxVsteps >= MINSTEPS && theconf.maxVsteps <= MAXSTEPS) ++Nchecked; - if(theconf.cosXU >= -1. && theconf.cosXU <= 1.) ++Nchecked; - if(theconf.sinXU >= -1. && theconf.sinXU <= 1.) ++Nchecked; - if(theconf.cosXV >= -1. && theconf.cosXV <= 1.) ++Nchecked; - if(theconf.sinXV >= -1. && theconf.sinXV <= 1.) ++Nchecked; - if(theconf.KU >= COEFMIN && theconf.KU <= COEFMAX) ++Nchecked; - if(theconf.KV >= COEFMIN && theconf.KV <= COEFMAX) ++Nchecked; - if(theconf.maxarea <= MAXAREA && theconf.maxarea >= MINAREA) ++Nchecked; - if(theconf.minarea <= MAXAREA && theconf.minarea >= MINAREA) ++Nchecked; - if(theconf.Nerosions > 0 && theconf.Nerosions <= MAX_NEROS) ++Nchecked; - if(theconf.Ndilations > 0 && theconf.Ndilations <= MAX_NDILAT) ++Nchecked; - if(theconf.xtarget > 1.) ++Nchecked; - if(theconf.ytarget > 1.) ++Nchecked; - if(theconf.throwpart > -DBL_EPSILON && theconf.throwpart < MAX_THROWPART+DBL_EPSILON) ++Nchecked; - if(theconf.xoff > 0 && theconf.xoff < MAX_OFFSET) ++Nchecked; - if(theconf.yoff > 0 && theconf.yoff < MAX_OFFSET) ++Nchecked; - if(theconf.width > 0 && theconf.width < MAX_OFFSET) ++Nchecked; - if(theconf.height > 0 && theconf.height < MAX_OFFSET) ++Nchecked; - if(theconf.minexp > 0. && theconf.minexp < EXPOS_MAX) ++Nchecked; - if(theconf.maxexp > theconf.minexp) ++Nchecked; - if(theconf.equalize > -1) ++Nchecked; - if(theconf.intensthres > DBL_EPSILON && theconf.intensthres < 1.) ++Nchecked; - if(theconf.naverage > 1 && theconf.naverage <= NAVER_MAX) ++Nchecked; - if(theconf.stpserverport > 0 && theconf.stpserverport < 65536) ++Nchecked; -#endif DBG("chkconfig(): found %d", found); return ret; } diff --git a/LocCorr/config.h b/LocCorr/config.h index cc03ecb..b1a9efa 100644 --- a/LocCorr/config.h +++ b/LocCorr/config.h @@ -42,12 +42,12 @@ #define BRIGHT_MIN (0.) #define BRIGHT_MAX (10.) // max average images counter -#define NAVER_MAX (50) +#define NAVER_MAX (25) // coefficients to convert dx,dy to du,dv #define KUVMIN (-5000.) #define KUVMAX (5000.) // default coefficient for corrections (move to Kdu, Kdv instead of du, dv) -#define KCORR (0.97) +#define KCORR (0.90) // min/max median seed #define MIN_MEDIAN_SEED (1) #define MAX_MEDIAN_SEED (7) diff --git a/LocCorr/debug.c b/LocCorr/debug.c new file mode 100644 index 0000000..6e813f1 --- /dev/null +++ b/LocCorr/debug.c @@ -0,0 +1,57 @@ +/* + * This file is part of the loccorr project. + * Copyright 2021 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef EBUG + +#include +#include + +#include "debug.h" + +#define DEBUGLOG "DEBUG.log" + +sl_log *debuglog = NULL; + +void makedebuglog(){ + unlink(DEBUGLOG); + debuglog = sl_createlog(DEBUGLOG, LOGLEVEL_ANY, 0); +} + +/** + * @brief my_malloc - memory allocator for logger + * @param N - number of elements to allocate + * @param S - size of single element (typically sizeof) + * @return pointer to allocated memory area + */ +void *my_malloc(size_t N, size_t S){ + size_t NS = N*S + sizeof(size_t); + sl_putlogt(0, debuglog, LOGLEVEL_ERR, "ALLOCSZ(%zd)", N*S); + void *p = malloc(NS); + if(!p) ERR("malloc"); + memset(p, 0, NS); + *((size_t*)p) = N*S; + return (p + sizeof(size_t)); +} + +void my_free(void *ptr){ + void *orig = ptr - sizeof(size_t); + sl_putlogt(0, debuglog, LOGLEVEL_ERR, "FREESZ(%zd)", *(size_t*)orig); + free(orig); +} + +#endif diff --git a/LocCorr/debug.h b/LocCorr/debug.h new file mode 100644 index 0000000..a5ab864 --- /dev/null +++ b/LocCorr/debug.h @@ -0,0 +1,53 @@ +/* + * This file is part of the loccorr project. + * Copyright 2021 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#ifndef DEBUG_H__ +#define DEBUG_H__ + +#include + +#ifdef EBUG + +extern sl_log *debuglog; +void makedebuglog(); +void *my_malloc(size_t N, size_t S); +void my_free(void *ptr); + +#undef FNAME +#undef ALLOC +#undef MALLOC +#undef FREE +#define _LOG(...) do{if(!debuglog) makedebuglog(); sl_putlogt(1, debuglog, LOGLEVEL_ERR, __VA_ARGS__);}while(0) +#define DBGLOG(...) do{_LOG("%s (%s, line %d)", __func__, __FILE__, __LINE__); \ + sl_putlogt(0, debuglog, LOGLEVEL_ERR, __VA_ARGS__);}while(0) +#define FNAME() _LOG("%s (%s, line %d)", __func__, __FILE__, __LINE__) + +#define _str(x) #x +#define ALLOC(type, var, size) DBGLOG("%s *%s = ALLOC(%d)", _str(type), _str(var), size*sizeof(type)); \ + type * var = ((type *)my_malloc(size, sizeof(type))) +#define MALLOC(type, size) ((type *)my_malloc(size, sizeof(type))); DBGLOG("ALLOC()") +#define FREE(ptr) do{if(ptr){DBGLOG("FREE(%s)", _str(ptr)); my_free(ptr); ptr = NULL;}}while(0); + +#else + +#define DBGLOG(...) + +#endif + + +#endif // DEBUG_H__ diff --git a/LocCorr/dilation.h b/LocCorr/dilation.h index 7fdba20..3326980 100644 --- a/LocCorr/dilation.h +++ b/LocCorr/dilation.h @@ -33,6 +33,12 @@ OMP_FOR() for(int y = 1; y < h; y++) #endif { +#ifdef IM_UP + int y = 0; +#endif +#ifdef IM_DOWN + int y = h; +#endif uint8_t *iptr = &image[W0*y]; uint8_t *optr = &ret[W0*y]; uint8_t p = DIL[*iptr] diff --git a/LocCorr/draw.c b/LocCorr/draw.c index ce95a20..a9e2397 100644 --- a/LocCorr/draw.c +++ b/LocCorr/draw.c @@ -16,11 +16,11 @@ * along with this program. If not, see . */ -// simplest interface to draw lines & ellipsis +// simplest interface to draw lines & ellipses +#include "debug.h" #include "draw.h" #include "fits.h" -#include // base colors: const uint8_t @@ -46,13 +46,35 @@ void Pattern_free(Pattern **p){ Pattern *Pattern_cross(int h, int w){ int s = h*w, hmid = h/2, wmid = w/2; uint8_t *data = MALLOC(uint8_t, s); + Pattern *p = MALLOC(Pattern, 1); + p->data = data; + p->h = h; p->w = w; uint8_t *ptr = &data[wmid]; for(int y = 0; y < h; ++y, ptr += w) *ptr = 255; ptr = &data[hmid*w]; for(int x = 0; x < w; ++x, ++ptr) *ptr = 255; + return p; +} + +// complicated cross +Pattern *Pattern_xcross(int h, int w){ + int s = h*w, hmid = h/2, wmid = w/2; + uint8_t *data = MALLOC(uint8_t, s); Pattern *p = MALLOC(Pattern, 1); p->data = data; p->h = h; p->w = w; + data[hmid*w + wmid] = 255; // point @ center + if(h < 7 || w < 7) return p; + int idxy1 = (hmid-3)*w, idxy2 = (hmid+3)*w; + int idxx1 = wmid-3, idxx2 = wmid+3; + for(int i = 0; i < wmid - 3; ++i){ + data[idxy1+i] = data[idxy1+w-1-i] = 255; + data[idxy2+i] = data[idxy2+w-1-i] = 255; + } + for(int i = 0; i < hmid - 3; ++i){ + data[idxx1 + i*w] = data[idxx1 + (h-1-i)*w] = 255; + data[idxx2 + i*w] = data[idxx2 + (h-1-i)*w] = 255; + } return p; } @@ -63,7 +85,8 @@ Pattern *Pattern_cross(int h, int w){ * @param xc, yc - coordinates of pattern center @ image * @param colr - color to draw pattern (when opaque == 255) */ -void Pattern_draw3(Img3 *img, Pattern *p, int xc, int yc, const uint8_t colr[]){ +void Pattern_draw3(Img3 *img, const Pattern *p, int xc, int yc, const uint8_t colr[]){ + if(!img || !p) return; int xul = xc - p->w/2, yul = yc - p->h/2; int xdr = xul+p->w-1, ydr = yul+p->h-1; int R = img->w, D = img->h; // right and down border coordinates + 1 @@ -96,7 +119,7 @@ void Pattern_draw3(Img3 *img, Pattern *p, int xc, int yc, const uint8_t colr[]){ uint8_t *in = &p->data[(iylow+y-oylow)*p->w + ixlow]; // opaque component uint8_t *out = &img->data[(y*img->w + oxlow)*3]; // 3-colours for(int x = oxlow; x < oxhigh; ++x, ++in, out += 3){ - float opaque = *in/255.; + float opaque = ((float)*in)/255.; for(int c = 0; c < 3; ++c){ out[c] = (uint8_t)(colr[c] * opaque + out[c]*(1.-opaque)); } diff --git a/LocCorr/draw.h b/LocCorr/draw.h index cbea4e7..7ee43f5 100644 --- a/LocCorr/draw.h +++ b/LocCorr/draw.h @@ -28,17 +28,6 @@ typedef struct{ int h; // height } Img3; -/* -// box (coordinates from upper left corner) -typedef struct{ - int xul; // coordinates of upper left box corner - int yul; - int w; // width and height - int h; - uint8_t pattern[3]; // pattern for figure filling -} BBox; -*/ - // opaque pattern for drawing typedef struct{ uint8_t *data; @@ -50,7 +39,8 @@ typedef struct{ extern const uint8_t C_R[], C_G[], C_B[], C_K[], C_W[]; void Pattern_free(Pattern **p); -void Pattern_draw3(Img3 *img, Pattern *p, int xc, int yc, const uint8_t colr[]); +void Pattern_draw3(Img3 *img, const Pattern *p, int xc, int yc, const uint8_t colr[]); Pattern *Pattern_cross(int h, int w); +Pattern *Pattern_xcross(int h, int w); #endif // DRAW_H__ diff --git a/LocCorr/ec_filter.h b/LocCorr/ec_filter.h index c95adec..b110f92 100644 --- a/LocCorr/ec_filter.h +++ b/LocCorr/ec_filter.h @@ -23,6 +23,12 @@ OMP_FOR() for(int y = 1; y < h; y++) #endif { +#ifdef IM_UP + int y = 0; +#endif +#ifdef IM_DOWN + int y = h; +#endif uint8_t *iptr = &image[W0*y]; uint8_t *optr = &ret[W0*y]; // x=0 diff --git a/LocCorr/fc_filter.h b/LocCorr/fc_filter.h index 5d30d3c..4a97789 100644 --- a/LocCorr/fc_filter.h +++ b/LocCorr/fc_filter.h @@ -23,6 +23,12 @@ OMP_FOR() for(int y = 1; y < h; y++) #endif { +#ifdef IM_UP + int y = 0; +#endif +#ifdef IM_DOWN + int y = h; +#endif uint8_t *iptr = &image[W0*y]; uint8_t *optr = &ret[W0*y]; // x=0 diff --git a/LocCorr/fits.c b/LocCorr/fits.c index 3e06ec7..154564a 100644 --- a/LocCorr/fits.c +++ b/LocCorr/fits.c @@ -18,9 +18,9 @@ #include #include #include -#include #include +#include "debug.h" #include "fits.h" static int fitsstatus = 0; @@ -56,12 +56,40 @@ void Image_free(Image **img){ FREE(*img); } +// I->data should be allocated!!! +static inline void convflt2ima(float *f, Image *I){ + if(!I || !I->data || !f) return; + float min = *f, max = min; + int wh = I->height * I->width; + #pragma omp parallel shared(min, max) + { + float min_p = min, max_p = min; + #pragma omp for nowait + for(int i = 0; i < wh; ++i){ + if(f[i] < min_p) min_p = f[i]; + else if(f[i] > max_p) max_p = f[i]; + } + #pragma omp critical + { + if(min > min_p) min = min_p; + if(max < max_p) max = max_p; + } + } + float W = 255./(max - min); + #pragma omp for + for(int i = 0; i < wh; ++i){ + I->data[i] = (Imtype)(W*(f[i] - min)); + } + I->maxval = 255; + I->minval = 0; +} + bool FITS_read(const char *filename, Image **fits){ FNAME(); bool ret = TRUE; fitsfile *fp; int i, j, hdunum, hdutype, nkeys, keypos; - int naxis; + int naxis, dtype; long naxes[2]; char card[FLEN_CARD]; Image *img = MALLOC(Image, 1); @@ -75,7 +103,7 @@ bool FITS_read(const char *filename, Image **fits){ goto returning; } // get image dimensions - TRYFITS(fits_get_img_param, fp, 2, &img->dtype, &naxis, naxes); + TRYFITS(fits_get_img_param, fp, 2, &dtype, &naxis, naxes); DBG("Image have %d axis", naxis); if(naxis > 2){ WARNX(_("Images with > 2 dimensions are not supported")); @@ -84,7 +112,7 @@ bool FITS_read(const char *filename, Image **fits){ } img->width = naxes[0]; img->height = naxes[1]; - DBG("got image %ldx%ld pix, bitpix=%d", naxes[0], naxes[1], img->dtype); + DBG("got image %ldx%ld pix, bitpix=%d", naxes[0], naxes[1], dtype); // loop through all HDUs for(i = 1; !(fits_movabs_hdu(fp, i, &hdutype, &fitsstatus)); ++i){ TRYFITS(fits_get_hdrpos, fp, &nkeys, &keypos); @@ -114,25 +142,19 @@ bool FITS_read(const char *filename, Image **fits){ } size_t sz = naxes[0] * naxes[1]; img->data = MALLOC(Imtype, sz); + float *targ = MALLOC(float, sz); int stat = 0; - TRYFITS(fits_read_img, fp, FITSDATATYPE, 1, sz, NULL, img->data, &stat); - Imtype *d = img->data, min = *d, max = *d; - for(size_t x = 0; x < sz; ++x){ - if(d[x] > max) max = d[x]; - else if(d[x] < min) min = d[x]; - } - img->maxval = max; - img->minval = min; - DBG("FITS stat: min=%g, max=%g", min, max); + TRYFITS(fits_read_img, fp, TFLOAT, 1, sz, NULL, targ, &stat); if(stat) WARNX(_("Found %d pixels with undefined value"), stat); + convflt2ima(targ, img); + FREE(targ); DBG("ready"); returning: FITSFUN(fits_close_file, fp); - if(!ret){ + if(!ret || !fits){ Image_free(&img); - } - if(fits) *fits = img; + }else *fits = img; return ret; } @@ -143,63 +165,8 @@ bool FITS_write(const char *filename, const Image *fits){ fitsfile *fp; TRYFITS(fits_create_file, &fp, filename); - TRYFITS(fits_create_img, fp, fits->dtype, 2, naxes); - Imtype *outp = fits->data; - bool need2free = FALSE; - if(fits->dtype > 0){ // convert floating data into integer - Imtype maxval; - Imtype minval; - switch(fits->dtype){ - case SBYTE_IMG: // there's a bug in cfitsio, it can't save float->sbyte - maxval = (Imtype)INT8_MAX; - minval = (Imtype)INT8_MIN; - break; - case SHORT_IMG: - maxval = (Imtype)INT16_MAX; - minval = (Imtype)INT16_MIN; - break; - case USHORT_IMG: - maxval = (Imtype)UINT16_MAX; - minval = (Imtype)0; - break; - case LONG_IMG: - maxval = (Imtype)INT32_MAX; - minval = (Imtype)INT32_MIN; - break; - case ULONG_IMG: - maxval = (Imtype)UINT32_MAX; - minval = (Imtype)0; - break; - case ULONGLONG_IMG: - maxval = (Imtype)UINT64_MAX; - minval = (Imtype)0; - break; - case LONGLONG_IMG: - maxval = (Imtype)INT64_MAX; - minval = (Imtype)INT64_MIN; - break; - case BYTE_IMG: - default: // byte - maxval = (Imtype)UINT8_MAX; - minval = (Imtype)0; - } - DBG("maxval = %g, minval = %g", maxval, minval); - int w = fits->width, h = fits->height; - Imtype min = fits->minval, max = fits->maxval, W = (maxval - minval)/(max - min); - outp = MALLOC(Imtype, w*h); - OMP_FOR() - for(int y = 0; y < h; ++y){ - Imtype *o = &outp[y*w], *i = &fits->data[y*w]; - for(int x = 0; x < w; ++x, ++o, ++i){ - *o = W*((*i) - min) + minval; - //if(*o < minval || *o > maxval) red("o: %g\n", *o); - //if(*o < minval) *o = minval; - //else if(*o > maxval) *o = maxval; - } - } - need2free = TRUE; - DBG("converted"); - } + TRYFITS(fits_create_img, fp, SHORT_IMG, 2, naxes); + if(keys){ // there's keys size_t i; char **records = fits->keylist; @@ -216,8 +183,7 @@ bool FITS_write(const char *filename, const Image *fits){ } FITSFUN(fits_write_record, fp, "COMMENT modified by loccorr"); fitsstatus = 0; - fits_write_img(fp, FITSDATATYPE, 1, sz, outp, &fitsstatus); - if(need2free) FREE(outp); + fits_write_img(fp, TBYTE, 1, sz, fits->data, &fitsstatus); if(fitsstatus){ fits_report_error(stderr, fitsstatus); return FALSE; diff --git a/LocCorr/fits.h b/LocCorr/fits.h index 865c49d..bd16dd6 100644 --- a/LocCorr/fits.h +++ b/LocCorr/fits.h @@ -22,31 +22,9 @@ #include #include -#include #include -#define Stringify(x) #x -#define OMP_FOR(x) _Pragma(Stringify(omp parallel for x)) - - -typedef float Imtype; // maybe float or double only -// this is TFLOAT or TDOUBLE depending on Imtype -#define FITSDATATYPE TFLOAT -/* -typedef double Imtype; -#define FITSDATATYPE TDOUBLE -*/ - -typedef struct{ - int width; // width - int height; // height - int dtype; // data type for image storage - Imtype *data; // picture data - Imtype minval; // extremal data values - Imtype maxval; - char **keylist; // list of options for each key - size_t keynum; // full number of keys (size of *keylist) -} Image; +#include "imagefile.h" void Image_free(Image **ima); bool FITS_read(const char *filename, Image **fits); diff --git a/LocCorr/grasshopper.c b/LocCorr/grasshopper.c index 70dfdd3..c9aac7a 100644 --- a/LocCorr/grasshopper.c +++ b/LocCorr/grasshopper.c @@ -22,9 +22,9 @@ #include #include #include -#include #include "config.h" +#include "debug.h" #include "grasshopper.h" #include "imagefile.h" @@ -32,8 +32,12 @@ static fc2Context context; static fc2PGRGuid guid; static fc2Error err = FC2_ERROR_OK; +#ifndef Stringify +#define Stringify(x) #x +#endif + #define FC2FN(fn, ...) do{err = FC2_ERROR_OK; if(FC2_ERROR_OK != (err=fn(context __VA_OPT__(,) __VA_ARGS__))){ \ - WARNX(#fn "(): %s", fc2ErrorToDescription(err)); return FALSE;}}while(0) + WARNX(Stringify(fn) "(): %s", fc2ErrorToDescription(err)); return FALSE;}}while(0) static void disconnect(){ fc2DestroyContext(context); @@ -146,6 +150,7 @@ static int geometrylimits(frameformat *max, frameformat *step){ } static int getformat(frameformat *fmt){ + if(!fmt) return FALSE; unsigned int packsz; float pc; fc2Format7ImageSettings f7; FC2FN(fc2GetFormat7Configuration, &f7, &packsz, &pc); @@ -155,7 +160,7 @@ static int getformat(frameformat *fmt){ } static int changeformat(frameformat *fmt){ - FNAME(); + if(!fmt) return FALSE; BOOL b; fc2Format7ImageSettings f7; f7.mode = FC2_MODE_0; @@ -203,7 +208,7 @@ static int connect(){ } static int GrabImage(fc2Image *convertedImage){ - //FNAME(); + if(!convertedImage) return FALSE; int ret = FALSE; fc2Image rawImage; // start capture @@ -211,7 +216,8 @@ static int GrabImage(fc2Image *convertedImage){ err = fc2CreateImage(&rawImage); if(err != FC2_ERROR_OK){ WARNX("Error in fc2CreateImage: %s", fc2ErrorToDescription(err)); - goto rtn; + fc2StopCapture(context); + return FALSE; } // Retrieve the image err = fc2RetrieveBuffer(context, &rawImage); diff --git a/LocCorr/imagefile.c b/LocCorr/imagefile.c index 002690f..63d00d6 100644 --- a/LocCorr/imagefile.c +++ b/LocCorr/imagefile.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -31,7 +30,9 @@ #include "cameracapture.h" #include "cmdlnopts.h" #include "config.h" +#include "debug.h" #include "draw.h" +#include "fits.h" #include "grasshopper.h" #include "imagefile.h" #include "median.h" @@ -68,6 +69,11 @@ static char *hexdmp(const char sig[8]){ } #endif +/** + * @brief imtype - check image type of given file + * @param f - opened image file structure + * @return image type or T_WRONG + */ static InputType imtype(FILE *f){ char signature[8]; int x = fread(signature, 1, 7, f); @@ -122,37 +128,22 @@ InputType chkinput(const char *name){ return tp; } -Image *u8toImage(uint8_t *data, int width, int height, int stride){ +/** + * @brief u8toImage - convert uint8_t data to Image structure (flipping upside down for FITS coordinates) + * @param data - original image data + * @param width - image width + * @param height - image height + * @param stride - image width with alignment + * @return Image structure (fully allocated, you can FREE(data) after it) + */ +Image *u8toImage(const uint8_t *data, int width, int height, int stride){ FNAME(); - Image *outp = MALLOC(Image, 1); - outp->width = width; - outp->height = height; - outp->dtype = FLOAT_IMG; -/* - int histogram[256] = {0}; - int wh = width*height; - #pragma omp parallel - { - int histogram_private[256] = {0}; - #pragma omp for nowait - for(int i = 0; i < wh; ++i){ - ++histogram_private[data[i]]; - } - #pragma omp critical - { - for(int i=0; i<256; ++i) histogram[i] += histogram_private[i]; - } - } - red("HISTO:\n"); - for(int i = 0; i < 256; ++i) printf("%d:\t%d\n", i, histogram[i]); -*/ - - outp->data = MALLOC(Imtype, width*height); + Image *outp = Image_new(width, height); // flip image updown for FITS coordinate system OMP_FOR() for(int y = 0; y < height; ++y){ Imtype *Out = &outp->data[(height-1-y)*width]; - uint8_t *In = &data[y*stride]; + const uint8_t *In = &data[y*stride]; for(int x = 0; x < width; ++x){ *Out++ = (Imtype)(*In++); } @@ -161,15 +152,21 @@ Image *u8toImage(uint8_t *data, int width, int height, int stride){ return outp; } -// load other image file -static Image *im_load(const char *name){ +/** + * @brief im_load - load image file + * @param name - filename + * @return Image structure or NULL + */ +static inline Image *im_load(const char *name){ int width, height, channels; uint8_t *img = stbi_load(name, &width, &height, &channels, 1); if(!img){ WARNX("Error in loading the image %s\n", name); return NULL; } - return u8toImage(img, width, height, width); + Image *I = u8toImage(img, width, height, width); + free(img); + return I; } /** @@ -199,6 +196,7 @@ Image *Image_read(const char *name){ * @return data allocated here */ Image *Image_new(int w, int h){ + if(w < 1 || h < 1) return NULL; Image *outp = MALLOC(Image, 1); outp->width = w; outp->height = h; @@ -213,24 +211,99 @@ Image *Image_new(int w, int h){ */ Image *Image_sim(const Image *i){ if(!i) return NULL; - if((i->width * i->height) < 1) return NULL; Image *outp = Image_new(i->width, i->height); - outp->dtype = i->dtype; return outp; } /** - * @brief linear - linear transform (mirror image upside down!) + * @brief get_histogram - calculate image histogram + * @param I - orig + * @return + */ +size_t *get_histogram(const Image *I){ + if(!I || !I->data) return NULL; + size_t *histogram = MALLOC(size_t, 256); + int wh = I->width * I->height; +#pragma omp parallel +{ + size_t histogram_private[256] = {0}; + #pragma omp for nowait + for(int i = 0; i < wh; ++i){ + ++histogram_private[I->data[i]]; + } + #pragma omp critical + { + for(int i = 0; i < 256; ++i) histogram[i] += histogram_private[i]; + } +} + return histogram; +} + + +/** + * @brief calc_background - Simple background calculation by histogram + * @param img (i) - input image (here will be modified its top2proc field) + * @param bk (o) - background value + * @return 0 if error + */ +int calc_background(const Image *img, Imtype *bk){ + if(!img || !img->data || !bk) return FALSE; + if(img->maxval == img->minval){ + WARNX("Zero or overilluminated image!"); + return FALSE; + } + if(theconf.fixedbkg){ + if(theconf.fixedbkg > img->minval){ + WARNX("Image values too small"); + return FALSE; + } + *bk = theconf.fixedbkg; + return TRUE; + } + size_t *histogram = get_histogram(img); + + size_t modeidx = 0, modeval = 0; + for(int i = 0; i < 256; ++i) + if(modeval < histogram[i]){ + modeval = histogram[i]; + modeidx = i; + } + //DBG("Mode=%g @ idx%d (N=%d)", ((Imtype)modeidx / 255.)*ampl, modeidx, modeval); + ssize_t diff2[256] = {0}; + for(int i = 2; i < 254; ++i) diff2[i] = (histogram[i+2]+histogram[i-2]-2*histogram[i])/4; + //green("HISTO:\n"); + //for(int i = 0; i < 256; ++i) printf("%d:\t%d\t%d\n", i, histogram[i], diff2[i]); + FREE(histogram); + if(modeidx < 2) modeidx = 2; + if(modeidx > 253){ + WARNX("Overilluminated image"); + return FALSE; // very bad image: overilluminated + } + size_t borderidx = modeidx; + for(int i = modeidx; i < 254; ++i){ // search bend-point by second derivate + if(diff2[i] <= 0 && diff2[i+1] <= 0){ + borderidx = i; break; + } + } + //DBG("borderidx=%d -> %d", borderidx, (borderidx+modeidx)/2); + //*bk = (borderidx + modeidx) / 2; + *bk = borderidx; + return TRUE; +} + + +/** + * @brief linear - linear transform for preparing file to save as JPEG or other type (mirror image upside down!) * @param I - input image * @param nchannels - 1 or 3 colour channels * @return allocated here image for jpeg/png storing */ uint8_t *linear(const Image *I, int nchannels){ // only 1 and 3 channels supported! - if(nchannels != 1 && nchannels != 3) return NULL; + if(!I || !I->data || (nchannels != 1 && nchannels != 3)) return NULL; int width = I->width, height = I->height; size_t stride = width*nchannels, S = height*stride; uint8_t *outp = MALLOC(uint8_t, S); - Imtype min = I->minval, max = I->maxval, W = 255./(max - min); + float min = (float)I->minval, max = (float)I->maxval, W = 255./(max - min); //DBG("make linear transform %dx%d, %d channels", I->width, I->height, nchannels); if(nchannels == 3){ OMP_FOR() @@ -238,7 +311,7 @@ uint8_t *linear(const Image *I, int nchannels){ // only 1 and 3 channels support uint8_t *Out = &outp[(height-1-y)*stride]; Imtype *In = &I->data[y*width]; for(int x = 0; x < width; ++x){ - Out[0] = Out[1] = Out[2] = (uint8_t)(W*((*In++) - min)); + Out[0] = Out[1] = Out[2] = (uint8_t)(W*((float)(*In++) - min)); Out += 3; } } @@ -248,7 +321,7 @@ uint8_t *linear(const Image *I, int nchannels){ // only 1 and 3 channels support uint8_t *Out = &outp[(height-1-y)*width]; Imtype *In = &I->data[y*width]; for(int x = 0; x < width; ++x){ - *Out++ = (uint8_t)(W*((*In++) - min)); + *Out++ = (uint8_t)(W*((float)(*In++) - min)); } } } @@ -263,24 +336,19 @@ uint8_t *linear(const Image *I, int nchannels){ // only 1 and 3 channels support * @return allocated here image for jpeg/png storing */ uint8_t *equalize(const Image *I, int nchannels, double throwpart){ - if(nchannels != 1 && nchannels != 3) return NULL; + if(!I || !I->data || (nchannels != 1 && nchannels != 3)) return NULL; int width = I->width, height = I->height; size_t stride = width*nchannels, S = height*stride; - uint8_t *lin = linear(I, 1); - if(!lin) return NULL; + size_t *orig_histo = get_histogram(I); // original hystogram (linear) + if(!orig_histo) return NULL; uint8_t *outp = MALLOC(uint8_t, S); - int orig_hysto[256] = {0}; // original hystogram (linear) uint8_t eq_levls[256] = {0}; // levels to convert: newpix = eq_levls[oldpix] int s = width*height; - for(int i = 0; i < s; ++i){ - ++orig_hysto[lin[i]]; - } - - int Nblack = 0, bpart = (int)(throwpart * s); + int Nblack = 0, bpart = (int)(throwpart * (double)s); int startidx; // remove first part of black pixels for(startidx = 0; startidx < 256; ++startidx){ - Nblack += orig_hysto[startidx]; + Nblack += orig_histo[startidx]; if(Nblack >= bpart) break; } ++startidx; @@ -290,15 +358,9 @@ uint8_t *equalize(const Image *I, int nchannels, double throwpart){ if(Nwhite >= wpart) break; }*/ //DBG("Throw %d (real: %d black) pixels, startidx=%d", bpart, Nblack, startidx); -/* - double part = (double)(s + 1) / 256., N = 0.; - for(int i = 0; i < 256; ++i){ - N += orig_hysto[i]; - eq_levls[i] = (uint8_t)(N/part); - }*/ double part = (double)(s + 1. - Nblack) / 256., N = 0.; for(int i = startidx; i < 256; ++i){ - N += orig_hysto[i]; + N += orig_histo[i]; eq_levls[i] = (uint8_t)(N/part); } //for(int i = stopidx; i < 256; ++i) eq_levls[i] = 255; @@ -309,8 +371,8 @@ uint8_t *equalize(const Image *I, int nchannels, double throwpart){ if(nchannels == 3){ OMP_FOR() for(int y = 0; y < height; ++y){ - uint8_t *Out = &outp[y*stride]; - uint8_t *In = &lin[y*width]; + uint8_t *Out = &outp[(height-1-y)*stride]; + Imtype *In = &I->data[y*width]; for(int x = 0; x < width; ++x){ Out[0] = Out[1] = Out[2] = eq_levls[*In++]; Out += 3; @@ -319,14 +381,14 @@ uint8_t *equalize(const Image *I, int nchannels, double throwpart){ }else{ OMP_FOR() for(int y = 0; y < height; ++y){ - uint8_t *Out = &outp[y*width]; - uint8_t *In = &lin[y*width]; + uint8_t *Out = &outp[(height-1-y)*width]; + Imtype *In = &I->data[y*width]; for(int x = 0; x < width; ++x){ *Out++ = eq_levls[*In++]; } } } - FREE(lin); + FREE(orig_histo); return outp; } @@ -344,6 +406,7 @@ int Image_write_jpg(const Image *I, const char *name, int eq){ outp = equalize(I, 1, theconf.throwpart); else outp = linear(I, 1); + if(!outp) return 0; //DBG("Try to write %s", name); char *tmpnm = MALLOC(char, strlen(name) + 5); sprintf(tmpnm, "%s-tmp", name); @@ -372,8 +435,9 @@ void Image_minmax(Image *I){ int min_p = min, max_p = min; #pragma omp for nowait for(int i = 0; i < wh; ++i){ - if(I->data[i] < min_p) min_p = I->data[i]; - else if(I->data[i] > max_p) max_p = I->data[i]; + Imtype pixval = I->data[i]; + if(pixval < min_p) min_p = pixval; + else if(pixval > max_p) max_p = pixval; } #pragma omp critical { @@ -383,27 +447,26 @@ void Image_minmax(Image *I){ } I->maxval = max; I->minval = min; - DBG("Image_minmax(): Min=%g, Max=%g, time: %gms", min, max, (dtime()-t0)*1e3); + DBG("Image_minmax(): Min=%d, Max=%d, time: %gms", min, max, (dtime()-t0)*1e3); } /* * =================== CONVERT IMAGE TYPES ===================> */ -// convert binarized image into floating /** * @brief bin2Im - convert binarized image into floating * @param image - binarized image * @param W, H - its size (in pixels!) * @return Image structure */ -Image *bin2Im(uint8_t *image, int W, int H){ +Image *bin2Im(const uint8_t *image, int W, int H){ Image *ret = Image_new(W, H); int stride = (W + 7) / 8, s1 = (stride*8 == W) ? stride : stride - 1; OMP_FOR() for(int y = 0; y < H; y++){ Imtype *optr = &ret->data[y*W]; - uint8_t *iptr = &image[y*stride]; + const uint8_t *iptr = &image[y*stride]; for(int x = 0; x < s1; x++){ register uint8_t inp = *iptr++; for(int i = 0; i < 8; ++i){ @@ -412,20 +475,21 @@ Image *bin2Im(uint8_t *image, int W, int H){ } } int rest = W - s1*8; - register uint8_t inp = *iptr; - for(int i = 0; i < rest; ++i){ - *optr++ = (inp & 0x80) ? 1. : 0; - inp <<= 1; + if(rest){ + register uint8_t inp = *iptr; + for(int i = 0; i < rest; ++i){ + *optr++ = (inp & 0x80) ? 1. : 0; + inp <<= 1; + } } } - ret->dtype = BYTE_IMG; ret->minval = 0; ret->maxval = 1; return ret; } /** - * Convert floatpoint image into pseudo-packed (1 char == 8 pixels), all values > 0 will be 1, else - 0 + * Convert floatpoint image into pseudo-packed (1 char == 8 pixels), all values > bk will be 1, else - 0 * @param im (i) - image to convert * @param stride (o) - new width of image * @param bk - background level (all values < bk will be 0, other will be 1) @@ -438,46 +502,47 @@ uint8_t *Im2bin(const Image *im, Imtype bk){ int y, W0 = (W + 7) / 8, s1 = (W/8 == W0) ? W0 : W0 - 1; uint8_t *ret = MALLOC(uint8_t, W0 * H); OMP_FOR() - for(y = 0; y < H; y++){ + for(y = 0; y < H; ++y){ Imtype *iptr = &im->data[y*W]; uint8_t *optr = &ret[y*W0]; - register uint8_t o; for(int x = 0; x < s1; ++x){ - o = 0; + register uint8_t o = 0; for(int i = 0; i < 8; ++i){ o <<= 1; if(*iptr++ > bk) o |= 1; } *optr++ = o; } - int rest = 7 - (W - s1*8); - if(rest < 7){ - o = 0; - for(int x = 7; x > rest; --x){ - if(*iptr++ > 0.) o |= 1< bk) o |= 1; } - *optr = o; - //*optr = o | 1<data[y*W]; - size_t *iptr = &image[y*W]; + const size_t *iptr = &image[y*W]; for(int x = 0; x < W; ++x){ *optr++ = (Imtype)*iptr++; } } - ret->dtype = FLOAT_IMG; Image_minmax(ret); return ret; } +#endif /** * Convert "packed" image into size_t array for conncomp procedure @@ -485,13 +550,13 @@ Image *ST2Im(size_t *image, int W, int H){ * @param W, H - size of image in pixels * @return allocated memory area with copy of an image */ -size_t *bin2ST(uint8_t *image, int W, int H){ +size_t *bin2ST(const uint8_t *image, int W, int H){ size_t *ret = MALLOC(size_t, W * H); int W0 = (W + 7) / 8, s1 = W0 - 1; OMP_FOR() for(int y = 0; y < H; y++){ size_t *optr = &ret[y*W]; - uint8_t *iptr = &image[y*W0]; + const uint8_t *iptr = &image[y*W0]; for(int x = 0; x < s1; ++x){ register uint8_t inp = *iptr++; for(int i = 0; i < 8; ++i){ @@ -500,10 +565,12 @@ size_t *bin2ST(uint8_t *image, int W, int H){ } } int rest = W - s1*8; - register uint8_t inp = *iptr; - for(int i = 0; i < rest; ++i){ - *optr++ = (inp & 0x80) ? 1 : 0; - inp <<= 1; + if(rest){ + register uint8_t inp = *iptr; + for(int i = 0; i < rest; ++i){ + *optr++ = (inp & 0x80) ? 1 : 0; + inp <<= 1; + } } } return ret; diff --git a/LocCorr/imagefile.h b/LocCorr/imagefile.h index 3670cba..b06d039 100644 --- a/LocCorr/imagefile.h +++ b/LocCorr/imagefile.h @@ -20,8 +20,24 @@ #define IMAGEFILE_H__ #include +#include // size_t -#include "fits.h" +#ifndef OMP_FOR +#define Stringify(x) #x +#define OMP_FOR(x) _Pragma(Stringify(omp parallel for x)) +#endif + +typedef uint8_t Imtype; // maybe float or double only + +typedef struct{ + int width; // width + int height; // height + Imtype *data; // picture data + Imtype minval; // extremal data values + Imtype maxval; + char **keylist; // list of options for each key + size_t keynum; // full number of keys (size of *keylist) +} Image; // input file/directory type typedef enum{ @@ -46,11 +62,13 @@ Image *Image_new(int w, int h); Image *Image_sim(const Image *i); void Image_free(Image **I); int Image_write_jpg(const Image *I, const char *name, int equalize); +size_t *get_histogram(const Image *I); +int calc_background(const Image *img, Imtype *bk); -Image *u8toImage(uint8_t *data, int width, int height, int stride); -Image *bin2Im(uint8_t *image, int W, int H); +Image *u8toImage(const uint8_t *data, int width, int height, int stride); +Image *bin2Im(const uint8_t *image, int W, int H); uint8_t *Im2bin(const Image *im, Imtype bk); -size_t *bin2ST(uint8_t *image, int W, int H); -Image *ST2Im(size_t *image, int W, int H); +size_t *bin2ST(const uint8_t *image, int W, int H); +//Image *ST2Im(const size_t *image, int W, int H); #endif // IMAGEFILE_H__ diff --git a/LocCorr/improc.c b/LocCorr/improc.c index 92268f2..318cc8e 100644 --- a/LocCorr/improc.c +++ b/LocCorr/improc.c @@ -21,13 +21,13 @@ #include #include #include -#include #include "basler.h" #include "binmorph.h" #include "cameracapture.h" #include "cmdlnopts.h" #include "config.h" +#include "debug.h" #include "draw.h" #include "grasshopper.h" #include "fits.h" @@ -47,6 +47,7 @@ steppersproc *theSteppers = NULL; static FILE *fXYlog = NULL; static double tstart = 0.; // time of logging start static double FPS = 0.; // frames per second +static float xc = -1., yc = -1.; // center coordinates typedef struct{ uint32_t area; // object area in pixels @@ -115,7 +116,7 @@ static void XYnewline(){ static void getDeviation(object *curobj){ int averflag = 0; - static double Xc[MAX_AVERAGING_ARRAY_SIZE], Yc[MAX_AVERAGING_ARRAY_SIZE]; + static double Xc[NAVER_MAX+1], Yc[NAVER_MAX+1]; double xx = curobj->xc, yy = curobj->yc, xsum2 = 0., ysum2 = 0.; double Sx = 0., Sy = 0.; static int counter = 0; @@ -126,23 +127,24 @@ static void getDeviation(object *curobj){ curobj->xsigma, curobj->ysigma, curobj->WdivH); } //DBG("counter = %d", counter); - if(++counter != theconf.naverage){ + if(++counter < theconf.naverage){ goto process_corrections; } // it's time to calculate average deviations - counter = 0; xx = 0.; yy = 0.; - for(int i = 0; i < theconf.naverage; ++i){ + xx = 0.; yy = 0.; + for(int i = 0; i < counter; ++i){ double x = Xc[i], y = Yc[i]; xx += x; yy += y; xsum2 += x*x; ysum2 += y*y; } - xx /= theconf.naverage; yy /= theconf.naverage; - Sx = sqrt(xsum2/theconf.naverage - xx*xx); - Sy = sqrt(ysum2/theconf.naverage - yy*yy); + xx /= counter; yy /= counter; + Sx = sqrt(xsum2/counter - xx*xx); + Sy = sqrt(ysum2/counter - yy*yy); + counter = 0; #ifdef EBUG - green("\n Average centroid: X=%g (+-%g), Y=%g (+-%g)\n", xx, Sx, yy, Sy); + green("\n Average centroid: X=%.1f (+-%.1f), Y=%.1f (+-%.1f)\n", xx, Sx, yy, Sy); #endif - LOGDBG("getDeviation(): Average centroid: X=%g (+-%g), Y=%g (+-%g)", xx, Sx, yy, Sy); + LOGDBG("getDeviation(): Average centroid: X=%.1f (+-%.1f), Y=%.1f (+-%.1f)", xx, Sx, yy, Sy); averflag = 1; if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy); process_corrections: @@ -156,7 +158,6 @@ process_corrections: } void process_file(Image *I){ - FNAME(); static double lastTproc = 0.; /* #ifdef EBUG @@ -176,12 +177,11 @@ void process_file(Image *I){ return; } int W = I->width, H = I->height; - if(!I->dtype) I->dtype = FLOAT_IMG; //save_fits(I, "fitsout.fits"); //DELTA("Save original"); Imtype bk; if(calc_background(I, &bk)){ - DBG("backgr = %g", bk); + DBG("backgr = %d", bk); DELTA("Got background"); uint8_t *ibin = Im2bin(I, bk); DELTA("Made binary"); @@ -201,14 +201,14 @@ void process_file(Image *I){ ConnComps *cc = NULL; size_t *S = cclabel4(opn, W, H, &cc); FREE(opn); - if(cc->Nobj > 1){ + if(cc->Nobj > 1){ // Nobj = amount of objects + 1 + DBGLOG("Nobj=%d", cc->Nobj-1); object *Objects = MALLOC(object, cc->Nobj-1); int objctr = 0; for(size_t i = 1; i < cc->Nobj; ++i){ Box *b = &cc->boxes[i]; double wh = ((double)b->xmax - b->xmin)/(b->ymax - b->ymin); //DBG("Obj# %zd: wh=%g, area=%d", i, wh, b->area); - // TODO: change magick numbers to parameters if(wh < theconf.minwh || wh > theconf.maxwh) continue; if((int)b->area < theconf.minarea || (int)b->area > theconf.maxarea) continue; double xc = 0., yc = 0.; @@ -239,25 +239,27 @@ void process_file(Image *I){ }; } DELTA("Labeling"); - DBG("T%zd, N=%d\n", time(NULL), objctr); + DBGLOG("T%.2f, N=%d\n", dtime(), objctr); if(objctr > 1){ if(theconf.starssort) qsort(Objects, objctr, sizeof(object), compIntens); else qsort(Objects, objctr, sizeof(object), compDist); } + if(objctr){ #ifdef EBUG - object *o = Objects; - green("%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%8s\n", - "N", "Area", "Mv", "W/H", "Xc", "Yc", "Sx", "Sy", "Area/r^2"); - for(int i = 0; i < objctr; ++i, ++o){ - // 1.0857 = 2.5/ln(10) - printf("%6d\t%6d\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%8.1f\n", - i, o->area, 20.-1.0857*log(o->Isum), o->WdivH, o->xc, o->yc, - o->xsigma, o->ysigma, o->area/o->xsigma/o->ysigma); - } + object *o = Objects; + green("%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%8s\n", + "N", "Area", "Mv", "W/H", "Xc", "Yc", "Sx", "Sy", "Area/r^2"); + for(int i = 0; i < objctr; ++i, ++o){ + // 1.0857 = 2.5/ln(10) + printf("%6d\t%6d\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%8.1f\n", + i, o->area, 20.-1.0857*log(o->Isum), o->WdivH, o->xc, o->yc, + o->xsigma, o->ysigma, o->area/o->xsigma/o->ysigma); + } #endif - getDeviation(Objects); // calculate dX/dY and process corrections + getDeviation(Objects); // calculate dX/dY and process corrections + } { // prepare image and save jpeg uint8_t *outp = NULL; if(theconf.equalize) @@ -265,7 +267,7 @@ void process_file(Image *I){ else outp = linear(I, 3); static Pattern *cross = NULL; - if(!cross) cross = Pattern_cross(33, 33); + if(!cross) cross = Pattern_xcross(33, 33); Img3 i3 = {.data = outp, .w = I->width, .h = H}; // draw fiber center position Pattern_draw3(&i3, cross, theconf.xtarget-theconf.xoff, H-(theconf.ytarget-theconf.yoff), C_B); @@ -273,11 +275,12 @@ void process_file(Image *I){ int H = I->height; // draw current star centroid Pattern_draw3(&i3, cross, Objects[0].xc, H-Objects[0].yc, C_G); + xc = Objects[0].xc; + yc = Objects[0].yc; // draw other centroids for(int i = 1; i < objctr; ++i) Pattern_draw3(&i3, cross, Objects[i].xc, H-Objects[i].yc, C_R); - // Pattern_free(&cross); don't free - static variable! - } + }else{xc = -1.; yc = -1.;} char *tmpnm = MALLOC(char, strlen(GP->outputjpg) + 5); sprintf(tmpnm, "%s-tmp", GP->outputjpg); if(stbi_write_jpg(tmpnm, I->width, I->height, 3, outp, 95)){ @@ -290,7 +293,11 @@ void process_file(Image *I){ FREE(outp); } FREE(Objects); - }else Image_write_jpg(I, GP->outputjpg, theconf.equalize); + }else{ + xc = -1.; yc = -1.; + Image_write_jpg(I, GP->outputjpg, theconf.equalize); + } + DBGLOG("Image saved"); FREE(S); FREE(cc); } @@ -306,8 +313,8 @@ static char *localimages(const char *messageid, int isdir, char *buf, int buflen if(!impath){ if(!realpath(GP->outputjpg, impath)) impath = strdup(GP->outputjpg); } - snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"watch %s\", \"impath\": \"%s\"}", - MESSAGEID, messageid, isdir ? "directory" : "file", impath); + snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"watch %s\", \"impath\": \"%s\", \"xcenter\": %.1f, \"ycenter\": %.1f }", + MESSAGEID, messageid, isdir ? "directory" : "file", impath, xc, yc); return buf; } static char *watchdr(const char *messageid, char *buf, int buflen){ @@ -383,3 +390,8 @@ void setpostprocess(const char *name){ } double getFramesPerS(){ return FPS; } + +void getcenter(float *x, float *y){ + if(x) *x = xc; + if(y) *y = yc; +} diff --git a/LocCorr/improc.h b/LocCorr/improc.h index 0ff2c81..9eed635 100644 --- a/LocCorr/improc.h +++ b/LocCorr/improc.h @@ -27,8 +27,6 @@ #define XY_TOLERANCE (5.) #define PUSIROBO_POSTPROC "pusirobo" -// how many frames will be averaged to count image deviation -#define MAX_AVERAGING_ARRAY_SIZE (25) extern volatile atomic_bool stopwork; extern volatile atomic_ullong ImNumber; @@ -54,5 +52,6 @@ void openXYlog(const char *name); void closeXYlog(); void setpostprocess(const char *name); double getFramesPerS(); +void getcenter(float *x, float *y); #endif // IMPROC_H__ diff --git a/LocCorr/inotify.c b/LocCorr/inotify.c index 542cb13..6d46ed9 100644 --- a/LocCorr/inotify.c +++ b/LocCorr/inotify.c @@ -23,8 +23,8 @@ #include #include #include -#include +#include "debug.h" #include "imagefile.h" static char filenm[FILENAME_MAX]; diff --git a/LocCorr/main.c b/LocCorr/main.c index 5686ddc..7837b61 100644 --- a/LocCorr/main.c +++ b/LocCorr/main.c @@ -19,11 +19,12 @@ #include #include #include // signal +#include #include // strdup -#include #include "cmdlnopts.h" #include "config.h" +#include "debug.h" #include "grasshopper.h" #include "improc.h" #include "pusirobo.h" @@ -112,8 +113,8 @@ int main(int argc, char *argv[]){ if(GP->throwpart < 0. || GP->throwpart > 0.99){ ERRX("Fraction of black pixels should be in [0., 0.99]"); } - if(GP->Naveraging < 2 || GP->Naveraging > MAX_AVERAGING_ARRAY_SIZE) - ERRX("Averaging amount should be from 2 to 25"); + if(GP->Naveraging < 1 || GP->Naveraging > NAVER_MAX) + ERRX("Averaging amount should be from 1 to %d", NAVER_MAX); tp = chk_inp(GP->inputname); if(tp == T_WRONG) ERRX("Enter correct image file or directory name"); // check ability of saving file @@ -183,7 +184,7 @@ int main(int argc, char *argv[]){ setpostprocess(GP->processing); check4running(self, GP->pidfile); DBG("%s started, snippets library version is %s\n", self, sl_libversion()); - free(self); + free(self); self = NULL; signal(SIGTERM, signals); // kill (-15) - quit signal(SIGHUP, SIG_IGN); // hup - ignore signal(SIGINT, signals); // ctrl+C - quit diff --git a/LocCorr/median.c b/LocCorr/median.c index 4dda43a..503eab7 100644 --- a/LocCorr/median.c +++ b/LocCorr/median.c @@ -26,9 +26,9 @@ #include #include #include -#include #include "config.h" +#include "debug.h" #include "imagefile.h" #include "median.h" @@ -36,8 +36,13 @@ #define ELEM_SWAP(a, b) {register Imtype t = a; a = b; b = t;} #define PIX_SORT(a, b) {if (p[a] > p[b]) ELEM_SWAP(p[a], p[b]);} +static inline Imtype mean(Imtype a, Imtype b){ + register uint16_t x = ((uint16_t)a + (uint16_t)b) / 2; + return (Imtype)x; +} + static Imtype opt_med2(Imtype *p){ - return (p[0] + p[1]) * 0.5; + return mean(p[0], p[1]); } static Imtype opt_med3(Imtype *p){ PIX_SORT(0, 1); PIX_SORT(1, 2); PIX_SORT(0, 1); @@ -46,7 +51,7 @@ static Imtype opt_med3(Imtype *p){ static Imtype opt_med4(Imtype *p){ PIX_SORT(0, 2); PIX_SORT(1, 3); PIX_SORT(0, 1); PIX_SORT(2, 3); - return(p[1] + p[2]) * 0.5; + return mean(p[1], p[2]); } static Imtype opt_med5(Imtype *p){ PIX_SORT(0, 1); PIX_SORT(3, 4); PIX_SORT(0, 3); @@ -61,7 +66,7 @@ static Imtype opt_med6(Imtype *p){ PIX_SORT(1, 2); PIX_SORT(3, 4); PIX_SORT(0, 1); PIX_SORT(2, 3); PIX_SORT(4, 5); PIX_SORT(1, 2); PIX_SORT(3, 4); - return ( p[2] + p[3] ) * 0.5; + return mean(p[2], p[3]); } static Imtype opt_med7(Imtype *p){ PIX_SORT(0, 5); PIX_SORT(0, 3); PIX_SORT(1, 6); @@ -78,7 +83,7 @@ static Imtype opt_med8(Imtype *p){ PIX_SORT(3, 5); PIX_SORT(0, 1); PIX_SORT(2, 3); PIX_SORT(4, 5); PIX_SORT(6, 7); PIX_SORT(1, 4); PIX_SORT(3, 6); - return(p[3] + p[4]) * 0.5; + return mean(p[3], p[4]); } static Imtype opt_med9(Imtype *p){ PIX_SORT(1, 2); PIX_SORT(4, 5); PIX_SORT(7, 8); @@ -103,7 +108,7 @@ static Imtype opt_med16(Imtype *p){ PIX_SORT(4, 5); PIX_SORT(6, 7); PIX_SORT(8, 9); PIX_SORT(10, 11); PIX_SORT(12, 13); PIX_SORT(14, 15); PIX_SORT(1, 8); PIX_SORT(3, 10); PIX_SORT(5, 12); PIX_SORT(7, 14); PIX_SORT(5, 8); PIX_SORT(7, 10); - return (p[7] + p[8]) * 0.5; + return mean(p[7], p[8]); } static Imtype opt_med25(Imtype *p){ PIX_SORT(0, 1) ; PIX_SORT(3, 4) ; PIX_SORT(2, 4) ; @@ -201,7 +206,7 @@ Imtype calc_median(Imtype *idata, int n){ const medfunc fnarr[] = {opt_med2, opt_med3, opt_med4, opt_med5, opt_med6, opt_med7, opt_med8, opt_med9}; if(n == 1) return *idata; - if(n < 10) fn = fnarr[n - 1]; + if(n < 10) fn = fnarr[n - 2]; else if(n == 16) fn = opt_med16; else if(n == 25) fn = opt_med25; if(fn){ @@ -229,12 +234,12 @@ typedef struct Mediator_t{ #define maxCt(m) (((m)->ct)/2) //count of Imtypes in maxheap //returns 1 if heap[i] < heap[j] -inline int mmless(Mediator* m, int i, int j){ +static inline int mmless(Mediator* m, int i, int j){ return ImtypeLess(m->data[m->heap[i]],m->data[m->heap[j]]); } //swaps Imtypes i&j in heap, maintains indexes -inline int mmexchange(Mediator* m, int i, int j){ +static inline int mmexchange(Mediator* m, int i, int j){ int t = m->heap[i]; m->heap[i] = m->heap[j]; m->heap[j] = t; @@ -244,12 +249,12 @@ inline int mmexchange(Mediator* m, int i, int j){ } //swaps Imtypes i&j if i1 && i < minCt(m) && mmless(m, i+1, i)) ++i; if(!mmCmpExch(m,i,i/2)) break; @@ -257,7 +262,7 @@ void minSortDown(Mediator* m, int i){ } //maintains maxheap property for all Imtypes below i/2. (negative indexes) -void maxSortDown(Mediator* m, int i){ +static inline void maxSortDown(Mediator* m, int i){ for(; i >= -maxCt(m); i*=2){ if(i<-1 && i > -maxCt(m) && mmless(m, i, i-1)) --i; if(!mmCmpExch(m,i/2,i)) break; @@ -266,14 +271,14 @@ void maxSortDown(Mediator* m, int i){ //maintains minheap property for all Imtypes above i, including median //returns true if median changed -int minSortUp(Mediator* m, int i){ +static inline int minSortUp(Mediator* m, int i){ while (i > 0 && mmCmpExch(m, i, i/2)) i /= 2; return (i == 0); } //maintains maxheap property for all Imtypes above i, including median //returns true if median changed -int maxSortUp(Mediator* m, int i){ +static inline int maxSortUp(Mediator* m, int i){ while (i < 0 && mmCmpExch(m, i/2, i)) i /= 2; return (i == 0); } @@ -282,7 +287,7 @@ int maxSortUp(Mediator* m, int i){ //creates new Mediator: to calculate `nImtypes` running median. //mallocs single block of memory, caller must free. -Mediator* MediatorNew(int nImtypes){ +static Mediator* MediatorNew(int nImtypes){ int size = sizeof(Mediator) + nImtypes*(sizeof(Imtype)+sizeof(int)*2); Mediator* m = malloc(size); m->data = (Imtype*)(m + 1); @@ -298,7 +303,7 @@ Mediator* MediatorNew(int nImtypes){ } //Inserts Imtype, maintains median in O(lg nImtypes) -void MediatorInsert(Mediator* m, Imtype v){ +static void MediatorInsert(Mediator* m, Imtype v){ int isNew=(m->ctN); int p = m->pos[m->idx]; Imtype old = m->data[m->idx]; @@ -318,15 +323,16 @@ void MediatorInsert(Mediator* m, Imtype v){ } //returns median Imtype (or average of 2 when Imtype count is even) -Imtype MediatorMedian(Mediator* m){ +static Imtype MediatorMedian(Mediator* m){ Imtype v = m->data[m->heap[0]]; if ((m->ct&1) == 0) v = ImtypeMean(v, m->data[m->heap[-1]]); return v; } +#if 0 // median + min/max -Imtype MediatorStat(Mediator* m, Imtype *minval, Imtype *maxval){ - Imtype v= m->data[m->heap[0]]; +static Imtype MediatorStat(Mediator* m, Imtype *minval, Imtype *maxval){ + Imtype v = m->data[m->heap[0]]; if ((m->ct&1) == 0) v = ImtypeMean(v, m->data[m->heap[-1]]); Imtype min = v, max = v; int i; @@ -342,6 +348,7 @@ Imtype MediatorStat(Mediator* m, Imtype *minval, Imtype *maxval){ *maxval = max; return v; } +#endif /** * filter image by median (seed*2 + 1) x (seed*2 + 1) @@ -374,7 +381,7 @@ Image *get_median(const Image *img, int seed){ MediatorInsert(m, inputima[xx]); med[medidx] = MediatorMedian(m); } - FREE(m); + free(m); } Image_minmax(out); DBG("time for median filtering %zdx%zd of image %zdx%zd: %gs", blksz, blksz, w, h, @@ -407,12 +414,12 @@ int get_stat(const Image *in, int seed, Image **mean, Image **std){ Imtype *om = (M) ? &M->data[startidx] : NULL; Imtype *os = (S) ? &S->data[startidx] : NULL; for(int x = seed; x < xmax; ++x){ - Imtype sum = 0, sum2 = 0; + double sum = 0, sum2 = 0; int yb = y + seed + 1, xm = x - seed; for(int yy = y - seed; yy < yb; ++yy){ Imtype *ptr = &in->data[yy * w + xm]; for(int xx = 0; xx < hsz; ++xx){ - Imtype d = *ptr++; + double d = *ptr++; sum += d; sum2 += d*d; } @@ -420,10 +427,10 @@ int get_stat(const Image *in, int seed, Image **mean, Image **std){ //DBG("sum=%g, sum2=%g, sz=%d", sum, sum2, sz); sum /= sz; if(om){ - *om++ = sum; + *om++ = (Imtype)sum; //DBG("mean (%d, %d): %g", x, y, sum); } - if(os) *os++ = sqrt(sum2/sz - sum*sum); + if(os) *os++ = (Imtype)sqrt(sum2/sz - sum*sum); } } if(mean){ @@ -437,79 +444,3 @@ int get_stat(const Image *in, int seed, Image **mean, Image **std){ DBG("time for mean/sigma computation: %gs", dtime() - t0); return TRUE; } - -/** - * @brief calc_background - Simple background calculation by histogram - * @param img (i) - input image (here will be modified its top2proc field) - * @param bk (o) - background value - * @return 0 if error - */ -int calc_background(Image *img, Imtype *bk){ - //DBG("image: min=%g, max=%g", img->minval, img->maxval); - if(!img || !bk) return FALSE; - if(img->maxval - img->minval < DBL_EPSILON){ - WARNX("Zero or overilluminated image!"); - return FALSE; - } - if(theconf.fixedbkg){ - *bk = theconf.fixedbkg; - return TRUE; - } - int w = img->width, h = img->height, wh = w*h; - Imtype min = img->minval, ampl = img->maxval - min; - int histogram[256] = {0}; - DBG("min: %g, max: %g, ampl: %g", min, img->maxval, ampl); - #pragma omp parallel - { - int histogram_private[256] = {0}; - #pragma omp for nowait - for(int i = 0; i < wh; ++i){ - int newval = (int)((((img->data[i]) - min)/ampl)*255. + 0.5); - ++histogram_private[newval]; - } - #pragma omp critical - { - for(int i=0; i<256; ++i) histogram[i] += histogram_private[i]; - } - } - int modeidx = 0, modeval = 0; - for(int i = 0; i < 256; ++i) - if(modeval < histogram[i]){ - modeval = histogram[i]; - modeidx = i; - } - //DBG("Mode=%g @ idx%d (N=%d)", ((Imtype)modeidx / 255.)*ampl, modeidx, modeval); - int diff2[256] = {0}; - for(int i = 2; i < 254; ++i) diff2[i] = (histogram[i+2]+histogram[i-2]-2*histogram[i])/4; - if(modeidx < 2) modeidx = 2; - if(modeidx > 253){ - WARNX("Overilluminated image"); - return FALSE; // very bad image: overilluminated - } - int borderidx = modeidx; - // green("2\n"); - for(int i = modeidx; i < 254; ++i){ // search bend-point by second derivate - // printf("%d: %d, %d\n", i, diff2[i], diff2[i+1]); - if(diff2[i] <= 0 && diff2[i+1] <=0){ - borderidx = i; break; - } - } - //DBG("borderidx=%d -> %d", borderidx, (borderidx+modeidx)/2); - //borderidx = (borderidx + modeidx) / 2; - Imtype borderval = ((Imtype)borderidx / 255.)*ampl + min; - if(bk) *bk = borderval; - //green("HISTO:\n"); - //for(int i = 0; i < 256; ++i) printf("%d:\t%d\t%d\n", i, histogram[i], diff2[i]); - // calculate values of upper 2% border -#if 0 - Image *out = Image_sim(img); - //DBG("found border: %g @ %d", borderval, borderidx); - OMP_FOR() - for(int i = 0; i < wh; ++i){ - register Imtype val = img->data[i]; - if(val > borderval) out->data[i] = val - borderval; - } - Image_minmax(out); -#endif - return TRUE; -} diff --git a/LocCorr/median.h b/LocCorr/median.h index 92fe1a5..d8014d1 100644 --- a/LocCorr/median.h +++ b/LocCorr/median.h @@ -27,6 +27,5 @@ Imtype calc_median(Imtype *idata, int n); Image *get_median(const Image *img, int seed); int get_stat(const Image *in, int seed, Image **mean, Image **std); -int calc_background(Image *img, Imtype *bk); #endif // __MEDIAN_H__ diff --git a/LocCorr/pusirobo.c b/LocCorr/pusirobo.c index 2910876..2d42783 100644 --- a/LocCorr/pusirobo.c +++ b/LocCorr/pusirobo.c @@ -26,9 +26,9 @@ #include #include #include -#include #include "config.h" +#include "debug.h" #include "improc.h" // global variable stopwork #include "pusirobo.h" #include "socket.h" @@ -327,7 +327,7 @@ static int chkRelay(){ relay = r; ret = TRUE; rtn: - FREE(ans); + free(ans); return ret; } @@ -357,7 +357,7 @@ static int setSpeed(const char *mesg, const char *name){ LOGERR("no %s motor", name); retval = FALSE; } - FREE(ans); + if(ans) free(ans); return retval; } @@ -403,11 +403,11 @@ static int pusi_connect_server(){ send_message_nocheck(registerVaxe); send_message_nocheck(registerFocus); send_message_nocheck(registerRelay); - int retval = TRUE; - if(!chkRelay()) retval = FALSE; - if(!setSpeed(setUspeed, "U")) retval = FALSE; - if(!setSpeed(setVspeed, "V")) retval = FALSE; - if(!setSpeed(setFspeed, "F")) retval = FALSE; + int retval = FALSE; + if(chkRelay()) retval = TRUE; + if(setSpeed(setUspeed, "U")) retval = TRUE; + if(setSpeed(setVspeed, "V")) retval = TRUE; + if(setSpeed(setFspeed, "F")) retval = TRUE; if(!retval) pusi_disconnect(); else{ state = PUSI_RELAX; @@ -460,7 +460,7 @@ static int moving_finished(const char *mesgstatus, volatile atomic_int *position LOGDBG("%s not found in '%s'", CURPOSstatus, ans); } } - FREE(ans); + if(ans) free(ans); return ret; } @@ -483,7 +483,7 @@ static int move_motor(const char *movecmd, int s){ LOGWARN("NO OK in %s", ans); ret = FALSE; } - FREE(ans); + if(ans) free(ans); return ret; } @@ -968,6 +968,7 @@ static char *Umove(const char *val, char *buf, int buflen){ int Unfixed = Uposition + d + Fposition; if(Unfixed > theconf.maxUsteps || Unfixed < -theconf.maxUsteps){ snprintf(buf, buflen, FAIL); + return buf; } dUmove = d; snprintf(buf, buflen, OK); @@ -978,6 +979,7 @@ static char *Vmove(const char *val, char *buf, int buflen){ int Vnfixed = Vposition + d + Fposition; if(Vnfixed > theconf.maxVsteps || Vnfixed < -theconf.maxVsteps){ snprintf(buf, buflen, FAIL); + return buf; } dVmove = d; snprintf(buf, buflen, OK); @@ -1009,7 +1011,7 @@ static char *relaycmd(const char *val, char *buf, int buflen){ } } } - FREE(par); + free(par); snprintf(buf, buflen, "%s", ans); return buf; } diff --git a/LocCorr/socket.c b/LocCorr/socket.c index 61a204b..40e0ad1 100644 --- a/LocCorr/socket.c +++ b/LocCorr/socket.c @@ -29,10 +29,10 @@ #include #include // syscall #include // daemon -#include #include "cmdlnopts.h" #include "config.h" +#include "debug.h" #include "improc.h" #include "socket.h" @@ -140,7 +140,7 @@ static char *moveU(const char *val, char *buf, int buflen){ return retFAIL(buf, buflen); } static char *moveV(const char *val, char *buf, int buflen){ - if(theSteppers && theSteppers->moveByV) return theSteppers->moveByU(val, buf, buflen); + if(theSteppers && theSteppers->moveByV) return theSteppers->moveByV(val, buf, buflen); return retFAIL(buf, buflen); } static char *relaycmd(const char *val, char *buf, int buflen){ @@ -171,7 +171,7 @@ static char *processCommand(const char msg[BUFLEN], char *ans, int anslen){ DBG("got KEY '%s' with value '%s'", kv, value); key_value result; par = chk_keyval(kv, value, &result); - FREE(kv); + free(kv); kv = NULL; if(par){ switch(par->type){ case PAR_INT: