From 3073be9d09a827394a2de14ce08be104a85ea660 Mon Sep 17 00:00:00 2001 From: eddyem Date: Wed, 1 Apr 2020 19:13:27 +0300 Subject: [PATCH] add save to FITS & hystogram equalization when displaying --- Makefile | 2 +- camera_functions.c | 12 +- events.c | 1 + grasshopper.c | 168 +++--------------------- image_functions.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ image_functions.h | 45 +++++++ imageview.c | 22 ++-- 7 files changed, 402 insertions(+), 168 deletions(-) create mode 100644 image_functions.c create mode 100644 image_functions.h diff --git a/Makefile b/Makefile index 7603e41..f97ae5c 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PROGRAM := grasshopper LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all LDFLAGS += -lusefull_macros -lflycapture-c -lflycapture -L/usr/local/lib -LDFLAGS += -lm -pthread -lglut -lGL -lX11 +LDFLAGS += -lm -pthread -lglut -lGL -lX11 -lcfitsio SRCS := $(wildcard *.c) DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 OBJDIR := mk diff --git a/camera_functions.c b/camera_functions.c index 71b7807..b858905 100644 --- a/camera_functions.c +++ b/camera_functions.c @@ -59,7 +59,7 @@ static void prbl(char *s, BOOL prop){ } fc2Error getproperty(fc2Context context, fc2PropertyType t){ - fc2Property prop; + fc2Property prop = {0}; prop.type = t; FC2FNW(fc2GetProperty, context, &prop); if(!prop.present) return FC2_ERROR_NOT_FOUND; @@ -75,7 +75,7 @@ fc2Error getproperty(fc2Context context, fc2PropertyType t){ } fc2Error getpropertyInfo(fc2Context context, fc2PropertyType t){ - fc2PropertyInfo i; + fc2PropertyInfo i = {0}; i.type = t; FC2FNW(fc2GetPropertyInfo, context, &i); if(!i.present) return FC2_ERROR_NOT_FOUND; @@ -104,9 +104,9 @@ fc2Error getpropertyInfo(fc2Context context, fc2PropertyType t){ * @return FC2_ERROR_OK if all OK */ fc2Error setfloat(fc2PropertyType t, fc2Context context, float f){ - fc2Property prop; + fc2Property prop = {0}; prop.type = t; - fc2PropertyInfo i; + fc2PropertyInfo i = {0}; i.type = t; FC2FNW(fc2GetProperty, context, &prop); FC2FNW(fc2GetPropertyInfo, context, &i); @@ -146,9 +146,9 @@ fc2Error setfloat(fc2PropertyType t, fc2Context context, float f){ } fc2Error propOnOff(fc2PropertyType t, fc2Context context, BOOL onOff){ - fc2Property prop; + fc2Property prop = {0}; prop.type = t; - fc2PropertyInfo i; + fc2PropertyInfo i = {0}; i.type = t; FC2FNW(fc2GetPropertyInfo, context, &i); FC2FNW(fc2GetProperty, context, &prop); diff --git a/events.c b/events.c index 9550885..a4d268b 100644 --- a/events.c +++ b/events.c @@ -57,6 +57,7 @@ static void processKeybrd(unsigned char key, int mod, _U_ int x, _U_ int y){ killwindow(); break; case 'c': // capture in pause mode + DBG("winevt = %d", win->winevt); if(win->winevt & WINEVT_PAUSE) win->winevt |= WINEVT_GETIMAGE; break; diff --git a/grasshopper.c b/grasshopper.c index 259af1a..702c33e 100644 --- a/grasshopper.c +++ b/grasshopper.c @@ -25,6 +25,7 @@ #include "aux.h" #include "camera_functions.h" #include "cmdlnopts.h" +#include "image_functions.h" #include "imageview.h" void signals(int sig){ @@ -39,156 +40,6 @@ void signals(int sig){ exit(sig); } - -static int GrabImage(fc2Context context, fc2Image *convertedImage){ - fc2Error error; - fc2Image rawImage; - // start capture - FC2FNE(fc2StartCapture, context); - error = fc2CreateImage(&rawImage); - if(error != FC2_ERROR_OK){ - printf("Error in fc2CreateImage: %s\n", fc2ErrorToDescription(error)); - return -1; - } - // Retrieve the image - error = fc2RetrieveBuffer(context, &rawImage); - if (error != FC2_ERROR_OK){ - printf("Error in retrieveBuffer: %s\n", fc2ErrorToDescription(error)); - return -1; - } - // Convert image to gray - windowData *win = getWin(); - if(win) pthread_mutex_lock(&win->mutex); - error = fc2ConvertImageTo(FC2_PIXEL_FORMAT_MONO8, &rawImage, convertedImage); - if(win) pthread_mutex_unlock(&win->mutex); - if(error != FC2_ERROR_OK){ - printf("Error in fc2ConvertImageTo: %s\n", fc2ErrorToDescription(error)); - return -1; - } - fc2StopCapture(context); - fc2DestroyImage(&rawImage); - return 0; -} - -/** - * Convert gray (unsigned short) into RGB components (GLubyte) - * @argument L - gray level - * @argument rgb - rgb array (GLubyte [3]) - */ -static void gray2rgb(double gray, GLubyte *rgb){ - int i = gray * 4.; - double x = (gray - (double)i * .25) * 4.; - GLubyte r = 0, g = 0, b = 0; - //r = g = b = (gray < 1) ? gray * 256 : 255; - switch(i){ - case 0: - g = (GLubyte)(255. * x); - b = 255; - break; - case 1: - g = 255; - b = (GLubyte)(255. * (1. - x)); - break; - case 2: - r = (GLubyte)(255. * x); - g = 255; - break; - case 3: - r = 255; - g = (GLubyte)(255. * (1. - x)); - break; - default: - r = 255; - } - *rgb++ = r; - *rgb++ = g; - *rgb = b; -} - -// functions for converting grayscale value into colour -typedef enum{ - COLORFN_LINEAR, // linear - COLORFN_LOG, // ln - COLORFN_SQRT, // sqrt - COLORFN_MAX // end of list -} colorfn_type; - -static colorfn_type ft = COLORFN_LINEAR; - -static double linfun(double arg){ return arg; } // bung for PREVIEW_LINEAR -static double logfun(double arg){ return log(1.+arg); } // for PREVIEW_LOG -static double (*colorfun)(double) = linfun; // default function to convert color - -static void change_colorfun(colorfn_type f){ - DBG("New colorfn: %d", f); - switch (f){ - case COLORFN_LOG: - colorfun = logfun; - ft = COLORFN_LOG; - break; - case COLORFN_SQRT: - colorfun = sqrt; - ft = COLORFN_SQRT; - break; - default: // linear - colorfun = linfun; - ft = COLORFN_LINEAR; - } -} - -static void roll_colorfun(){ - colorfn_type t = ++ft; - if(t == COLORFN_MAX) t = COLORFN_LINEAR; - change_colorfun(t); -} - -static void change_displayed_image(windowData *win, fc2Image *convertedImage){ - if(!win || !win->image) return; - rawimage *im = win->image; - DBG("imh=%d, imw=%d, ch=%u, cw=%u", im->h, im->w, convertedImage->rows, convertedImage->cols); - /* - if(!im->rawdata || im->h != (int)convertedImage->rows || im->w != (int)convertedImage->cols){ - DBG("[re]allocate im->rawdata"); - FREE(im->rawdata); - im->h = (int)convertedImage->rows; - im->w = (int)convertedImage->cols; - im->rawdata = MALLOC(GLubyte, 3 * im->h * im->w); - if(!im->rawdata) ERR("Can't allocate memory"); - } - printf("image data:\n"); - printf("rows=%u, cols=%u, stride=%u, datasize=%u, recds=%u\n", convertedImage->rows, - convertedImage->cols, convertedImage->stride, convertedImage->dataSize, convertedImage->receivedDataSize); - */ - pthread_mutex_lock(&win->mutex); - int x, y, w = convertedImage->cols, h = convertedImage->rows; - double avr, wd, max, min; - avr = max = min = (double)*convertedImage->pData; - for(y = 0; y < h; ++y){ - unsigned char *ptr = &convertedImage->pData[y*convertedImage->stride]; - for(x = 0; x < w; ++x, ++ptr){ - double pix = (double) *ptr; - if(pix > max) max = pix; - if(pix < min) min = pix; - avr += pix; - } - } - avr /= (double)(w*h); - wd = max - min; - if(wd > DBL_EPSILON) avr = (avr - min) / wd; // normal average by preview - if(avr < 0.6) wd *= avr + 0.2; - if(wd < DBL_EPSILON) wd = 1.; - DBG("stat: sz=(%dx%d) avr=%g wd=%g max=%g min=%g", w,h,avr, wd, max, min); - GLubyte *dst = im->rawdata; - for(y = 0; y < h; y++){ - unsigned char *ptr = &convertedImage->pData[y*convertedImage->stride]; - for(x = 0; x < w; x++, dst += 3, ++ptr){ - gray2rgb(colorfun((*ptr - min) / wd), dst); - } - } - win->image->changed = 1; - pthread_mutex_unlock(&win->mutex); -} - static void savePng(fc2Image *convertedImage, char *name){ VDBG("Save the image data into %s", name); fc2Error error = fc2SaveImage(convertedImage, name, FC2_PNG); @@ -203,12 +54,15 @@ static void saveImages(fc2Image *convertedImage, char *prefix){ if(newname) savePng(convertedImage, newname); } // and save FITS here + char *newname = check_filename(prefix, "fits"); + if(newname && writefits(newname, convertedImage)) + VDBG("FITS file saved into %s", newname); } // manage some menu/shortcut events static void winevt_manage(windowData *win, fc2Image *convertedImage){ if(win->winevt & WINEVT_SAVEIMAGE){ // save image - DBG("Try to make screenshot"); + VDBG("Try to make screenshot"); saveImages(convertedImage, "ScreenShot"); win->winevt &= ~WINEVT_SAVEIMAGE; } @@ -288,7 +142,12 @@ int main(int argc, char **argv){ if(verbose_level >= VERB_MESG && numCameras > 1) PrintCameraInfo(context, G.camno); if(isnan(G.exptime)){ // no expose time -> return printf("No exposure parameters given -> exit\n"); - goto destr; + fc2StopCapture(context); + fc2DestroyContext(context); + signals(ret); + } + if(!G.showimage && !outfprefix){ // not display image & not save it? + ERRX("You should point file name or option `display image`"); } // turn off all shit autoExpOff(context); @@ -360,6 +219,11 @@ destr: if(G.showimage){ while((mainwin = getWin())){ if(mainwin->killthread) break; + if(mainwin->winevt & WINEVT_GETIMAGE){ + mainwin->winevt &= ~WINEVT_GETIMAGE; + if(!GrabImage(context, &convertedImage)) + change_displayed_image(mainwin, &convertedImage); + } } DBG("Close window"); clear_GL_context(); diff --git a/image_functions.c b/image_functions.c new file mode 100644 index 0000000..361e74a --- /dev/null +++ b/image_functions.c @@ -0,0 +1,320 @@ +/* + * This file is part of the grasshopper project. + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "camera_functions.h" +#include "cmdlnopts.h" +#include "image_functions.h" + +int GrabImage(fc2Context context, fc2Image *convertedImage){ + fc2Error error; + fc2Image rawImage; + // start capture + FC2FNE(fc2StartCapture, context); + error = fc2CreateImage(&rawImage); + if(error != FC2_ERROR_OK){ + printf("Error in fc2CreateImage: %s\n", fc2ErrorToDescription(error)); + return -1; + } + // Retrieve the image + error = fc2RetrieveBuffer(context, &rawImage); + if (error != FC2_ERROR_OK){ + printf("Error in retrieveBuffer: %s\n", fc2ErrorToDescription(error)); + return -1; + } + // Convert image to gray + windowData *win = getWin(); + if(win) pthread_mutex_lock(&win->mutex); + error = fc2ConvertImageTo(FC2_PIXEL_FORMAT_MONO8, &rawImage, convertedImage); + if(win) pthread_mutex_unlock(&win->mutex); + if(error != FC2_ERROR_OK){ + printf("Error in fc2ConvertImageTo: %s\n", fc2ErrorToDescription(error)); + return -1; + } + fc2StopCapture(context); + fc2DestroyImage(&rawImage); + return 0; +} + + +/** + * Convert gray (unsigned short) into RGB components (GLubyte) + * @argument L - gray level (0..1) + * @argument rgb - rgb array (GLubyte [3]) + */ +void gray2rgb(double gray, GLubyte *rgb){ + int i = gray * 4.; + double x = (gray - (double)i * .25) * 4.; + GLubyte r = 0, g = 0, b = 0; + //r = g = b = (gray < 1) ? gray * 256 : 255; + switch(i){ + case 0: + g = (GLubyte)(255. * x); + b = 255; + break; + case 1: + g = 255; + b = (GLubyte)(255. * (1. - x)); + break; + case 2: + r = (GLubyte)(255. * x); + g = 255; + break; + case 3: + r = 255; + g = (GLubyte)(255. * (1. - x)); + break; + default: + r = 255; + } + *rgb++ = r; + *rgb++ = g; + *rgb = b; +} + +static colorfn_type ft = COLORFN_LINEAR; + +// 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 logfun(double arg){ return log(1.+arg) / 0.6931472; } // for PREVIEW_LOG [log_2(x+1)] +static double (*colorfun)(double) = linfun; // default function to convert color + +colorfn_type get_colorfun(){return ft;} + +void change_colorfun(colorfn_type f){ + DBG("New colorfn: %d", f); + switch (f){ + case COLORFN_LOG: + colorfun = logfun; + ft = COLORFN_LOG; + break; + case COLORFN_SQRT: + colorfun = sqrt; + ft = COLORFN_SQRT; + break; + default: // linear + colorfun = linfun; + ft = COLORFN_LINEAR; + } +} + +// cycle switch between palettes +void roll_colorfun(){ + colorfn_type t = ++ft; + if(t == COLORFN_MAX) t = COLORFN_LINEAR; + change_colorfun(t); +} + +/** + * @brief equalize - hystogram equalization + * @param ori (io) - input/output data + * @param w,h,s - image width, height and stride + * @return data allocated here + */ +static uint8_t *equalize(uint8_t *ori, int w, int h, int s){ + uint8_t *retn = MALLOC(uint8_t, s*h); + + double orig_hysto[256] = {0.}; // original hystogram + uint8_t eq_levls[256] = {0}; // levels to convert: newpix = eq_levls[oldpix] + for(int y = 0; y < h; ++y){ + uint8_t *ptr = &ori[y * s]; + for(int x = 0; x < w; ++x) + ++orig_hysto[*ptr++]; + } + double part = (double)(w*h - 1) / 256., N = 0.; + for(size_t i = 0; i < 256; ++i){ + N += orig_hysto[i]; + eq_levls[i] = (uint8_t)(N/part); + } + + for(int y = 0; y < h; ++y){ + uint8_t *iptr = &ori[y * s]; + uint8_t *optr = &retn[y * s]; + for(int x = 0; x < w; ++x){ + //*optr++ = *iptr++; + *optr++ = eq_levls[*iptr++]; + } + } + return retn; +} + +void change_displayed_image(windowData *win, fc2Image *convertedImage){ + if(!win || !win->image) return; + rawimage *im = win->image; + DBG("imh=%d, imw=%d, ch=%u, cw=%u", im->h, im->w, convertedImage->rows, convertedImage->cols); + /* + if(!im->rawdata || im->h != (int)convertedImage->rows || im->w != (int)convertedImage->cols){ + DBG("[re]allocate im->rawdata"); + FREE(im->rawdata); + im->h = (int)convertedImage->rows; + im->w = (int)convertedImage->cols; + im->rawdata = MALLOC(GLubyte, 3 * im->h * im->w); + if(!im->rawdata) ERR("Can't allocate memory"); + } + printf("image data:\n"); + printf("rows=%u, cols=%u, stride=%u, datasize=%u, recds=%u\n", convertedImage->rows, + convertedImage->cols, convertedImage->stride, convertedImage->dataSize, convertedImage->receivedDataSize); + */ + pthread_mutex_lock(&win->mutex); + int x, y, w = convertedImage->cols, h = convertedImage->rows, s = convertedImage->stride; + uint8_t *newima = equalize(convertedImage->pData, w, h, s); + /* + double avr, wd, max, min; + avr = max = min = (double)*convertedImage->pData; + for(y = 0; y < h; ++y){ + unsigned char *ptr = &convertedImage->pData[y*convertedImage->stride]; + for(x = 0; x < w; ++x, ++ptr){ + double pix = (double) *ptr; + if(pix > max) max = pix; + if(pix < min) min = pix; + avr += pix; + } + } + avr /= (double)(w*h); + wd = max - min; + if(wd > DBL_EPSILON) avr = (avr - min) / wd; // normal average by preview + if(avr < 0.6) wd *= avr + 0.2; + if(wd < DBL_EPSILON) wd = 1.; + DBG("stat: sz=(%dx%d) avr=%g wd=%g max=%g min=%g", w,h,avr, wd, max, min); + */ + GLubyte *dst = im->rawdata; + for(y = 0; y < h; y++){ + //unsigned char *ptr = &convertedImage->pData[y * s]; + unsigned char *ptr = &newima[y * s]; + for(x = 0; x < w; x++, dst += 3, ++ptr){ + //gray2rgb(colorfun((*ptr - min) / wd), dst); + gray2rgb(colorfun(*ptr / 256.), dst); + } + } + FREE(newima); + win->image->changed = 1; + pthread_mutex_unlock(&win->mutex); +} + +#define TRYFITS(f, ...) \ +do{ int status = 0; \ + f(__VA_ARGS__, &status); \ + if (status){ \ + fits_report_error(stderr, status); \ + return 1;} \ +}while(0) +#define WRITEKEY(...) \ +do{ int status = 0; \ + fits_write_key(__VA_ARGS__, &status); \ + if(status) fits_report_error(stderr, status);\ +}while(0) + +/** + * @brief writefits - save FITS-file + * @param filename - full filename of output file + * @param convertedImage - image to save + * @return 0 if all OK + */ +int writefits(char *filename, fc2Image *convertedImage){ + int w = convertedImage->cols, s = convertedImage->stride, h = convertedImage->rows; + long naxes[2] = {w, h}; //, startTime; + double tmp = 0.0; + //struct tm *tm_starttime; + char buf[80]; + time_t savetime = time(NULL); + fitsfile *fp; + TRYFITS(fits_create_file, &fp, filename); + TRYFITS(fits_create_img, fp, BYTE_IMG, 2, naxes); + // FILE / Input file original name + WRITEKEY(fp, TSTRING, "FILE", filename, "Input file original name"); + // ORIGIN / organization responsible for the data + WRITEKEY(fp, TSTRING, "ORIGIN", "SAO RAS", "organization responsible for the data"); + // OBSERVAT / Observatory name + WRITEKEY(fp, TSTRING, "OBSERVAT", "Special Astrophysical Observatory, Russia", "Observatory name"); + fc2Context context; + if(FC2_ERROR_OK == fc2CreateContext(&context)){ + fc2CameraInfo camInfo; + fc2Error error = fc2GetCameraInfo(context, &camInfo); + if(error == FC2_ERROR_OK){ + // INSTRUME / Instrument + WRITEKEY(fp, TSTRING, "INSTRUME", camInfo.modelName, "Instrument"); + // DETECTOR / detector + WRITEKEY(fp, TSTRING, "DETECTOR", camInfo.sensorInfo, "Detector model"); + } + fc2DestroyContext(context); + } + double pixX, pixY = pixX = 6.45; + snprintf(buf, 80, "%g x %g", pixX, pixY); + // PXSIZE / pixel size + WRITEKEY(fp, TSTRING, "PXSIZE", buf, "Pixel size (um)"); + WRITEKEY(fp, TDOUBLE, "XPIXSZ", &pixX, "Pixel Size X (um)"); + WRITEKEY(fp, TDOUBLE, "YPIXSZ", &pixY, "Pixel Size Y (um)"); +/* + if(G->exptime < 2.*DBL_EPSILON) sprintf(buf, "bias"); + else if(G->dark) sprintf(buf, "dark"); + else if(G->objtype) strncpy(buf, G->objtype, 80); + else sprintf(buf, "object"); + // IMAGETYP / object, flat, dark, bias, scan, eta, neon, push + WRITEKEY(fp, TSTRING, "IMAGETYP", buf, "Image type"); +*/ + /* + // DATAMAX, DATAMIN / Max,min pixel value + int itmp = 0; + WRITEKEY(fp, TINT, "DATAMIN", &itmp, "Min pixel value"); + //itmp = G->fast ? 255 : 65535; + itmp = 65535; + WRITEKEY(fp, TINT, "DATAMAX", &itmp, "Max pixel value"); + WRITEKEY(fp, TUSHORT, "STATMAX", &max, "Max data value"); + WRITEKEY(fp, TUSHORT, "STATMIN", &min, "Min data value"); + WRITEKEY(fp, TDOUBLE, "STATAVR", &avr, "Average data value"); + WRITEKEY(fp, TDOUBLE, "STATSTD", &std, "Std. of data value"); + WRITEKEY(fp, TDOUBLE, "TEMP0", &G->temperature, "Camera temperature at exp. start (degr C)"); + */ + tmp = (double)G.exptime / 1000.; + // EXPTIME / actual exposition time (sec) + WRITEKEY(fp, TDOUBLE, "EXPTIME", &tmp, "Actual exposition time (sec)"); + // DATE / Creation date (YYYY-MM-DDThh:mm:ss, UTC) + strftime(buf, 80, "%Y-%m-%dT%H:%M:%S", gmtime(&savetime)); + WRITEKEY(fp, TSTRING, "DATE", buf, "Creation date (YYYY-MM-DDThh:mm:ss, UTC)"); +/* + startTime = (long)expStartsAt.tv_sec; + tm_starttime = localtime(&expStartsAt.tv_sec); + strftime(buf, 80, "exposition starts at %d/%m/%Y, %H:%M:%S (local)", tm_starttime); + tmp = startTime + (double)expStartsAt.tv_usec/1e6; + WRITEKEY(fp, TDOUBLE, "UNIXTIME", &tmp, buf); + strftime(buf, 80, "%Y/%m/%d", tm_starttime); + // DATE-OBS / DATE (YYYY/MM/DD) OF OBS. + WRITEKEY(fp, TSTRING, "DATE-OBS", buf, "DATE OF OBS. (YYYY/MM/DD, local)"); + strftime(buf, 80, "%H:%M:%S", tm_starttime); + // START / Measurement start time (local) (hh:mm:ss) + WRITEKEY(fp, TSTRING, "START", buf, "Measurement start time (hh:mm:ss, local)"); + */ + uint8_t *data = MALLOC(uint8_t, w*h); + // mirror upside down to make right image + for(int y = 0; y < h; y++){ + memcpy(&data[y * w], &convertedImage->pData[(h-y-1) * s], w); + } + int status = 0; + fits_write_img(fp, TBYTE, 1, w * h, data, &status); + if(status) fits_report_error(stderr, status); + FREE(data); + TRYFITS(fits_close_file, fp); + return 0; +} + +#undef TRYFITS +#undef WRITEKEY diff --git a/image_functions.h b/image_functions.h new file mode 100644 index 0000000..6ffbf96 --- /dev/null +++ b/image_functions.h @@ -0,0 +1,45 @@ +/* + * This file is part of the grasshopper project. + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#ifndef IMAGE_FUNCTIONS__ +#define IMAGE_FUNCTIONS__ + +#include +#include +#include "imageview.h" + +// functions for converting grayscale value into colour +typedef enum{ + COLORFN_LINEAR, // linear + COLORFN_LOG, // ln + COLORFN_SQRT, // sqrt + COLORFN_MAX // end of list +} colorfn_type; + +int GrabImage(fc2Context context, fc2Image *convertedImage); +void change_displayed_image(windowData *win, fc2Image *convertedImage); + +void gray2rgb(double gray, GLubyte *rgb); +colorfn_type get_colorfun(); +void change_colorfun(colorfn_type f); +void roll_colorfun(); + +int writefits(char *filename, fc2Image *convertedImage); + +#endif // IMAGE_FUNCTIONS__ diff --git a/imageview.c b/imageview.c index a082241..de4421d 100644 --- a/imageview.c +++ b/imageview.c @@ -111,25 +111,28 @@ static void createWindow(){ int killwindow(){ if(!win) return 0; glutSetWindow(win->ID); // obviously set window (for closing from menu) + pthread_mutex_lock(&win->mutex); if(!win->killthread){ - pthread_mutex_lock(&win->mutex); // say changed thread to die win->killthread = 1; - pthread_mutex_unlock(&win->mutex); } DBG("wait for changed thread"); pthread_join(win->thread, NULL); // wait while thread dies if(win->menu) glutDestroyMenu(win->menu); glutDestroyWindow(win->ID); - DBG("destroy texture %d", win->Tex); + DBG("destroy menu, wundow & texture %d", win->Tex); glDeleteTextures(1, &(win->Tex)); - glFinish(); + //glFinish(); + windowData *old = win; + win = NULL; DBG("free(rawdata)"); - FREE(win->image->rawdata); + FREE(old->image->rawdata); DBG("free(image)"); - FREE(win->image); + FREE(old->image); + pthread_mutex_unlock(&old->mutex); DBG("free(win)"); - FREE(win); + FREE(old); + DBG("return"); return 1; } @@ -202,8 +205,8 @@ static void *Redraw(_U_ void *arg){ FNAME(); while(1){ if(!initialized){ - DBG("!initialized"); - pthread_exit(NULL); + DBG("!initialized -> exit thread"); + return NULL; } if(win && win->ID > 0){ redisplay(win->ID); @@ -306,6 +309,7 @@ void clear_GL_context(){ DBG("kill"); killwindow(); DBG("join"); + //pthread_cancel(GLUTthread); pthread_join(GLUTthread, NULL); // wait while main thread exits DBG("main GL thread cancelled"); }