LocCorr - pre-alpha version of INASAN corrector

This commit is contained in:
2021-06-09 12:29:39 +03:00
parent cff48d3583
commit c55b407cf8
15 changed files with 2042 additions and 125 deletions

View File

@@ -25,22 +25,28 @@
#include "binmorph.h"
#include "cmdlnopts.h"
#include "config.h"
#include "draw.h"
#include "grasshopper.h"
#include "fits.h"
#include "improc.h"
#include "inotify.h"
#include "median.h"
// how many frames will be averaged to count image deviation
#define AVERAGING_ARRAY_SIZE (5)
// tolerance of deviations by X and Y axis
#define XY_TOLERANCE (1.)
#include "pusirobo.h"
static FILE *fXYlog = NULL;
static double Xtarget = -1., Ytarget = -1.; // target coordinates
static double tstart = 0.; // time of logging start
int stopwork = 0;
// function to process calculated corrections
static void (*proc_corr)(double, double, int) = NULL;
// function to get stepper server status
char *(*stepstatus)(char *buf, int buflen) = NULL;
// set new status
char *(*setstepstatus)(const char *newstatus, char *buf, int buflen) = NULL;
// move focus
char *(*movefocus)(const char *newstatus, char *buf, int buflen) = NULL;
typedef struct{
uint32_t area; // object area in pixels
@@ -52,19 +58,20 @@ typedef struct{
double ysigma;
} object;
typedef enum{
PROCESS_NONE,
PROCESS_PUSIROBO
} postproc_type;
static postproc_type postprocess = PROCESS_NONE;
static bool save_fits(Image *I, const char *name){
uint8_t *outp = NULL;
if(GP->equalize)
outp = equalize(I, 1, GP->throwpart);
else
outp = linear(I, 1);
char fname[PATH_MAX];
char *flname = strdup(name);
char *pt = strrchr(flname, '.');
snprintf(fname, PATH_MAX, name);
char *pt = strrchr(fname, '.');
if(pt) *pt = 0;
snprintf(fname, PATH_MAX, "%s.jpg", flname);
stbi_write_jpg(fname, I->width, I->height, 1, outp, 95);
FREE(outp);
strncat(fname, ".jpg", PATH_MAX);
Image_write_jpg(I, fname, theconf.equalize);
unlink(name);
return FITS_write(name, I);
}
@@ -77,22 +84,37 @@ static void savebin(uint8_t *b, int W, int H, const char *name){
}
}
// function for Qsort
static int compObjs(const void *a, const void *b){
// functions for Qsort
static int compIntens(const void *a, const void *b){ // compare by intensity
const object *oa = (const object*)a;
const object *ob = (const object*)b;
double idiff = (oa->Isum - ob->Isum)/(oa->Isum + ob->Isum);
if(fabs(idiff) > GP->intensthres) return (idiff > 0) ? -1:1;
if(fabs(idiff) > theconf.intensthres) return (idiff > 0) ? -1:1;
double r2a = oa->xc * oa->xc + oa->yc * oa->yc;
double r2b = ob->xc * ob->xc + ob->yc * ob->yc;
return (r2a < r2b) ? -1 : 1;
}
static int compDist(const void *a, const void *b){ // compare by distanse from target
const object *oa = (const object*)a;
const object *ob = (const object*)b;
double xa = oa->xc - theconf.xtarget, xb = ob->xc - theconf.xtarget,
ya = oa->yc - theconf.ytarget, yb = ob->yc - theconf.ytarget;
double r2a = xa*xa + ya*ya;
double r2b = xb*xb + yb*yb;
return (r2a < r2b) ? -1 : 1;
}
static void XYnewline(){
if(!fXYlog) return;
fprintf(fXYlog, "\n");
fflush(fXYlog);
}
static void getDeviation(object *curobj){
if(Xtarget < 0. || Ytarget < 0.){ // init from user parameters
Xtarget = GP->xtarget; Ytarget = GP->ytarget;
}
static double Xc[AVERAGING_ARRAY_SIZE], Yc[AVERAGING_ARRAY_SIZE];
int averflag = 0;
static double Xc[MAX_AVERAGING_ARRAY_SIZE], Yc[MAX_AVERAGING_ARRAY_SIZE];
double xx = curobj->xc, yy = curobj->yc, xsum2 = 0., ysum2 = 0.;
double Sx = 0., Sy = 0.;
static int counter = 0;
Xc[counter] = curobj->xc; Yc[counter] = curobj->yc;
if(fXYlog){ // make log record
@@ -100,31 +122,32 @@ static void getDeviation(object *curobj){
dtime() - tstart, curobj->xc, curobj->yc,
curobj->xsigma, curobj->ysigma, curobj->WdivH);
}
if(++counter != AVERAGING_ARRAY_SIZE){
if(fXYlog) fprintf(fXYlog, "\n");
return;
DBG("counter = %d", counter);
if(++counter != theconf.naverage){
goto process_corrections;
}
// it's time to calculate average deviations
counter = 0;
double xdev = 0., ydev = 0., xsum2 = 0., ysum2 = 0.;
for(int i = 0; i < AVERAGING_ARRAY_SIZE; ++i){
double dx = Xc[i] - Xtarget, dy = Yc[i] - Ytarget;
xdev += dx; ydev += dy;
xsum2 += dx*dx; ysum2 += dy*dy;
counter = 0; xx = 0.; yy = 0.;
for(int i = 0; i < theconf.naverage; ++i){
double x = Xc[i], y = Yc[i];
xx += x; yy += y;
xsum2 += x*x; ysum2 += y*y;
}
xdev /= AVERAGING_ARRAY_SIZE; ydev /= AVERAGING_ARRAY_SIZE;
double Sx = sqrt(xsum2/AVERAGING_ARRAY_SIZE - xdev*xdev);
double Sy = sqrt(ysum2/AVERAGING_ARRAY_SIZE - ydev*ydev);
DBG("xtag=%g, ytag=%g", Xtarget, Ytarget);
green("\n\n\n Deviations: dX=%g (+-%g), dY=%g (+-%g)\n", xdev, Sx, ydev, Sy);
if(Xtarget < 0. || Ytarget < 0. || fabs(xdev) < XY_TOLERANCE || fabs(ydev) < XY_TOLERANCE){
DBG("Target coordinates not defined or correction too small");
if(fXYlog) fprintf(fXYlog, "\n");
return;
}
if(fXYlog){
fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f\n", xdev, ydev, Sx, Sy);
xx /= theconf.naverage; yy /= theconf.naverage;
Sx = sqrt(xsum2/theconf.naverage - xx*xx);
Sy = sqrt(ysum2/theconf.naverage - yy*yy);
green("\n\n\n Average centroid: X=%g (+-%g), Y=%g (+-%g)\n", xx, Sx, yy, Sy);
LOGDBG("getDeviation(): Average centroid: X=%g (+-%g), Y=%g (+-%g)", xx, Sx, yy, Sy);
averflag = 1;
if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy);
process_corrections:
if(proc_corr){
if(Sx > 1. || Sy > 1.){
LOGDBG("Bad value - not process"); // don't run processing for bad data
}else
proc_corr(xx, yy, averflag);
}
XYnewline();
}
void process_file(Image *I){
@@ -135,7 +158,6 @@ void process_file(Image *I){
#define DELTA(x)
#endif
// I - original image
// M - median filtering
// mean - local mean
// std - local STD
/**** read original image ****/
@@ -148,15 +170,6 @@ void process_file(Image *I){
if(!I->dtype) I->dtype = FLOAT_IMG;
save_fits(I, "fitsout.fits");
DELTA("Save original");
/*
uint8_t *outp = NULL;
if(GP->equalize)
outp = equalize(I, 1, GP->throwpart);
else
outp = linear(I, 1);
stbi_write_jpg("jpegout.jpg", I->width, I->height, 3, outp, 95);
FREE(outp);
*/
Imtype bk;
if(calc_background(I, &bk)){
DBG("backgr = %g", bk);
@@ -166,12 +179,12 @@ void process_file(Image *I){
if(ibin){
savebin(ibin, W, H, "binary.fits");
DELTA("save binary.fits");
uint8_t *er = erosionN(ibin, W, H, GP->nerosions);
uint8_t *er = erosionN(ibin, W, H, theconf.Nerosions);
FREE(ibin);
DELTA("Erosion");
savebin(er, W, H, "erosion.fits");
DELTA("Save erosion");
uint8_t *opn = dilationN(er, W, H, GP->ndilations);
uint8_t *opn = dilationN(er, W, H, theconf.Ndilations);
FREE(er);
DELTA("Opening");
savebin(opn, W, H, "opening.fits");
@@ -187,8 +200,8 @@ void process_file(Image *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 < 0.2 || wh > 5.) continue;
if((int)b->area < GP->minarea) continue;
if(wh < MINWH || wh > MAXWH) continue;
if((int)b->area < theconf.minarea || (int)b->area > theconf.maxarea) continue;
double xc = 0., yc = 0.;
double x2c = 0., y2c = 0., Isum = 0.;
for(size_t y = b->ymin; y <= b->ymax; ++y){
@@ -218,7 +231,12 @@ void process_file(Image *I){
}
DELTA("Labeling");
printf("T%zd, N=%d\n", time(NULL), objctr);
qsort(Objects, objctr, sizeof(object), compObjs);
if(objctr > 1){
if(theconf.starssort)
qsort(Objects, objctr, sizeof(object), compIntens);
else
qsort(Objects, objctr, sizeof(object), compDist);
}
object *o = Objects;
green("%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\n",
"N", "Area", "Mv", "W/H", "Xc", "Yc", "Sx", "Sy");
@@ -228,20 +246,23 @@ void process_file(Image *I){
i, o->area, 20.-1.0857*log(o->Isum), o->WdivH, o->xc, o->yc, o->xsigma, o->ysigma);
}
getDeviation(Objects);
if(objctr){ // draw crosses @ objects' centers
{ // prepare image
uint8_t *outp = NULL;
if(GP->equalize)
outp = equalize(I, 3, GP->throwpart);
if(theconf.equalize)
outp = equalize(I, 3, theconf.throwpart);
else
outp = linear(I, 3);
Pattern *cross = Pattern_cross(33, 33);
int H = I->height;
Img3 i3 = {.data = outp, .w = I->width, .h = H};
Pattern_draw3(&i3, cross, Objects[0].xc, H-Objects[0].yc, C_G);
for(int i = 1; i < objctr; ++i)
Pattern_draw3(&i3, cross, Objects[i].xc, H-Objects[i].yc, C_R);
Pattern_free(&cross);
stbi_write_jpg("outpWcrosses.jpg", I->width, I->height, 3, outp, 95);
if(objctr){ // draw crosses @ objects' centers
static Pattern *cross = NULL;
if(!cross) cross = Pattern_cross(33, 33);
int H = I->height;
Img3 i3 = {.data = outp, .w = I->width, .h = H};
Pattern_draw3(&i3, cross, Objects[0].xc, H-Objects[0].yc, C_G);
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!
}
stbi_write_jpg(GP->outputjpg, I->width, I->height, 3, outp, 95);
FREE(outp);
}
FREE(cc);
@@ -273,6 +294,7 @@ void process_file(Image *I){
}
int process_input(InputType tp, char *name){
DBG("process_input(%d, %s)", tp, name);
if(tp == T_DIRECTORY) return watch_directory(name, process_file);
else if(tp == T_CAPT_GRASSHOPPER) return capture_grasshopper(process_file);
return watch_file(name, process_file);
@@ -293,7 +315,8 @@ void openXYlog(const char *name){
}
time_t t = time(NULL);
fprintf(fXYlog, "# Start at: %s", ctime(&t));
fprintf(fXYlog, "# time,s\tXc\tYc\t\tSx\tSy\tW/H\tcorrX\tcorrY\tSXcorr\tSYcorr\n");
fprintf(fXYlog, "# time Xc\tYc\t\tSx\tSy\tW/H\taverX\taverY\tSX\tSY\n");
fflush(fXYlog);
tstart = dtime();
}
void closeXYlog(){
@@ -301,3 +324,27 @@ void closeXYlog(){
fclose(fXYlog);
fXYlog = NULL;
}
/**
* @brief setpostprocess - set postprocessing name (what to do with deviations data)
* @param name - "pusirobo" for pusirobot drives
*/
void setpostprocess(const char *name){
if(!name) return;
if(strncasecmp(name, PUSIROBO_POSTPROC, sizeof(PUSIROBO_POSTPROC) - 1) == 0){
postprocess = PROCESS_PUSIROBO;
DBG("Postprocess: pusirobot drives");
LOGMSG("Postprocess: pusirobot drives");
if(!pusi_connect()){
WARNX("Pusiserver unavailable, will check later");
LOGWARN("Pusiserver unavailable, will check later");
}
proc_corr = pusi_process_corrections;
stepstatus = pusi_status;
setstepstatus = set_pusistatus;
movefocus = set_pfocus;
}else{
WARNX("Unknown postprocess \"%s\"", name);
LOGERR("Unknown postprocess \"%s\"", name);
}
}