some bugs fixed

This commit is contained in:
Edward Emelianov 2021-10-18 17:24:03 +03:00
parent 81c94bcd1e
commit 68449bef89
30 changed files with 577 additions and 551 deletions

View File

@ -5,11 +5,10 @@ set(MID_VERSION "0")
set(MAJOR_VERSION "0") set(MAJOR_VERSION "0")
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C) project(${PROJ} VERSION ${VERSION} LANGUAGES C)
# default flags # default flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=gnu99 -march=native -fdata-sections -ffunction-sections") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections")
set(CMAKE_COLOR_MAKEFILE ON) set(CMAKE_COLOR_MAKEFILE ON)
@ -20,10 +19,12 @@ set(CMAKE_VERBOSE_MAKEFILE "ON")
# cmake -DEBUG=1 -> debugging # cmake -DEBUG=1 -> debugging
if(DEFINED EBUG AND EBUG EQUAL 1) 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) set(CMAKE_BUILD_TYPE DEBUG)
add_definitions(-DEBUG) add_definitions(-DEBUG)
else() 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) set(CMAKE_BUILD_TYPE RELEASE)
endif() endif()
@ -69,7 +70,7 @@ link_directories(${${PROJ}_LIBRARY_DIRS} ${FLYCAP_LIBRARY_DIRS} ${BASLER_LIBRARY
add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\"
-DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\" -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\"
-DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\" -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 # -l
target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} ${FLYCAP_LIBRARIES} ${BASLER_LIBRARIES} -lm) target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} ${FLYCAP_LIBRARIES} ${BASLER_LIBRARIES} -lm)

9
LocCorr/DEBUG.log.analyze Executable file
View File

@ -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"

View File

@ -16,10 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <usefull_macros.h>
#include <pylonc/PylonC.h> #include <pylonc/PylonC.h>
#include "basler.h" #include "basler.h"
#include "debug.h"
#include "imagefile.h" #include "imagefile.h"
static PYLON_DEVICE_HANDLE hDev; static PYLON_DEVICE_HANDLE hDev;
@ -74,7 +74,6 @@ static void disconnect(){
isopened = FALSE; isopened = FALSE;
} }
// get node & check it for read/write
/** /**
* @brief chkNode - get node & check it for read/write * @brief chkNode - get node & check it for read/write
* @param phNode (io) - pointer to node * @param phNode (io) - pointer to node
@ -144,6 +143,7 @@ static int setBoolean(char *featureName, _Bool val){
NODE_HANDLE hNode; NODE_HANDLE hNode;
if(!chkNode(&hNode, featureName, BooleanNode, TRUE)) return FALSE; if(!chkNode(&hNode, featureName, BooleanNode, TRUE)) return FALSE;
PYLONFN(GenApiBooleanSetValue, hNode, val); PYLONFN(GenApiBooleanSetValue, hNode, val);
return TRUE;
} }
static int setInt(char *featureName, int64_t val){ static int setInt(char *featureName, int64_t val){
if(!isopened || !featureName) return FALSE; if(!isopened || !featureName) return FALSE;
@ -222,6 +222,7 @@ static Image *capture(){
float_values f; float_values f;
if(!getFloat("DeviceTemperature", &f)) WARNX("Can't get temperature"); if(!getFloat("DeviceTemperature", &f)) WARNX("Can't get temperature");
else{ else{
LOGDBG("Basler temperature: %.1f", f.val);
DBG("Temperature: %.1f", f.val); DBG("Temperature: %.1f", f.val);
if(f.val > 80.){ if(f.val > 80.){
WARNX("Device too hot"); WARNX("Device too hot");
@ -230,7 +231,7 @@ static Image *capture(){
toohot = TRUE; toohot = TRUE;
} }
}else if(toohot && f.val < 75.){ }else if(toohot && f.val < 75.){
LOGMSG("Device temperature is normal"); LOGDBG("Device temperature is normal");
toohot = FALSE; toohot = FALSE;
} }
} }

View File

@ -24,8 +24,9 @@
#include <string.h> // memcpy #include <string.h> // memcpy
#include <math.h> #include <math.h>
#include <sys/time.h> #include <sys/time.h>
#include <usefull_macros.h>
#include "binmorph.h" #include "binmorph.h"
#include "debug.h"
#include "imagefile.h" #include "imagefile.h"
// global arrays for erosion/dilation masks // 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); uint8_t *ret = MALLOC(uint8_t, W*H);
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
int w = W0-1, h = H-1; int w = W0-1, h = H-1;
{int y = 0; {
// top of image, y = 0 // top of image, y = 0
#define IM_UP #define IM_UP
#include "fc_filter.h" #include "fc_filter.h"
@ -79,7 +80,6 @@ uint8_t *filter4(uint8_t *image, int W, int H){
} }
{ {
// image bottom, y = h // image bottom, y = h
int y = h;
#define IM_DOWN #define IM_DOWN
#include "fc_filter.h" #include "fc_filter.h"
#undef IM_DOWN #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); uint8_t *ret = MALLOC(uint8_t, W*H);
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
int w = W0-1, h = H-1; int w = W0-1, h = H-1;
{int y = 0; {
#define IM_UP #define IM_UP
#include "ec_filter.h" #include "ec_filter.h"
#undef IM_UP #undef IM_UP
@ -108,7 +108,6 @@ uint8_t *filter8(uint8_t *image, int W, int H){
#include "ec_filter.h" #include "ec_filter.h"
} }
{ {
int y = h;
#define IM_DOWN #define IM_DOWN
#include "ec_filter.h" #include "ec_filter.h"
#undef IM_DOWN #undef IM_DOWN
@ -130,7 +129,7 @@ uint8_t *dilation(uint8_t *image, int W, int H){
uint8_t lastmask = ~(1<<rest); uint8_t lastmask = ~(1<<rest);
if(!DIL) morph_init(); if(!DIL) morph_init();
uint8_t *ret = MALLOC(uint8_t, W0*H); uint8_t *ret = MALLOC(uint8_t, W0*H);
{int y = 0; {
// top of image, y = 0 // top of image, y = 0
#define IM_UP #define IM_UP
#include "dilation.h" #include "dilation.h"
@ -140,7 +139,7 @@ uint8_t *dilation(uint8_t *image, int W, int H){
// mid of image, y = 1..h-1 // mid of image, y = 1..h-1
#include "dilation.h" #include "dilation.h"
} }
{int y = h; {
// image bottom, y = h // image bottom, y = h
#define IM_DOWN #define IM_DOWN
#include "dilation.h" #include "dilation.h"
@ -329,19 +328,8 @@ uint8_t *substim(uint8_t *im1, uint8_t *im2, int W, int H){
#define TEST(...) #define TEST(...)
#endif #endif
/**
* label 4-connected components on image
* (slow algorythm, but easy to parallel)
*
* @param I (i) - image ("packed")
* @param W,H - size of the image (W - width in pixels)
* @param CC (o) - connected components boxes
* @return an array of labeled components
*/
size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){
size_t *assoc;
// check table and rename all "oldval" into "newval" // check table and rename all "oldval" into "newval"
inline void remark(size_t newval, size_t oldval){ static inline void remark(size_t newval, size_t oldval, size_t *assoc){
TEST("\tnew = %zd, old=%zd; ", newval, oldval); TEST("\tnew = %zd, old=%zd; ", newval, oldval);
// find the least values // find the least values
do{newval = assoc[newval];}while(assoc[newval] != newval); do{newval = assoc[newval];}while(assoc[newval] != newval);
@ -356,6 +344,18 @@ size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){
TEST("change %zd to %zd\n", oldval, newval); TEST("change %zd to %zd\n", oldval, newval);
} }
} }
/**
* label 4-connected components on image
* (slow algorythm, but easy to parallel)
*
* @param I (i) - image ("packed")
* @param W,H - size of the image (W - width in pixels)
* @param CC (o) - connected components boxes
* @return an array of labeled components
*/
size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){
size_t *assoc;
if(W < MINWIDTH || H < MINHEIGHT) return NULL; if(W < MINWIDTH || H < MINHEIGHT) return NULL;
uint8_t *f = filter4(Img, W, H); // remove all non 4-connected pixels uint8_t *f = filter4(Img, W, H); // remove all non 4-connected pixels
//DBG("convert to size_t"); //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(found){ // there's a pixel to the left
if(U && U != curmark){ // meet old mark -> remark one of them in assoc[] if(U && U != curmark){ // meet old mark -> remark one of them in assoc[]
TEST("(%d, %d): remark %zd --> %zd\n", x, y, U, curmark); 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) curmark = U; // change curmark to upper mark (to reduce further checks)
} }
}else{ // new mark -> change curmark }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].xmin = W;
boxes[i].ymin = H; 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) #pragma omp parallel shared(boxes)
{ {
Box *l_boxes = MALLOC(Box, cidx); Box *l_boxes = MALLOC(Box, cidx);
@ -507,60 +490,6 @@ size_t *cclabel8(size_t *labels, int W, int H, size_t *Nobj){
} }
#endif #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 =================== * <=================== CONNECTED COMPONENTS LABELING ===================
*/ */

View File

@ -60,26 +60,12 @@ uint8_t *filter4(uint8_t *image, int W, int H);
uint8_t *filter8(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 *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 #if 0
size_t *cclabel8(uint8_t *Img, int W, int H, size_t *Nobj);
// logical operations // logical operations
uint8_t *imand(uint8_t *im1, uint8_t *im2, int W, int H); 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); 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
#endif // BINMORPH_H__ #endif // BINMORPH_H__

View File

@ -20,10 +20,10 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <usefull_macros.h>
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "fits.h" #include "fits.h"
#include "grasshopper.h" #include "grasshopper.h"
#include "imagefile.h" #include "imagefile.h"
@ -132,31 +132,19 @@ static void recalcexp(Image *I){
exptime = theconf.maxexp; exptime = theconf.maxexp;
return; return;
} }
if(I->minval < 0. || I->maxval > 255.1){ size_t *histogram = get_histogram(I);
DBG("Bad image data: min=%g, max=%g", I->minval, I->maxval); if(!histogram){
WARNX("Can't calculate histogram");
return; return;
} }
int wh = I->width * I->height; int idx100;
int histogram[256] = {0}; size_t sum100 = 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;
for(idx100 = 255; idx100 >= 0; --idx100){ for(idx100 = 255; idx100 >= 0; --idx100){
sum100 += histogram[idx100]; sum100 += histogram[idx100];
if(sum100 > 100) break; 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 > 230 && idx100 < 253) return; // good values
if(idx100 > 253){ // exposure too long if(idx100 > 253){ // exposure too long
calcexpgain(0.7*exptime); calcexpgain(0.7*exptime);
@ -248,13 +236,25 @@ int camcapture(void (*process)(Image*)){
FREE(oIma->data); FREE(oIma->data);
FREE(oIma); FREE(oIma);
} }
if(oIma){
FREE(oIma->data);
FREE(oIma);
}
camdisconnect(); camdisconnect();
DBG("CAMCAPTURE: out"); DBG("CAMCAPTURE: out");
return 1; 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){ char *camstatus(const char *messageid, char *buf, int buflen){
if(!buf || buflen < 2) return NULL;
if(!messageid) messageid = "unknown";
static char *impath = NULL; static char *impath = NULL;
if(!impath){ if(!impath){
if(!(impath = realpath(GP->outputjpg, impath))){ if(!(impath = realpath(GP->outputjpg, impath))){
@ -263,9 +263,13 @@ char *camstatus(const char *messageid, char *buf, int buflen){
} }
DBG("path: %s", impath); DBG("path: %s", impath);
} }
float xc, yc;
getcenter(&xc, &yc);
snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"%sconnected\", \"impath\": \"%s\", \"imctr\": %llu, " 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(), 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; return buf;
} }

View File

@ -15,11 +15,12 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#ifndef CAMERACAPTURE_H__ #ifndef CAMERACAPTURE_H__
#define CAMERACAPTURE_H__ #define CAMERACAPTURE_H__
#include "fits.h" // Image*
#include "imagefile.h" // Image
// format of single frame // format of single frame
typedef struct{ typedef struct{

View File

@ -23,10 +23,10 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <math.h> #include <math.h>
#include <usefull_macros.h>
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "improc.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)")}, {"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 ")")}, {"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)")}, {"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")}, {"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.)")}, // {"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")}, {"equalize", NO_ARGS, NULL, 'e', arg_int, APTR(&G.equalize), _("make historam equalization of saved jpeg")},

