some bugs fixed, added gray image displaying (with linear and log scales)

This commit is contained in:
Edward Emelianov 2023-05-31 16:20:41 +03:00
parent 0eb3b3ef39
commit cb38636d78
6 changed files with 177 additions and 95 deletions

View File

@ -73,7 +73,7 @@ static int camcapt(IMG *ima){
uint16_t *d = &ima->data[y*ima->w]; uint16_t *d = &ima->data[y*ima->w];
for(int x = 0; x < ima->w; ++x){ // sinusoide 100x200 for(int x = 0; x < ima->w; ++x){ // sinusoide 100x200
//*d++ = (uint16_t)(((n+x)%100)/99.*65535.); //*d++ = (uint16_t)(((n+x)%100)/99.*65535.);
*d++ = (uint16_t)((1 + sin((n+x) * M_PI/50)*sin((n+y) * M_PI/100))*32767.); *d++ = (uint16_t)((1. + sin((n+x) * M_PI/50.)*sin((n+y) * M_PI/100.))*32767.);
} }
} }
++n; ++n;

View File

@ -883,7 +883,7 @@ static void *grabnext(void *arg){
*/ */
int ccdcaptured(IMG **imgptr){ int ccdcaptured(IMG **imgptr){
if(!imgptr) return FALSE; if(!imgptr) return FALSE;
TIMESTAMP("ccdcaptured() start"); //TIMESTAMP("ccdcaptured() start");
static pthread_t grabthread = 0; static pthread_t grabthread = 0;
if(imgptr == (void*)-1){ // kill `grabnext` if(imgptr == (void*)-1){ // kill `grabnext`
DBG("Wait for grabbing thread ends"); DBG("Wait for grabbing thread ends");
@ -926,7 +926,7 @@ int ccdcaptured(IMG **imgptr){
return TRUE; return TRUE;
} }
} }
TIMESTAMP("ccdcaptured() end"); //TIMESTAMP("ccdcaptured() end");
return FALSE; return FALSE;
} }
#endif #endif

View File

