mirror of
https://github.com/eddyem/pointgreycam.git
synced 2025-12-06 02:35:22 +03:00
add save to FITS & hystogram equalization when displaying
This commit is contained in:
parent
a1cbbd613f
commit
3073be9d09
2
Makefile
2
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
|
||||
|
||||
@ -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);
|
||||
|
||||
1
events.c
1
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;
|
||||
|
||||
168
grasshopper.c
168
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();
|
||||
|
||||
320
image_functions.c
Normal file
320
image_functions.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* This file is part of the grasshopper project.
|
||||
* Copyright 2020 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/>.
|
||||
*/
|
||||
|
||||
#include <fitsio.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#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
|
||||
45
image_functions.h
Normal file
45
image_functions.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the grasshopper project.
|
||||
* Copyright 2020 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 IMAGE_FUNCTIONS__
|
||||
#define IMAGE_FUNCTIONS__
|
||||
|
||||
#include <C/FlyCapture2_C.h>
|
||||
#include <GL/glut.h>
|
||||
#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__
|
||||
22
imageview.c
22
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)
|
||||
if(!win->killthread){
|
||||
pthread_mutex_lock(&win->mutex);
|
||||
if(!win->killthread){
|
||||
// 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");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user