View File

@ -19,10 +19,10 @@
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <usefull_macros.h>
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
static char *conffile = NULL; // configuration file name static char *conffile = NULL; // configuration file name
@ -192,12 +192,12 @@ static char *read_key(FILE *file, char value[128]){
char *line = NULL; char *line = NULL;
size_t n = 0; size_t n = 0;
int got = getline(&line, &n, file); int got = getline(&line, &n, file);
if(!line) return NULL;
if(got < 0){ if(got < 0){
FREE(line); free(line);
return NULL; return NULL;
} }
char *kv = get_keyval(line, value); char *kv = get_keyval(line, value);
FREE(line);
return kv; return kv;
} }
@ -267,7 +267,7 @@ confparam *chk_keyval(const char *key, const char *val, key_value *result){
*/ */
int chkconfig(const char *confname){ int chkconfig(const char *confname){
DBG("Config name: %s", confname); DBG("Config name: %s", confname);
FREE(conffile); if(conffile){ free(conffile); conffile = NULL; }
conffile = strdup(confname); conffile = strdup(confname);
FILE *f = fopen(confname, "r"); FILE *f = fopen(confname, "r");
int ret = TRUE; int ret = TRUE;
@ -283,7 +283,8 @@ int chkconfig(const char *confname){
} }
while((key = read_key(f, val))){ while((key = read_key(f, val))){
if(*key == '#'){ if(*key == '#'){
FREE(key); free(key);
key = NULL;
continue; // comment continue; // comment
} }
//DBG("key: %s", key); //DBG("key: %s", key);
@ -291,7 +292,8 @@ int chkconfig(const char *confname){
par = chk_keyval(key, val, &kv); par = chk_keyval(key, val, &kv);
if(!par){ if(!par){
WARNX("Parameter '%s' is wrong or out of range", key); WARNX("Parameter '%s' is wrong or out of range", key);
FREE(key); free(key);
key = NULL;
continue; continue;
} }
switch(par->type){ switch(par->type){
@ -303,7 +305,8 @@ int chkconfig(const char *confname){
break; break;
} }
++par->got; ++par->got;
FREE(key); free(key);
key = NULL;
} }
fclose(f); fclose(f);
int found = 0; int found = 0;
@ -321,34 +324,6 @@ int chkconfig(const char *confname){
} }
++found; ++par; ++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); DBG("chkconfig(): found %d", found);
return ret; return ret;
} }

View File

@ -42,12 +42,12 @@
#define BRIGHT_MIN (0.) #define BRIGHT_MIN (0.)
#define BRIGHT_MAX (10.) #define BRIGHT_MAX (10.)
// max average images counter // max average images counter
#define NAVER_MAX (50) #define NAVER_MAX (25)
// coefficients to convert dx,dy to du,dv // coefficients to convert dx,dy to du,dv
#define KUVMIN (-5000.) #define KUVMIN (-5000.)
#define KUVMAX (5000.) #define KUVMAX (5000.)
// default coefficient for corrections (move to Kdu, Kdv instead of du, dv) // default coefficient for corrections (move to Kdu, Kdv instead of du, dv)
#define KCORR (0.97) #define KCORR (0.90)
// min/max median seed // min/max median seed
#define MIN_MEDIAN_SEED (1) #define MIN_MEDIAN_SEED (1)
#define MAX_MEDIAN_SEED (7) #define MAX_MEDIAN_SEED (7)

57
LocCorr/debug.c Normal file
View File