@ -273,7 +273,7 @@ void client(int sock){
t0 = dtime(); t0 = dtime();
if(expstate == CAMERA_ERROR){ if(expstate == CAMERA_ERROR){
WARNX(_("Can't make exposition")); WARNX(_("Can't make exposition"));
return; continue;
} }
if(expstate != CAMERA_CAPTURE){ if(expstate != CAMERA_CAPTURE){
verbose(2, "Frame ready!"); verbose(2, "Frame ready!");

View File

@ -16,7 +16,7 @@
* 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 <X11/Xlib.h> // XInitThreads(); //#include <X11/Xlib.h> // XInitThreads();
#include <math.h> // roundf(), log(), sqrt() #include <math.h> // roundf(), log(), sqrt()
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
@ -51,10 +51,12 @@ static void imageview_init(){
WARNX(_("Already initialized!")); WARNX(_("Already initialized!"));
return; return;
} }
XInitThreads(); // we need it for threaded windows //XInitThreads(); // we need it for threaded windows
glutInit(&c, v); glutInit(&c, v);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); // we should call desctructors before exiting
//glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
initialized = 1; initialized = 1;
} }
@ -138,28 +140,37 @@ static void killwindow(){
if(win->menu){ if(win->menu){
DBG("Destroy menu"); DBG("Destroy menu");
glutDestroyMenu(win->menu); glutDestroyMenu(win->menu);
win->menu = 0;
}
if(win->ID){
DBG("Destroy window");
glutDestroyWindow(win->ID);
win->ID = 0;
} }
DBG("Destroy window");
glutDestroyWindow(win->ID);
DBG("Delete textures"); DBG("Delete textures");
glDeleteTextures(1, &(win->Tex)); if(win->Tex){
glDeleteTextures(1, &(win->Tex));
win->Tex = 0;
}
if(GLUTthread){ if(GLUTthread){
DBG("Leave mainloop"); DBG("Leave mainloop");
glutLeaveMainLoop(); glutLeaveMainLoop();
DBG("cancel GLUTthread"); DBG("wait GLUTthread");
pthread_cancel(GLUTthread); pthread_join(GLUTthread, NULL);
GLUTthread = 0; GLUTthread = 0;
} }
DBG("main GL thread cancelled"); DBG("main GL thread cancelled");
initialized = 0; initialized = 0;
windowData *old = win; if(win){
win = NULL; windowData *old = win;
DBG("free(rawdata)"); win = NULL;
FREE(old->image->rawdata); DBG("free(rawdata)");
DBG("free(image)"); FREE(old->image->rawdata);
FREE(old->image); DBG("free(image)");
DBG("free(win)"); FREE(old->image);
FREE(old); DBG("free(win)");
FREE(old);
}
DBG("return"); DBG("return");
return; return;
} }
@ -233,6 +244,12 @@ static void *Redraw(_U_ void *arg){
FNAME(); FNAME();
createWindow(); createWindow();
glutMainLoop(); glutMainLoop();
// cleanup after window closing
win->menu = 0; // prevent deleting of non-existant menu and window
win->ID = 0;
win->killthread = 1; // kill all threads
GLUTthread = 0; // prevent call of glutLeaveMainLoop
DBG("\n\nCLOSE ALL after window closing");
return NULL; return NULL;
} }
@ -354,17 +371,20 @@ static void gray2rgb(double gray, GLubyte *rgb){
} }
typedef enum{ typedef enum{
COLORFN_LINEAR, // linear COLORFN_BWLINEAR, // gray levels, linear
COLORFN_LOG, // ln COLORFN_BWLOG, // gray ln
COLORFN_SQRT, // sqrt COLORFN_LINEAR, // linear
COLORFN_POW, // power COLORFN_LOG, // ln
COLORFN_MAX // end of list COLORFN_SQRT, // sqrt
COLORFN_POW, // power
COLORFN_MAX // end of list
} colorfn_type; } colorfn_type;
static colorfn_type ft = COLORFN_LINEAR; static colorfn_type ft = COLORFN_BWLINEAR;
// all colorfun's should get argument in [0, 1] and return in [0, 1] // all colorfun's should get argument in [0, 1] and return in [0, 1]
static double linfun(double arg){ return arg; } // bung for PREVIEW_LINEAR static double linfun(double arg){ return arg; } // bung for PREVIEW_LINEAR
static double glogfun(double arg){ return 45.98590 * log(1.+arg); } // gray for log (arg in [0, 255])
static double logfun(double arg){ return log(1.+arg) / 0.6931472; } // for PREVIEW_LOG [log_2(x+1)] static double logfun(double arg){ return log(1.+arg) / 0.6931472; } // for PREVIEW_LOG [log_2(x+1)]
static double powfun(double arg){ return arg * arg;} static double powfun(double arg){ return arg * arg;}
static double (*colorfun)(double) = linfun; // default function to convert color static double (*colorfun)(double) = linfun; // default function to convert color
@ -374,6 +394,14 @@ static void change_colorfun(colorfn_type f){
const char *cfn = NULL; const char *cfn = NULL;
ft = f; ft = f;
switch (f){ switch (f){
case COLORFN_BWLINEAR:
colorfun = linfun;
cfn = "bw linear";
break;
case COLORFN_BWLOG:
colorfun = glogfun;
cfn = "bw log";
break;
case COLORFN_LOG: case COLORFN_LOG:
colorfun = logfun; colorfun = logfun;
cfn = "log"; cfn = "log";
@ -396,9 +424,19 @@ static void change_colorfun(colorfn_type f){
// cycle switch between palettes // cycle switch between palettes
static void roll_colorfun(){ static void roll_colorfun(){
colorfn_type t = ++ft; colorfn_type t = ++ft;
if(t == COLORFN_MAX) t = COLORFN_LINEAR; if(t == COLORFN_MAX) t = COLORFN_BWLINEAR;
change_colorfun(t); change_colorfun(t);
} }
/*
no omp
histo: 0.000675201s
equal: 0.000781059s
result: 0.00135899s
omp:
histo: 0.000928879s
equal: 0.0010879s
result: 0.0014689s
*/
/** /**
* @brief equalize - hystogram equalization * @brief equalize - hystogram equalization
@ -411,7 +449,7 @@ static uint8_t *equalize(uint16_t *ori, int w, int h){
double orig_hysto[0x10000] = {0.}; // original hystogram double orig_hysto[0x10000] = {0.}; // original hystogram
uint8_t eq_levls[0x10000] = {0}; // levels to convert: newpix = eq_levls[oldpix] uint8_t eq_levls[0x10000] = {0}; // levels to convert: newpix = eq_levls[oldpix]
int s = w*h; int s = w*h;
//double t0 = dtime(); //double t0 = dtime();
/* -- takes too long because of sync /* -- takes too long because of sync
#pragma omp parallel #pragma omp parallel
{ {
@ -429,17 +467,88 @@ static uint8_t *equalize(uint16_t *ori, int w, int h){
for(int i = 0; i < s; ++i){ for(int i = 0; i < s; ++i){
++orig_hysto[ori[i]]; ++orig_hysto[ori[i]];
} }
//DBG("HISTOGRAM takes %g", dtime() - t0); //WARNX("histo: %gs", dtime()-t0);
double part = (double)(s + 1) / 0x100, N = 0.; double part = (double)(s + 1) / 0x100, N = 0.;
for(int i = 0; i <= 0xffff; ++i){ for(int i = 0; i <= 0xffff; ++i){
N += orig_hysto[i]; N += orig_hysto[i];
eq_levls[i] = (uint8_t)(N/part); eq_levls[i] = (uint8_t)(N/part);
} }
//OMP_FOR() -- takes too long! //WARNX("equal: %gs", dtime()-t0);
//OMP_FOR() -- takes the same time!
for(int i = 0; i < s; ++i){ for(int i = 0; i < s; ++i){
retn[i] = eq_levls[ori[i]]; retn[i] = eq_levls[ori[i]];
} }
//DBG("EQUALIZATION takes %g", dtime() - t0); //WARNX("result: %gs", dtime()-t0);
return retn;
}
/*
no omp @ histo:
histo: 0.00269914s
stat: 0.00272393s
cuts: 0.00357103s
omp @ histo:
histo: 0.00120497s
stat: 0.00127792s
cuts: 0.00188208s
*/
// count image cuts as [median-sigma median+5sigma]
static uint8_t *mkcuts(uint16_t *ori, int w, int h){
uint8_t *retn = MALLOC(uint8_t, w*h);
int orig_hysto[0x10000] = {0.}; // original hystogram
int s = w*h;
double sum = 0., sum2 = 0.;
//double t0 = dtime();
#pragma omp parallel
{
size_t histogram_private[0x10000] = {0};
double sm = 0., sm2 = 0.;
#pragma omp for nowait
for(int i = 0; i < s; ++i){
++histogram_private[ori[i]];
double b = ori[i];
sm += b;
sm2 += b*b;
}
#pragma omp critical
{
for(int i = 0; i < 0x10000; ++i) orig_hysto[i] += histogram_private[i];
sum += sm;
sum2 += sm2;
}
}
/*
for(int i = 0; i < s; ++i){
double b = ori[i];
++orig_hysto[ori[i]];
sum += b;
sum2 += b*b;
}
*/
//WARNX("histo: %gs", dtime()-t0);
// get median level
int counts = s/2, median = 0;
for(; median < 0xffff; ++median){
if((counts -= orig_hysto[median]) < 0) break;
}
sum /= s;
double sigma = sqrt(sum2/s - sum*sum);
int low = median - sigma, high = median + 5.*sigma;
if(low < 0) low = 0;
if(high > 0xffff) high = 0xffff;
double A = 255./(high - low);
DBG("Got: sigma=%.1f, low=%d, high=%d, A=%g", sigma, low, high, A);
// now we can recalculate values: new = (old - low)*A
//WARNX("stat: %gs", dtime()-t0);
// DEBUG: 2ms without OMP; 0.7ms with
OMP_FOR()
for(int i = 0; i < s; ++i){
uint16_t old = ori[i];
if(old > high){ retn[i] = 255; continue; }
else if(old < low){ retn[i] = 0; continue; }
retn[i] = (uint8_t)(A*(old - low));
}
//WARNX("cuts: %gs", dtime()-t0);
return retn; return retn;
} }
@ -457,25 +566,32 @@ static void change_displayed_image(IMG *img){
win->image = im; win->image = im;
DBG("win->image changed"); DBG("win->image changed");
} }
uint8_t *newima;
if(imequalize){ if(imequalize){
DBG("equalize"); DBG("equalize");
uint8_t *newima = equalize(img->data, w, h); newima = equalize(img->data, w, h);
GLubyte *dst = im->rawdata; }else{
DBG("convert; s=%d, im->s=%d", s, im->h*im->w); DBG("cuts");
// openmp would make all calculations MORE SLOW than even in one thread! newima = mkcuts(img->data, w, h);
//OMP_FOR() }
GLubyte *dst = im->rawdata;
//double t0 = dtime();
if(ft < COLORFN_LINEAR){ // gray
// without OMP: 1.8ms; with OMP: 0.8ms
OMP_FOR()
for(int i = 0; i < s; ++i){
GLubyte *t = &dst[i*3];
t[0] = t[1] = t[2] = colorfun(newima[i]);
}
}else{
// without OMP: 3.6ms; with OMP: 1.7ms
OMP_FOR()
for(int i = 0; i < s; ++i){ for(int i = 0; i < s; ++i){
gray2rgb(colorfun(newima[i] / 256.), &dst[i*3]); gray2rgb(colorfun(newima[i] / 256.), &dst[i*3]);
} }
FREE(newima);
}else{
DBG("convert; s=%d, im->s=%d", s, im->h*im->w);
GLubyte *dst = im->rawdata;
//OMP_FOR()
for(int i = 0; i < s; ++i){
gray2rgb(colorfun(img->data[i] / 65536.), &dst[i*3]);
}
} }
//WARNX("Conversion time: %g", dtime()-t0);
FREE(newima);
/* /*
// mirror image around Y // mirror image around Y
int w3 = w*3, h1 = h-1, wsz = w3*sizeof(GLubyte); int w3 = w*3, h1 = h-1, wsz = w3*sizeof(GLubyte);
@ -495,40 +611,6 @@ static void change_displayed_image(IMG *img){
pthread_mutex_unlock(&win->mutex); pthread_mutex_unlock(&win->mutex);
} }
#if 0
// thread for checking
static void* image_thread(void *data){
FNAME();
IMG *(*newimage)(const char *) = (IMG*(*)(const char*)) data;
IMG *img = NULL;
while(1){
if(!win || win->killthread){
DBG("got killthread");
clear_GL_context();
pthread_exit(NULL);
}
if(win && win->winevt){
if(win->winevt & WINEVT_SAVEIMAGE){ // save image
verbose(2, "Make screenshot\n");
saveFITS(img, NULL);
win->winevt &= ~WINEVT_SAVEIMAGE;
}
if(win->winevt & WINEVT_ROLLCOLORFUN){
roll_colorfun();
win->winevt &= ~WINEVT_ROLLCOLORFUN;
change_displayed_image(win, img);
}
if(win->winevt & WINEVT_EQUALIZE){
win->winevt &= ~WINEVT_EQUALIZE;
imequalize = !imequalize;
verbose(1, _("Equalization of histogram: %s"), imequalize ? N_("on") : N_("off"));
}
}
usleep(10000);
}
}
#endif
void closeGL(){ // killed by external signal or ctrl+c void closeGL(){ // killed by external signal or ctrl+c
if(!initialized) return; if(!initialized) return;
DBG("KILLL"); DBG("KILLL");

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-06 14:36+0300\n" "POT-Creation-Date: 2023-05-31 16:14+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -571,28 +571,28 @@ msgstr ""
msgid "Already initialized!" msgid "Already initialized!"
msgstr "" msgstr ""
#: imageview.c:291 #: imageview.c:308
msgid "Can't init mutex!" msgid "Can't init mutex!"
msgstr "" msgstr ""
#: imageview.c:393 #: imageview.c:421
#, c-format #, c-format
msgid "Histogram conversion: %s" msgid "Histogram conversion: %s"
msgstr "" msgstr ""
#: imageview.c:524 imageview.c:600 #: imageview.c:640
msgid "Can't open OpenGL window, image preview will be inaccessible"
msgstr ""
#: imageview.c:682
#, c-format #, c-format
msgid "Equalization of histogram: %s" msgid "Equalization of histogram: %s"
msgstr "" msgstr ""
#: imageview.c:524 imageview.c:600 #: imageview.c:682
msgid "on" msgid "on"
msgstr "" msgstr ""
#: imageview.c:524 imageview.c:600 #: imageview.c:682
msgid "off" msgid "off"
msgstr "" msgstr ""
#: imageview.c:558
msgid "Can't open OpenGL window, image preview will be inaccessible"
msgstr ""

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: PACKAGE VERSION\n" msgstr "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-06 14:36+0300\n" "POT-Creation-Date: 2023-05-31 16:14+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -113,7 +113,7 @@ msgstr "
msgid "Can't home focuser" msgid "Can't home focuser"
msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÆÏËÕÓÅÒ × ÎÕÌØ" msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÆÏËÕÓÅÒ × ÎÕÌØ"
#: imageview.c:291 #: imageview.c:308
msgid "Can't init mutex!" msgid "Can't init mutex!"
msgstr "îÅ ÍÏÇÕ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÍØÀÔÅËÓ!" msgstr "îÅ ÍÏÇÕ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÍØÀÔÅËÓ!"
@ -121,7 +121,7 @@ msgstr "
msgid "Can't make exposition" msgid "Can't make exposition"
msgstr "îÅ ÍÏÇÕ ×ÙÐÏÌÎÉÔØ ÜËÓÐÏÚÉÃÉÀ" msgstr "îÅ ÍÏÇÕ ×ÙÐÏÌÎÉÔØ ÜËÓÐÏÚÉÃÉÀ"
#: imageview.c:558 #: imageview.c:640
msgid "Can't open OpenGL window, image preview will be inaccessible" msgid "Can't open OpenGL window, image preview will be inaccessible"
msgstr "îÅ ÍÏÇÕ ÏÔËÒÙÔØ ÏËÎÏ OpenGL, ÏÔÏÂÒÁÖÅÎÉÅ ÂÕÄÅÔ ÎÅÄÏÓÔÕÐÎÏ" msgstr "îÅ ÍÏÇÕ ÏÔËÒÙÔØ ÏËÎÏ OpenGL, ÏÔÏÂÒÁÖÅÎÉÅ ÂÕÄÅÔ ÎÅÄÏÓÔÕÐÎÏ"
@ -232,7 +232,7 @@ msgstr ""
msgid "Display image in OpenGL window" msgid "Display image in OpenGL window"
msgstr "ïÔÏÂÒÁÖÅÎÉÅ ÉÚÏÂÒÁÖÅÎÉÑ × ÏËÎÅ OpenGL" msgstr "ïÔÏÂÒÁÖÅÎÉÅ ÉÚÏÂÒÁÖÅÎÉÑ × ÏËÎÅ OpenGL"
#: imageview.c:524 imageview.c:600 #: imageview.c:682
#, c-format #, c-format
msgid "Equalization of histogram: %s" msgid "Equalization of histogram: %s"
msgstr "üË×ÁÌÉÚÁÃÉÑ ÇÉÓÔÏÇÒÁÍÍÙ: %s" msgstr "üË×ÁÌÉÚÁÃÉÑ ÇÉÓÔÏÇÒÁÍÍÙ: %s"
@ -275,7 +275,7 @@ msgstr "
msgid "Full array: %s" msgid "Full array: %s"
msgstr "ðÏÌÎÙÊ ÆÏÒÍÁÔ: %s" msgstr "ðÏÌÎÙÊ ÆÏÒÍÁÔ: %s"
#: imageview.c:393 #: imageview.c:421
#, c-format #, c-format
msgid "Histogram conversion: %s" msgid "Histogram conversion: %s"
msgstr "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÇÉÓÔÏÇÒÁÍÍÙ: %s" msgstr "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÇÉÓÔÏÇÒÁÍÍÙ: %s"
@ -510,11 +510,11 @@ msgstr "
msgid "observing program name" msgid "observing program name"
msgstr "ÎÁÚ×ÁÎÉÅ ÐÒÏÇÒÁÍÍÙ" msgstr "ÎÁÚ×ÁÎÉÅ ÐÒÏÇÒÁÍÍÙ"
#: imageview.c:524 imageview.c:600 #: imageview.c:682
msgid "off" msgid "off"
msgstr "×ÙËÌ" msgstr "×ÙËÌ"
#: imageview.c:524 imageview.c:600 #: imageview.c:682
msgid "on" msgid "on"
msgstr "×ËÌ" msgstr "×ËÌ"