@ -0,0 +1,57 @@
/*
* This file is part of the loccorr project.
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifdef EBUG
#include <string.h>
#include <unistd.h>
#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

53
LocCorr/debug.h Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of the loccorr project.
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef DEBUG_H__
#define DEBUG_H__
#include <usefull_macros.h>
#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__

View File

@ -33,6 +33,12 @@ OMP_FOR()
for(int y = 1; y < h; y++) for(int y = 1; y < h; y++)
#endif #endif
{ {
#ifdef IM_UP
int y = 0;
#endif
#ifdef IM_DOWN
int y = h;
#endif
uint8_t *iptr = &image[W0*y]; uint8_t *iptr = &image[W0*y];
uint8_t *optr = &ret[W0*y]; uint8_t *optr = &ret[W0*y];
uint8_t p = DIL[*iptr] uint8_t p = DIL[*iptr]

View File

@ -16,11 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// simplest interface to draw lines & ellipsis // simplest interface to draw lines & ellipses
#include "debug.h"
#include "draw.h" #include "draw.h"
#include "fits.h" #include "fits.h"
#include <usefull_macros.h>
// base colors: // base colors:
const uint8_t const uint8_t
@ -46,13 +46,35 @@ void Pattern_free(Pattern **p){
Pattern *Pattern_cross(int h, int w){ Pattern *Pattern_cross(int h, int w){
int s = h*w, hmid = h/2, wmid = w/2; int s = h*w, hmid = h/2, wmid = w/2;
uint8_t *data = MALLOC(uint8_t, s); 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]; uint8_t *ptr = &data[wmid];
for(int y = 0; y < h; ++y, ptr += w) *ptr = 255; for(int y = 0; y < h; ++y, ptr += w) *ptr = 255;
ptr = &data[hmid*w]; ptr = &data[hmid*w];
for(int x = 0; x < w; ++x, ++ptr) *ptr = 255; 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); Pattern *p = MALLOC(Pattern, 1);
p->data = data; p->data = data;
p->h = h; p->w = w; 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; return p;
} }
@ -63,7 +85,8 @@ Pattern *Pattern_cross(int h, int w){
* @param xc, yc - coordinates of pattern center @ image * @param xc, yc - coordinates of pattern center @ image
* @param colr - color to draw pattern (when opaque == 255) * @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 xul = xc - p->w/2, yul = yc - p->h/2;
int xdr = xul+p->w-1, ydr = yul+p->h-1; int xdr = xul+p->w-1, ydr = yul+p->h-1;
int R = img->w, D = img->h; // right and down border coordinates + 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 *in = &p->data[(iylow+y-oylow)*p->w + ixlow]; // opaque component
uint8_t *out = &img->data[(y*img->w + oxlow)*3]; // 3-colours uint8_t *out = &img->data[(y*img->w + oxlow)*3]; // 3-colours
for(int x = oxlow; x < oxhigh; ++x, ++in, out += 3){ 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){ for(int c = 0; c < 3; ++c){
out[c] = (uint8_t)(colr[c] * opaque + out[c]*(1.-opaque)); out[c] = (uint8_t)(colr[c] * opaque + out[c]*(1.-opaque));
} }

View File

@ -28,17 +28,6 @@ typedef struct{
int h; // height int h; // height
} Img3; } 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 // opaque pattern for drawing
typedef struct{ typedef struct{
uint8_t *data; uint8_t *data;
@ -50,7 +39,8 @@ typedef struct{
extern const uint8_t C_R[], C_G[], C_B[], C_K[], C_W[]; extern const uint8_t C_R[], C_G[], C_B[], C_K[], C_W[];
void Pattern_free(Pattern **p); 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_cross(int h, int w);
Pattern *Pattern_xcross(int h, int w);
#endif // DRAW_H__ #endif // DRAW_H__

View File

@ -23,6 +23,12 @@ OMP_FOR()
for(int y = 1; y < h; y++) for(int y = 1; y < h; y++)
#endif #endif
{ {
#ifdef IM_UP
int y = 0;
#endif
#ifdef IM_DOWN
int y = h;
#endif
uint8_t *iptr = &image[W0*y]; uint8_t *iptr = &image[W0*y];
uint8_t *optr = &ret[W0*y]; uint8_t *optr = &ret[W0*y];
// x=0 // x=0

View File

@ -23,6 +23,12 @@ OMP_FOR()
for(int y = 1; y < h; y++) for(int y = 1; y < h; y++)
#endif #endif
{ {
#ifdef IM_UP
int y = 0;
#endif
#ifdef IM_DOWN
int y = h;
#endif
uint8_t *iptr = &image[W0*y]; uint8_t *iptr = &image[W0*y];
uint8_t *optr = &ret[W0*y]; uint8_t *optr = &ret[W0*y];
// x=0 // x=0

View File

@ -18,9 +18,9 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <usefull_macros.h>
#include <math.h> #include <math.h>
#include "debug.h"
#include "fits.h" #include "fits.h"
static int fitsstatus = 0; static int fitsstatus = 0;
@ -56,12 +56,40 @@ void Image_free(Image **img){
FREE(*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){ bool FITS_read(const char *filename, Image **fits){
FNAME(); FNAME();
bool ret = TRUE; bool ret = TRUE;
fitsfile *fp; fitsfile *fp;
int i, j, hdunum, hdutype, nkeys, keypos; int i, j, hdunum, hdutype, nkeys, keypos;
int naxis; int naxis, dtype;
long naxes[2]; long naxes[2];
char card[FLEN_CARD]; char card[FLEN_CARD];
Image *img = MALLOC(Image, 1); Image *img = MALLOC(Image, 1);
@ -75,7 +103,7 @@ bool FITS_read(const char *filename, Image **fits){
goto returning; goto returning;
} }
// get image dimensions // 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); DBG("Image have %d axis", naxis);
if(naxis > 2){ if(naxis > 2){
WARNX(_("Images with > 2 dimensions are not supported")); 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->width = naxes[0];
img->height = naxes[1]; 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 // loop through all HDUs
for(i = 1; !(fits_movabs_hdu(fp, i, &hdutype, &fitsstatus)); ++i){ for(i = 1; !(fits_movabs_hdu(fp, i, &hdutype, &fitsstatus)); ++i){
TRYFITS(fits_get_hdrpos, fp, &nkeys, &keypos); 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]; size_t sz = naxes[0] * naxes[1];
img->data = MALLOC(Imtype, sz); img->data = MALLOC(Imtype, sz);
float *targ = MALLOC(float, sz);
int stat = 0; int stat = 0;
TRYFITS(fits_read_img, fp, FITSDATATYPE, 1, sz, NULL, img->data, &stat); TRYFITS(fits_read_img, fp, TFLOAT, 1, sz, NULL, targ, &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);
if(stat) WARNX(_("Found %d pixels with undefined value"), stat); if(stat) WARNX(_("Found %d pixels with undefined value"), stat);
convflt2ima(targ, img);
FREE(targ);
DBG("ready"); DBG("ready");
returning: returning:
FITSFUN(fits_close_file, fp); FITSFUN(fits_close_file, fp);
if(!ret){ if(!ret || !fits){
Image_free(&img); Image_free(&img);
} }else *fits = img;
if(fits) *fits = img;
return ret; return ret;
} }
@ -143,63 +165,8 @@ bool FITS_write(const char *filename, const Image *fits){
fitsfile *fp; fitsfile *fp;
TRYFITS(fits_create_file, &fp, filename); TRYFITS(fits_create_file, &fp, filename);
TRYFITS(fits_create_img, fp, fits->dtype, 2, naxes); TRYFITS(fits_create_img, fp, SHORT_IMG, 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");
}
if(keys){ // there's keys if(keys){ // there's keys
size_t i; size_t i;
char **records = fits->keylist; 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"); FITSFUN(fits_write_record, fp, "COMMENT modified by loccorr");
fitsstatus = 0; fitsstatus = 0;
fits_write_img(fp, FITSDATATYPE, 1, sz, outp, &fitsstatus); fits_write_img(fp, TBYTE, 1, sz, fits->data, &fitsstatus);
if(need2free) FREE(outp);
if(fitsstatus){ if(fitsstatus){
fits_report_error(stderr, fitsstatus); fits_report_error(stderr, fitsstatus);
return FALSE; return FALSE;

View File

@ -22,31 +22,9 @@
#include <fitsio.h> #include <fitsio.h>
#include <omp.h> #include <omp.h>
#include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#define Stringify(x) #x #include "imagefile.h"
#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;
void Image_free(Image **ima); void Image_free(Image **ima);
bool FITS_read(const char *filename, Image **fits); bool FITS_read(const char *filename, Image **fits);

View File

@ -22,9 +22,9 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <usefull_macros.h>
#include "config.h" #include "config.h"
#include "debug.h"
#include "grasshopper.h" #include "grasshopper.h"
#include "imagefile.h" #include "imagefile.h"
@ -32,8 +32,12 @@ static fc2Context context;
static fc2PGRGuid guid; static fc2PGRGuid guid;
static fc2Error err = FC2_ERROR_OK; 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__))){ \ #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(){ static void disconnect(){
fc2DestroyContext(context); fc2DestroyContext(context);
@ -146,6 +150,7 @@ static int geometrylimits(frameformat *max, frameformat *step){
} }
static int getformat(frameformat *fmt){ static int getformat(frameformat *fmt){
if(!fmt) return FALSE;
unsigned int packsz; float pc; unsigned int packsz; float pc;
fc2Format7ImageSettings f7; fc2Format7ImageSettings f7;
FC2FN(fc2GetFormat7Configuration, &f7, &packsz, &pc); FC2FN(fc2GetFormat7Configuration, &f7, &packsz, &pc);
@ -155,7 +160,7 @@ static int getformat(frameformat *fmt){
} }
static int changeformat(frameformat *fmt){ static int changeformat(frameformat *fmt){
FNAME(); if(!fmt) return FALSE;
BOOL b; BOOL b;
fc2Format7ImageSettings f7; fc2Format7ImageSettings f7;
f7.mode = FC2_MODE_0; f7.mode = FC2_MODE_0;
@ -203,7 +208,7 @@ static int connect(){
} }
static int GrabImage(fc2Image *convertedImage){ static int GrabImage(fc2Image *convertedImage){
//FNAME(); if(!convertedImage) return FALSE;
int ret = FALSE; int ret = FALSE;
fc2Image rawImage; fc2Image rawImage;
// start capture // start capture
@ -211,7 +216,8 @@ static int GrabImage(fc2Image *convertedImage){
err = fc2CreateImage(&rawImage); err = fc2CreateImage(&rawImage);
if(err != FC2_ERROR_OK){ if(err != FC2_ERROR_OK){
WARNX("Error in fc2CreateImage: %s", fc2ErrorToDescription(err)); WARNX("Error in fc2CreateImage: %s", fc2ErrorToDescription(err));
goto rtn; fc2StopCapture(context);
return FALSE;
} }
// Retrieve the image // Retrieve the image
err = fc2RetrieveBuffer(context, &rawImage); err = fc2RetrieveBuffer(context, &rawImage);

View File

@ -22,7 +22,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <usefull_macros.h>
#include <stb/stb_image.h> #include <stb/stb_image.h>
#include <stb/stb_image_write.h> #include <stb/stb_image_write.h>
@ -31,7 +30,9 @@
#include "cameracapture.h" #include "cameracapture.h"
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "draw.h" #include "draw.h"
#include "fits.h"
#include "grasshopper.h" #include "grasshopper.h"
#include "imagefile.h" #include "imagefile.h"
#include "median.h" #include "median.h"
@ -68,6 +69,11 @@ static char *hexdmp(const char sig[8]){
} }
#endif #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){ static InputType imtype(FILE *f){
char signature[8]; char signature[8];
int x = fread(signature, 1, 7, f); int x = fread(signature, 1, 7, f);
@ -122,37 +128,22 @@ InputType chkinput(const char *name){
return tp; return tp;
} }
Image *u8toImage(uint8_t *data, int width, int height, int stride){ /**
FNAME(); * @brief u8toImage - convert uint8_t data to Image structure (flipping upside down for FITS coordinates)
Image *outp = MALLOC(Image, 1); * @param data - original image data
outp->width = width; * @param width - image width
outp->height = height; * @param height - image height
outp->dtype = FLOAT_IMG; * @param stride - image width with alignment
/* * @return Image structure (fully allocated, you can FREE(data) after it)
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]);
*/ */
Image *u8toImage(const uint8_t *data, int width, int height, int stride){
outp->data = MALLOC(Imtype, width*height); FNAME();
Image *outp = Image_new(width, height);
// flip image updown for FITS coordinate system // flip image updown for FITS coordinate system
OMP_FOR() OMP_FOR()
for(int y = 0; y < height; ++y){ for(int y = 0; y < height; ++y){
Imtype *Out = &outp->data[(height-1-y)*width]; 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){ for(int x = 0; x < width; ++x){
*Out++ = (Imtype)(*In++); *Out++ = (Imtype)(*In++);
} }
@ -161,15 +152,21 @@ Image *u8toImage(uint8_t *data, int width, int height, int stride){
return outp; 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; int width, height, channels;
uint8_t *img = stbi_load(name, &width, &height, &channels, 1); uint8_t *img = stbi_load(name, &width, &height, &channels, 1);
if(!img){ if(!img){
WARNX("Error in loading the image %s\n", name); WARNX("Error in loading the image %s\n", name);
return NULL; 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 * @return data allocated here
*/ */
Image *Image_new(int w, int h){ Image *Image_new(int w, int h){
if(w < 1 || h < 1) return NULL;
Image *outp = MALLOC(Image, 1); Image *outp = MALLOC(Image, 1);
outp->width = w; outp->width = w;
outp->height = h; outp->height = h;
@ -213,24 +211,99 @@ Image *Image_new(int w, int h){
*/ */
Image *Image_sim(const Image *i){ Image *Image_sim(const Image *i){
if(!i) return NULL; if(!i) return NULL;
if((i->width * i->height) < 1) return NULL;
Image *outp = Image_new(i->width, i->height); Image *outp = Image_new(i->width, i->height);
outp->dtype = i->dtype;
return outp; 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 I - input image
* @param nchannels - 1 or 3 colour channels * @param nchannels - 1 or 3 colour channels
* @return allocated here image for jpeg/png storing * @return allocated here image for jpeg/png storing
*/ */
uint8_t *linear(const Image *I, int nchannels){ // only 1 and 3 channels supported! 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; int width = I->width, height = I->height;
size_t stride = width*nchannels, S = height*stride; size_t stride = width*nchannels, S = height*stride;
uint8_t *outp = MALLOC(uint8_t, S); 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); //DBG("make linear transform %dx%d, %d channels", I->width, I->height, nchannels);
if(nchannels == 3){ if(nchannels == 3){
OMP_FOR() 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]; uint8_t *Out = &outp[(height-1-y)*stride];
Imtype *In = &I->data[y*width]; Imtype *In = &I->data[y*width];
for(int x = 0; x < width; ++x){ 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; 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]; uint8_t *Out = &outp[(height-1-y)*width];
Imtype *In = &I->data[y*width]; Imtype *In = &I->data[y*width];
for(int x = 0; x < width; ++x){ 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 * @return allocated here image for jpeg/png storing
*/ */
uint8_t *equalize(const Image *I, int nchannels, double throwpart){ 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; int width = I->width, height = I->height;
size_t stride = width*nchannels, S = height*stride; size_t stride = width*nchannels, S = height*stride;
uint8_t *lin = linear(I, 1); size_t *orig_histo = get_histogram(I); // original hystogram (linear)
if(!lin) return NULL; if(!orig_histo) return NULL;
uint8_t *outp = MALLOC(uint8_t, S); 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] uint8_t eq_levls[256] = {0}; // levels to convert: newpix = eq_levls[oldpix]
int s = width*height; int s = width*height;
for(int i = 0; i < s; ++i){ int Nblack = 0, bpart = (int)(throwpart * (double)s);
++orig_hysto[lin[i]];
}
int Nblack = 0, bpart = (int)(throwpart * s);
int startidx; int startidx;
// remove first part of black pixels // remove first part of black pixels
for(startidx = 0; startidx < 256; ++startidx){ for(startidx = 0; startidx < 256; ++startidx){
Nblack += orig_hysto[startidx]; Nblack += orig_histo[startidx];
if(Nblack >= bpart) break; if(Nblack >= bpart) break;
} }
++startidx; ++startidx;
@ -290,15 +358,9 @@ uint8_t *equalize(const Image *I, int nchannels, double throwpart){
if(Nwhite >= wpart) break; if(Nwhite >= wpart) break;
}*/ }*/
//DBG("Throw %d (real: %d black) pixels, startidx=%d", bpart, Nblack, startidx); //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.; double part = (double)(s + 1. - Nblack) / 256., N = 0.;
for(int i = startidx; i < 256; ++i){ for(int i = startidx; i < 256; ++i){
N += orig_hysto[i]; N += orig_histo[i];
eq_levls[i] = (uint8_t)(N/part); eq_levls[i] = (uint8_t)(N/part);
} }
//for(int i = stopidx; i < 256; ++i) eq_levls[i] = 255; //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){ if(nchannels == 3){
OMP_FOR() OMP_FOR()
for(int y = 0; y < height; ++y){ for(int y = 0; y < height; ++y){
uint8_t *Out = &outp[y*stride]; uint8_t *Out = &outp[(height-1-y)*stride];
uint8_t *In = &lin[y*width]; Imtype *In = &I->data[y*width];
for(int x = 0; x < width; ++x){ for(int x = 0; x < width; ++x){
Out[0] = Out[1] = Out[2] = eq_levls[*In++]; Out[0] = Out[1] = Out[2] = eq_levls[*In++];
Out += 3; Out += 3;
@ -319,14 +381,14 @@ uint8_t *equalize(const Image *I, int nchannels, double throwpart){
}else{ }else{
OMP_FOR() OMP_FOR()
for(int y = 0; y < height; ++y){ for(int y = 0; y < height; ++y){
uint8_t *Out = &outp[y*width]; uint8_t *Out = &outp[(height-1-y)*width];
uint8_t *In = &lin[y*width]; Imtype *In = &I->data[y*width];
for(int x = 0; x < width; ++x){ for(int x = 0; x < width; ++x){
*Out++ = eq_levls[*In++]; *Out++ = eq_levls[*In++];
} }
} }
} }
FREE(lin); FREE(orig_histo);
return outp; return outp;
} }
@ -344,6 +406,7 @@ int Image_write_jpg(const Image *I, const char *name, int eq){
outp = equalize(I, 1, theconf.throwpart); outp = equalize(I, 1, theconf.throwpart);
else else
outp = linear(I, 1); outp = linear(I, 1);
if(!outp) return 0;
//DBG("Try to write %s", name); //DBG("Try to write %s", name);
char *tmpnm = MALLOC(char, strlen(name) + 5); char *tmpnm = MALLOC(char, strlen(name) + 5);
sprintf(tmpnm, "%s-tmp", name); sprintf(tmpnm, "%s-tmp", name);
@ -372,8 +435,9 @@ void Image_minmax(Image *I){
int min_p = min, max_p = min; int min_p = min, max_p = min;
#pragma omp for nowait #pragma omp for nowait
for(int i = 0; i < wh; ++i){ for(int i = 0; i < wh; ++i){
if(I->data[i] < min_p) min_p = I->data[i]; Imtype pixval = I->data[i];
else if(I->data[i] > max_p) max_p = I->data[i]; if(pixval < min_p) min_p = pixval;
else if(pixval > max_p) max_p = pixval;
} }
#pragma omp critical #pragma omp critical
{ {
@ -383,27 +447,26 @@ void Image_minmax(Image *I){
} }
I->maxval = max; I->maxval = max;
I->minval = min; 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 IMAGE TYPES ===================>
*/ */
// convert binarized image into floating
/** /**
* @brief bin2Im - convert binarized image into floating * @brief bin2Im - convert binarized image into floating
* @param image - binarized image * @param image - binarized image
* @param W, H - its size (in pixels!) * @param W, H - its size (in pixels!)
* @return Image structure * @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); Image *ret = Image_new(W, H);
int stride = (W + 7) / 8, s1 = (stride*8 == W) ? stride : stride - 1; int stride = (W + 7) / 8, s1 = (stride*8 == W) ? stride : stride - 1;
OMP_FOR() OMP_FOR()
for(int y = 0; y < H; y++){ for(int y = 0; y < H; y++){
Imtype *optr = &ret->data[y*W]; 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++){ for(int x = 0; x < s1; x++){
register uint8_t inp = *iptr++; register uint8_t inp = *iptr++;
for(int i = 0; i < 8; ++i){ 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; int rest = W - s1*8;
if(rest){
register uint8_t inp = *iptr; register uint8_t inp = *iptr;
for(int i = 0; i < rest; ++i){ for(int i = 0; i < rest; ++i){
*optr++ = (inp & 0x80) ? 1. : 0; *optr++ = (inp & 0x80) ? 1. : 0;
inp <<= 1; inp <<= 1;
} }
} }
ret->dtype = BYTE_IMG; }
ret->minval = 0; ret->minval = 0;
ret->maxval = 1; ret->maxval = 1;
return ret; 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 im (i) - image to convert
* @param stride (o) - new width of image * @param stride (o) - new width of image
* @param bk - background level (all values < bk will be 0, other will be 1) * @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; int y, W0 = (W + 7) / 8, s1 = (W/8 == W0) ? W0 : W0 - 1;
uint8_t *ret = MALLOC(uint8_t, W0 * H); uint8_t *ret = MALLOC(uint8_t, W0 * H);
OMP_FOR() OMP_FOR()
for(y = 0; y < H; y++){ for(y = 0; y < H; ++y){
Imtype *iptr = &im->data[y*W]; Imtype *iptr = &im->data[y*W];
uint8_t *optr = &ret[y*W0]; uint8_t *optr = &ret[y*W0];
register uint8_t o;
for(int x = 0; x < s1; ++x){ for(int x = 0; x < s1; ++x){
o = 0; register uint8_t o = 0;
for(int i = 0; i < 8; ++i){ for(int i = 0; i < 8; ++i){
o <<= 1; o <<= 1;
if(*iptr++ > bk) o |= 1; if(*iptr++ > bk) o |= 1;
} }
*optr++ = o; *optr++ = o;
} }
int rest = 7 - (W - s1*8); int rest = W - s1*8;
if(rest < 7){ if(rest){
o = 0; register uint8_t o = 0;
for(int x = 7; x > rest; --x){ for(int x = 0; x < rest; ++x){
if(*iptr++ > 0.) o |= 1<<x; o <<= 1;
if(*iptr++ > bk) o |= 1;
} }
*optr = o; *optr = o << (8 - rest);
//*optr = o | 1<<rest; // mark outern right edge (for good CC labeling)
} }
} }
return ret; return ret;
} }
// convert size_t labels into floating #if 0
Image *ST2Im(size_t *image, int W, int H){ UNUSED function! Need to be refactored
// convert size_t labels into Image
Image *ST2Im(const size_t *image, int W, int H){
Image *ret = Image_new(W, H); Image *ret = Image_new(W, H);
OMP_FOR() OMP_FOR()
for(int y = 0; y < H; ++y){ for(int y = 0; y < H; ++y){
Imtype *optr = &ret->data[y*W]; Imtype *optr = &ret->data[y*W];
size_t *iptr = &image[y*W]; const size_t *iptr = &image[y*W];
for(int x = 0; x < W; ++x){ for(int x = 0; x < W; ++x){
*optr++ = (Imtype)*iptr++; *optr++ = (Imtype)*iptr++;
} }
} }
ret->dtype = FLOAT_IMG;
Image_minmax(ret); Image_minmax(ret);
return ret; return ret;
} }
#endif
/** /**
* Convert "packed" image into size_t array for conncomp procedure * 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 * @param W, H - size of image in pixels
* @return allocated memory area with copy of an image * @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); size_t *ret = MALLOC(size_t, W * H);
int W0 = (W + 7) / 8, s1 = W0 - 1; int W0 = (W + 7) / 8, s1 = W0 - 1;
OMP_FOR() OMP_FOR()
for(int y = 0; y < H; y++){ for(int y = 0; y < H; y++){
size_t *optr = &ret[y*W]; 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){ for(int x = 0; x < s1; ++x){
register uint8_t inp = *iptr++; register uint8_t inp = *iptr++;
for(int i = 0; i < 8; ++i){ for(int i = 0; i < 8; ++i){
@ -500,12 +565,14 @@ size_t *bin2ST(uint8_t *image, int W, int H){
} }
} }
int rest = W - s1*8; int rest = W - s1*8;
if(rest){
register uint8_t inp = *iptr; register uint8_t inp = *iptr;
for(int i = 0; i < rest; ++i){ for(int i = 0; i < rest; ++i){
*optr++ = (inp & 0x80) ? 1 : 0; *optr++ = (inp & 0x80) ? 1 : 0;
inp <<= 1; inp <<= 1;
} }
} }
}
return ret; return ret;
} }

View File

@ -20,8 +20,24 @@
#define IMAGEFILE_H__ #define IMAGEFILE_H__
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> // 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 // input file/directory type
typedef enum{ typedef enum{
@ -46,11 +62,13 @@ Image *Image_new(int w, int h);
Image *Image_sim(const Image *i); Image *Image_sim(const Image *i);
void Image_free(Image **I); void Image_free(Image **I);
int Image_write_jpg(const Image *I, const char *name, int equalize); 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 *u8toImage(const uint8_t *data, int width, int height, int stride);
Image *bin2Im(uint8_t *image, int W, int H); Image *bin2Im(const uint8_t *image, int W, int H);
uint8_t *Im2bin(const Image *im, Imtype bk); uint8_t *Im2bin(const Image *im, Imtype bk);
size_t *bin2ST(uint8_t *image, int W, int H); size_t *bin2ST(const uint8_t *image, int W, int H);
Image *ST2Im(size_t *image, int W, int H); //Image *ST2Im(const size_t *image, int W, int H);
#endif // IMAGEFILE_H__ #endif // IMAGEFILE_H__

View File

@ -21,13 +21,13 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <usefull_macros.h>
#include "basler.h" #include "basler.h"
#include "binmorph.h" #include "binmorph.h"
#include "cameracapture.h" #include "cameracapture.h"
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "draw.h" #include "draw.h"
#include "grasshopper.h" #include "grasshopper.h"
#include "fits.h" #include "fits.h"
@ -47,6 +47,7 @@ steppersproc *theSteppers = NULL;
static FILE *fXYlog = NULL; static FILE *fXYlog = NULL;
static double tstart = 0.; // time of logging start static double tstart = 0.; // time of logging start
static double FPS = 0.; // frames per second static double FPS = 0.; // frames per second
static float xc = -1., yc = -1.; // center coordinates
typedef struct{ typedef struct{
uint32_t area; // object area in pixels uint32_t area; // object area in pixels
@ -115,7 +116,7 @@ static void XYnewline(){
static void getDeviation(object *curobj){ static void getDeviation(object *curobj){
int averflag = 0; 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 xx = curobj->xc, yy = curobj->yc, xsum2 = 0., ysum2 = 0.;
double Sx = 0., Sy = 0.; double Sx = 0., Sy = 0.;
static int counter = 0; static int counter = 0;
@ -126,23 +127,24 @@ static void getDeviation(object *curobj){
curobj->xsigma, curobj->ysigma, curobj->WdivH); curobj->xsigma, curobj->ysigma, curobj->WdivH);
} }
//DBG("counter = %d", counter); //DBG("counter = %d", counter);
if(++counter != theconf.naverage){ if(++counter < theconf.naverage){
goto process_corrections; goto process_corrections;
} }
// it's time to calculate average deviations // it's time to calculate average deviations
counter = 0; xx = 0.; yy = 0.; xx = 0.; yy = 0.;
for(int i = 0; i < theconf.naverage; ++i){ for(int i = 0; i < counter; ++i){
double x = Xc[i], y = Yc[i]; double x = Xc[i], y = Yc[i];
xx += x; yy += y; xx += x; yy += y;
xsum2 += x*x; ysum2 += y*y; xsum2 += x*x; ysum2 += y*y;
} }
xx /= theconf.naverage; yy /= theconf.naverage; xx /= counter; yy /= counter;
Sx = sqrt(xsum2/theconf.naverage - xx*xx); Sx = sqrt(xsum2/counter - xx*xx);
Sy = sqrt(ysum2/theconf.naverage - yy*yy); Sy = sqrt(ysum2/counter - yy*yy);
counter = 0;
#ifdef EBUG #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 #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; averflag = 1;
if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy); if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy);
process_corrections: process_corrections:
@ -156,7 +158,6 @@ process_corrections:
} }
void process_file(Image *I){ void process_file(Image *I){
FNAME();
static double lastTproc = 0.; static double lastTproc = 0.;
/* /*
#ifdef EBUG #ifdef EBUG
@ -176,12 +177,11 @@ void process_file(Image *I){
return; return;
} }
int W = I->width, H = I->height; int W = I->width, H = I->height;
if(!I->dtype) I->dtype = FLOAT_IMG;
//save_fits(I, "fitsout.fits"); //save_fits(I, "fitsout.fits");
//DELTA("Save original"); //DELTA("Save original");
Imtype bk; Imtype bk;
if(calc_background(I, &bk)){ if(calc_background(I, &bk)){
DBG("backgr = %g", bk); DBG("backgr = %d", bk);
DELTA("Got background"); DELTA("Got background");
uint8_t *ibin = Im2bin(I, bk); uint8_t *ibin = Im2bin(I, bk);
DELTA("Made binary"); DELTA("Made binary");
@ -201,14 +201,14 @@ void process_file(Image *I){
ConnComps *cc = NULL; ConnComps *cc = NULL;
size_t *S = cclabel4(opn, W, H, &cc); size_t *S = cclabel4(opn, W, H, &cc);
FREE(opn); 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); object *Objects = MALLOC(object, cc->Nobj-1);
int objctr = 0; int objctr = 0;
for(size_t i = 1; i < cc->Nobj; ++i){ for(size_t i = 1; i < cc->Nobj; ++i){
Box *b = &cc->boxes[i]; Box *b = &cc->boxes[i];
double wh = ((double)b->xmax - b->xmin)/(b->ymax - b->ymin); double wh = ((double)b->xmax - b->xmin)/(b->ymax - b->ymin);
//DBG("Obj# %zd: wh=%g, area=%d", i, wh, b->area); //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(wh < theconf.minwh || wh > theconf.maxwh) continue;
if((int)b->area < theconf.minarea || (int)b->area > theconf.maxarea) continue; if((int)b->area < theconf.minarea || (int)b->area > theconf.maxarea) continue;
double xc = 0., yc = 0.; double xc = 0., yc = 0.;
@ -239,13 +239,14 @@ void process_file(Image *I){
}; };
} }
DELTA("Labeling"); DELTA("Labeling");
DBG("T%zd, N=%d\n", time(NULL), objctr); DBGLOG("T%.2f, N=%d\n", dtime(), objctr);
if(objctr > 1){ if(objctr > 1){
if(theconf.starssort) if(theconf.starssort)
qsort(Objects, objctr, sizeof(object), compIntens); qsort(Objects, objctr, sizeof(object), compIntens);
else else
qsort(Objects, objctr, sizeof(object), compDist); qsort(Objects, objctr, sizeof(object), compDist);
} }
if(objctr){
#ifdef EBUG #ifdef EBUG
object *o = Objects; object *o = Objects;
green("%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%8s\n", green("%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%8s\n",
@ -258,6 +259,7 @@ void process_file(Image *I){
} }
#endif #endif
getDeviation(Objects); // calculate dX/dY and process corrections getDeviation(Objects); // calculate dX/dY and process corrections
}
{ // prepare image and save jpeg { // prepare image and save jpeg
uint8_t *outp = NULL; uint8_t *outp = NULL;
if(theconf.equalize) if(theconf.equalize)
@ -265,7 +267,7 @@ void process_file(Image *I){
else else
outp = linear(I, 3); outp = linear(I, 3);
static Pattern *cross = NULL; 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}; Img3 i3 = {.data = outp, .w = I->width, .h = H};
// draw fiber center position // draw fiber center position
Pattern_draw3(&i3, cross, theconf.xtarget-theconf.xoff, H-(theconf.ytarget-theconf.yoff), C_B); 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; int H = I->height;
// draw current star centroid // draw current star centroid
Pattern_draw3(&i3, cross, Objects[0].xc, H-Objects[0].yc, C_G); Pattern_draw3(&i3, cross, Objects[0].xc, H-Objects[0].yc, C_G);
xc = Objects[0].xc;
yc = Objects[0].yc;
// draw other centroids // draw other centroids
for(int i = 1; i < objctr; ++i) for(int i = 1; i < objctr; ++i)
Pattern_draw3(&i3, cross, Objects[i].xc, H-Objects[i].yc, C_R); 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); char *tmpnm = MALLOC(char, strlen(GP->outputjpg) + 5);
sprintf(tmpnm, "%s-tmp", GP->outputjpg); sprintf(tmpnm, "%s-tmp", GP->outputjpg);
if(stbi_write_jpg(tmpnm, I->width, I->height, 3, outp, 95)){ if(stbi_write_jpg(tmpnm, I->width, I->height, 3, outp, 95)){
@ -290,7 +293,11 @@ void process_file(Image *I){
FREE(outp); FREE(outp);
} }
FREE(Objects); 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(S);
FREE(cc); FREE(cc);
} }
@ -306,8 +313,8 @@ static char *localimages(const char *messageid, int isdir, char *buf, int buflen
if(!impath){ if(!impath){
if(!realpath(GP->outputjpg, impath)) impath = strdup(GP->outputjpg); if(!realpath(GP->outputjpg, impath)) impath = strdup(GP->outputjpg);
} }
snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"watch %s\", \"impath\": \"%s\"}", snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"watch %s\", \"impath\": \"%s\", \"xcenter\": %.1f, \"ycenter\": %.1f }",
MESSAGEID, messageid, isdir ? "directory" : "file", impath); MESSAGEID, messageid, isdir ? "directory" : "file", impath, xc, yc);
return buf; return buf;
} }
static char *watchdr(const char *messageid, char *buf, int buflen){ static char *watchdr(const char *messageid, char *buf, int buflen){
@ -383,3 +390,8 @@ void setpostprocess(const char *name){
} }
double getFramesPerS(){ return FPS; } double getFramesPerS(){ return FPS; }
void getcenter(float *x, float *y){
if(x) *x = xc;
if(y) *y = yc;
}

View File

@ -27,8 +27,6 @@
#define XY_TOLERANCE (5.) #define XY_TOLERANCE (5.)
#define PUSIROBO_POSTPROC "pusirobo" #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_bool stopwork;
extern volatile atomic_ullong ImNumber; extern volatile atomic_ullong ImNumber;
@ -54,5 +52,6 @@ void openXYlog(const char *name);
void closeXYlog(); void closeXYlog();
void setpostprocess(const char *name); void setpostprocess(const char *name);
double getFramesPerS(); double getFramesPerS();
void getcenter(float *x, float *y);
#endif // IMPROC_H__ #endif // IMPROC_H__

View File

@ -23,8 +23,8 @@
#include <sys/inotify.h> #include <sys/inotify.h>
#include <sys/select.h> #include <sys/select.h>
#include <unistd.h> #include <unistd.h>
#include <usefull_macros.h>
#include "debug.h"
#include "imagefile.h" #include "imagefile.h"
static char filenm[FILENAME_MAX]; static char filenm[FILENAME_MAX];

View File

@ -19,11 +19,12 @@
#include <math.h> #include <math.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> // signal #include <signal.h> // signal
#include <stdio.h>
#include <string.h> // strdup #include <string.h> // strdup
#include <usefull_macros.h>
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "grasshopper.h" #include "grasshopper.h"
#include "improc.h" #include "improc.h"
#include "pusirobo.h" #include "pusirobo.h"
@ -112,8 +113,8 @@ int main(int argc, char *argv[]){
if(GP->throwpart < 0. || GP->throwpart > 0.99){ if(GP->throwpart < 0. || GP->throwpart > 0.99){
ERRX("Fraction of black pixels should be in [0., 0.99]"); ERRX("Fraction of black pixels should be in [0., 0.99]");
} }
if(GP->Naveraging < 2 || GP->Naveraging > MAX_AVERAGING_ARRAY_SIZE) if(GP->Naveraging < 1 || GP->Naveraging > NAVER_MAX)
ERRX("Averaging amount should be from 2 to 25"); ERRX("Averaging amount should be from 1 to %d", NAVER_MAX);
tp = chk_inp(GP->inputname); tp = chk_inp(GP->inputname);
if(tp == T_WRONG) ERRX("Enter correct image file or directory name"); if(tp == T_WRONG) ERRX("Enter correct image file or directory name");
// check ability of saving file // check ability of saving file
@ -183,7 +184,7 @@ int main(int argc, char *argv[]){
setpostprocess(GP->processing); setpostprocess(GP->processing);
check4running(self, GP->pidfile); check4running(self, GP->pidfile);
DBG("%s started, snippets library version is %s\n", self, sl_libversion()); 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(SIGTERM, signals); // kill (-15) - quit
signal(SIGHUP, SIG_IGN); // hup - ignore signal(SIGHUP, SIG_IGN); // hup - ignore
signal(SIGINT, signals); // ctrl+C - quit signal(SIGINT, signals); // ctrl+C - quit

View File

@ -26,9 +26,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <usefull_macros.h>
#include "config.h" #include "config.h"
#include "debug.h"
#include "imagefile.h" #include "imagefile.h"
#include "median.h" #include "median.h"
@ -36,8 +36,13 @@
#define ELEM_SWAP(a, b) {register Imtype t = a; a = b; b = t;} #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]);} #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){ 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){ static Imtype opt_med3(Imtype *p){
PIX_SORT(0, 1); PIX_SORT(1, 2); PIX_SORT(0, 1); 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){ static Imtype opt_med4(Imtype *p){
PIX_SORT(0, 2); PIX_SORT(1, 3); PIX_SORT(0, 2); PIX_SORT(1, 3);
PIX_SORT(0, 1); PIX_SORT(2, 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){ static Imtype opt_med5(Imtype *p){
PIX_SORT(0, 1); PIX_SORT(3, 4); PIX_SORT(0, 3); 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(1, 2); PIX_SORT(3, 4);
PIX_SORT(0, 1); PIX_SORT(2, 3); PIX_SORT(4, 5); PIX_SORT(0, 1); PIX_SORT(2, 3); PIX_SORT(4, 5);
PIX_SORT(1, 2); PIX_SORT(3, 4); 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){ static Imtype opt_med7(Imtype *p){
PIX_SORT(0, 5); PIX_SORT(0, 3); PIX_SORT(1, 6); 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(3, 5); PIX_SORT(0, 1); PIX_SORT(2, 3);
PIX_SORT(4, 5); PIX_SORT(6, 7); PIX_SORT(1, 4); PIX_SORT(4, 5); PIX_SORT(6, 7); PIX_SORT(1, 4);
PIX_SORT(3, 6); PIX_SORT(3, 6);
return(p[3] + p[4]) * 0.5; return mean(p[3], p[4]);
} }
static Imtype opt_med9(Imtype *p){ static Imtype opt_med9(Imtype *p){
PIX_SORT(1, 2); PIX_SORT(4, 5); PIX_SORT(7, 8); 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(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(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); 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){ static Imtype opt_med25(Imtype *p){
PIX_SORT(0, 1) ; PIX_SORT(3, 4) ; PIX_SORT(2, 4) ; 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, const medfunc fnarr[] = {opt_med2, opt_med3, opt_med4, opt_med5, opt_med6,
opt_med7, opt_med8, opt_med9}; opt_med7, opt_med8, opt_med9};
if(n == 1) return *idata; 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 == 16) fn = opt_med16;
else if(n == 25) fn = opt_med25; else if(n == 25) fn = opt_med25;
if(fn){ if(fn){
@ -229,12 +234,12 @@ typedef struct Mediator_t{
#define maxCt(m) (((m)->ct)/2) //count of Imtypes in maxheap #define maxCt(m) (((m)->ct)/2) //count of Imtypes in maxheap
//returns 1 if heap[i] < heap[j] //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]]); return ImtypeLess(m->data[m->heap[i]],m->data[m->heap[j]]);
} }
//swaps Imtypes i&j in heap, maintains indexes //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]; int t = m->heap[i];
m->heap[i] = m->heap[j]; m->heap[i] = m->heap[j];
m->heap[j] = t; m->heap[j] = t;
@ -244,12 +249,12 @@ inline int mmexchange(Mediator* m, int i, int j){
} }
//swaps Imtypes i&j if i<j; returns true if swapped //swaps Imtypes i&j if i<j; returns true if swapped
inline int mmCmpExch(Mediator* m, int i, int j){ static inline int mmCmpExch(Mediator* m, int i, int j){
return (mmless(m,i,j) && mmexchange(m,i,j)); return (mmless(m,i,j) && mmexchange(m,i,j));
} }
//maintains minheap property for all Imtypes below i/2. //maintains minheap property for all Imtypes below i/2.
void minSortDown(Mediator* m, int i){ static inline void minSortDown(Mediator* m, int i){
for(; i <= minCt(m); i*=2){ for(; i <= minCt(m); i*=2){
if(i>1 && i < minCt(m) && mmless(m, i+1, i)) ++i; if(i>1 && i < minCt(m) && mmless(m, i+1, i)) ++i;
if(!mmCmpExch(m,i,i/2)) break; 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) //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){ for(; i >= -maxCt(m); i*=2){
if(i<-1 && i > -maxCt(m) && mmless(m, i, i-1)) --i; if(i<-1 && i > -maxCt(m) && mmless(m, i, i-1)) --i;
if(!mmCmpExch(m,i/2,i)) break; 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 //maintains minheap property for all Imtypes above i, including median
//returns true if median changed //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; while (i > 0 && mmCmpExch(m, i, i/2)) i /= 2;
return (i == 0); return (i == 0);
} }
//maintains maxheap property for all Imtypes above i, including median //maintains maxheap property for all Imtypes above i, including median
//returns true if median changed //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; while (i < 0 && mmCmpExch(m, i/2, i)) i /= 2;
return (i == 0); return (i == 0);
} }
@ -282,7 +287,7 @@ int maxSortUp(Mediator* m, int i){
//creates new Mediator: to calculate `nImtypes` running median. //creates new Mediator: to calculate `nImtypes` running median.
//mallocs single block of memory, caller must free. //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); int size = sizeof(Mediator) + nImtypes*(sizeof(Imtype)+sizeof(int)*2);
Mediator* m = malloc(size); Mediator* m = malloc(size);
m->data = (Imtype*)(m + 1); m->data = (Imtype*)(m + 1);
@ -298,7 +303,7 @@ Mediator* MediatorNew(int nImtypes){
} }
//Inserts Imtype, maintains median in O(lg 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->ct<m->N); int isNew=(m->ct<m->N);
int p = m->pos[m->idx]; int p = m->pos[m->idx];
Imtype old = m->data[m->idx]; Imtype old = m->data[m->idx];
@ -318,14 +323,15 @@ void MediatorInsert(Mediator* m, Imtype v){
} }
//returns median Imtype (or average of 2 when Imtype count is even) //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]]; Imtype v = m->data[m->heap[0]];
if ((m->ct&1) == 0) v = ImtypeMean(v, m->data[m->heap[-1]]); if ((m->ct&1) == 0) v = ImtypeMean(v, m->data[m->heap[-1]]);
return v; return v;
} }
#if 0
// median + min/max // median + min/max
Imtype MediatorStat(Mediator* m, Imtype *minval, Imtype *maxval){ static Imtype MediatorStat(Mediator* m, Imtype *minval, Imtype *maxval){
Imtype v = m->data[m->heap[0]]; Imtype v = m->data[m->heap[0]];
if ((m->ct&1) == 0) v = ImtypeMean(v, m->data[m->heap[-1]]); if ((m->ct&1) == 0) v = ImtypeMean(v, m->data[m->heap[-1]]);
Imtype min = v, max = v; Imtype min = v, max = v;
@ -342,6 +348,7 @@ Imtype MediatorStat(Mediator* m, Imtype *minval, Imtype *maxval){
*maxval = max; *maxval = max;
return v; return v;
} }
#endif
/** /**
* filter image by median (seed*2 + 1) x (seed*2 + 1) * 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]); MediatorInsert(m, inputima[xx]);
med[medidx] = MediatorMedian(m); med[medidx] = MediatorMedian(m);
} }
FREE(m); free(m);
} }
Image_minmax(out); Image_minmax(out);
DBG("time for median filtering %zdx%zd of image %zdx%zd: %gs", blksz, blksz, w, h, 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 *om = (M) ? &M->data[startidx] : NULL;
Imtype *os = (S) ? &S->data[startidx] : NULL; Imtype *os = (S) ? &S->data[startidx] : NULL;
for(int x = seed; x < xmax; ++x){ 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; int yb = y + seed + 1, xm = x - seed;
for(int yy = y - seed; yy < yb; ++yy){ for(int yy = y - seed; yy < yb; ++yy){
Imtype *ptr = &in->data[yy * w + xm]; Imtype *ptr = &in->data[yy * w + xm];
for(int xx = 0; xx < hsz; ++xx){ for(int xx = 0; xx < hsz; ++xx){
Imtype d = *ptr++; double d = *ptr++;
sum += d; sum += d;
sum2 += d*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); //DBG("sum=%g, sum2=%g, sz=%d", sum, sum2, sz);
sum /= sz; sum /= sz;
if(om){ if(om){
*om++ = sum; *om++ = (Imtype)sum;
//DBG("mean (%d, %d): %g", x, y, 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){ 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); DBG("time for mean/sigma computation: %gs", dtime() - t0);
return TRUE; 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;
}

View File

@ -27,6 +27,5 @@
Imtype calc_median(Imtype *idata, int n); Imtype calc_median(Imtype *idata, int n);
Image *get_median(const Image *img, int seed); Image *get_median(const Image *img, int seed);
int get_stat(const Image *in, int seed, Image **mean, Image **std); int get_stat(const Image *in, int seed, Image **mean, Image **std);
int calc_background(Image *img, Imtype *bk);
#endif // __MEDIAN_H__ #endif // __MEDIAN_H__

View File

@ -26,9 +26,9 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <usefull_macros.h>
#include "config.h" #include "config.h"
#include "debug.h"
#include "improc.h" // global variable stopwork #include "improc.h" // global variable stopwork
#include "pusirobo.h" #include "pusirobo.h"
#include "socket.h" #include "socket.h"
@ -327,7 +327,7 @@ static int chkRelay(){
relay = r; relay = r;
ret = TRUE; ret = TRUE;
rtn: rtn:
FREE(ans); free(ans);
return ret; return ret;
} }
@ -357,7 +357,7 @@ static int setSpeed(const char *mesg, const char *name){
LOGERR("no %s motor", name); LOGERR("no %s motor", name);
retval = FALSE; retval = FALSE;
} }
FREE(ans); if(ans) free(ans);
return retval; return retval;
} }
@ -403,11 +403,11 @@ static int pusi_connect_server(){
send_message_nocheck(registerVaxe); send_message_nocheck(registerVaxe);
send_message_nocheck(registerFocus); send_message_nocheck(registerFocus);
send_message_nocheck(registerRelay); send_message_nocheck(registerRelay);
int retval = TRUE; int retval = FALSE;
if(!chkRelay()) retval = FALSE; if(chkRelay()) retval = TRUE;
if(!setSpeed(setUspeed, "U")) retval = FALSE; if(setSpeed(setUspeed, "U")) retval = TRUE;
if(!setSpeed(setVspeed, "V")) retval = FALSE; if(setSpeed(setVspeed, "V")) retval = TRUE;
if(!setSpeed(setFspeed, "F")) retval = FALSE; if(setSpeed(setFspeed, "F")) retval = TRUE;
if(!retval) pusi_disconnect(); if(!retval) pusi_disconnect();
else{ else{
state = PUSI_RELAX; 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); LOGDBG("%s not found in '%s'", CURPOSstatus, ans);
} }
} }
FREE(ans); if(ans) free(ans);
return ret; return ret;
} }
@ -483,7 +483,7 @@ static int move_motor(const char *movecmd, int s){
LOGWARN("NO OK in %s", ans); LOGWARN("NO OK in %s", ans);
ret = FALSE; ret = FALSE;
} }
FREE(ans); if(ans) free(ans);
return ret; return ret;
} }
@ -968,6 +968,7 @@ static char *Umove(const char *val, char *buf, int buflen){
int Unfixed = Uposition + d + Fposition; int Unfixed = Uposition + d + Fposition;
if(Unfixed > theconf.maxUsteps || Unfixed < -theconf.maxUsteps){ if(Unfixed > theconf.maxUsteps || Unfixed < -theconf.maxUsteps){
snprintf(buf, buflen, FAIL); snprintf(buf, buflen, FAIL);
return buf;
} }
dUmove = d; dUmove = d;
snprintf(buf, buflen, OK); snprintf(buf, buflen, OK);
@ -978,6 +979,7 @@ static char *Vmove(const char *val, char *buf, int buflen){
int Vnfixed = Vposition + d + Fposition; int Vnfixed = Vposition + d + Fposition;
if(Vnfixed > theconf.maxVsteps || Vnfixed < -theconf.maxVsteps){ if(Vnfixed > theconf.maxVsteps || Vnfixed < -theconf.maxVsteps){
snprintf(buf, buflen, FAIL); snprintf(buf, buflen, FAIL);
return buf;
} }
dVmove = d; dVmove = d;
snprintf(buf, buflen, OK); 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); snprintf(buf, buflen, "%s", ans);
return buf; return buf;
} }

View File

@ -29,10 +29,10 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/syscall.h> // syscall #include <sys/syscall.h> // syscall
#include <unistd.h> // daemon #include <unistd.h> // daemon
#include <usefull_macros.h>
#include "cmdlnopts.h" #include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "improc.h" #include "improc.h"
#include "socket.h" #include "socket.h"
@ -140,7 +140,7 @@ static char *moveU(const char *val, char *buf, int buflen){
return retFAIL(buf, buflen); return retFAIL(buf, buflen);
} }
static char *moveV(const char *val, char *buf, int 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); return retFAIL(buf, buflen);
} }
static char *relaycmd(const char *val, char *buf, int 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); DBG("got KEY '%s' with value '%s'", kv, value);
key_value result; key_value result;
par = chk_keyval(kv, value, &result); par = chk_keyval(kv, value, &result);
FREE(kv); free(kv); kv = NULL;
if(par){ if(par){
switch(par->type){ switch(par->type){
case PAR_INT: case PAR_INT: