summaryrefslogtreecommitdiffstats
path: root/kstars/kstars/fitsprocess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kstars/kstars/fitsprocess.cpp')
-rw-r--r--kstars/kstars/fitsprocess.cpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/kstars/kstars/fitsprocess.cpp b/kstars/kstars/fitsprocess.cpp
new file mode 100644
index 00000000..60d3e539
--- /dev/null
+++ b/kstars/kstars/fitsprocess.cpp
@@ -0,0 +1,352 @@
+/***************************************************************************
+ fitsprocess.h - Image processing utilities
+ -------------------
+ begin : Tue Feb 24 2004
+ copyright : (C) 2004 by Jasem Mutlaq
+ email : mutlaqja@ikarustech.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ #include <kdebug.h>
+ #include <klocale.h>
+ #include <kprogress.h>
+ #include <kapplication.h>
+
+ #include <qimage.h>
+
+ #include "fitsprocess.h"
+ #include "fitsviewer.h"
+ #include "fitsimage.h"
+
+ #define ELEM_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; }
+
+ FITSProcess::FITSProcess(FITSViewer *parent, QStringList darkFiles, QStringList flatFiles, QStringList darkflatFiles, int darkMode, int flatMode, int darkflatMode)
+ {
+ float * buffer = NULL;
+ darkCombineMode = darkMode;
+ flatCombineMode = flatMode;
+ darkflatCombineMode = darkflatMode;
+ viewer = parent;
+ finalDark = NULL;
+ finalFlat = NULL;
+ finalDarkFlat = NULL;
+ npix = viewer->image->width * viewer->image->height;
+
+ darkFrames.setAutoDelete(true);
+ flatFrames.setAutoDelete(true);
+ darkflatFrames.setAutoDelete(true);
+
+ KProgressDialog reduceProgress(0, 0, i18n("FITS Viewer"), i18n("Image Loading Process..."));
+ reduceProgress.progressBar()->setTotalSteps(darkFiles.size() + flatFiles.size() + darkflatFiles.size());
+ reduceProgress.setMinimumWidth(300);
+ reduceProgress.show();
+
+ int nprogress = 0;
+
+ /* #1 Load dark frames */
+ for (unsigned int i=0; i < darkFiles.size(); i++)
+ {
+ if ( (buffer = viewer->loadData(darkFiles[i].ascii(), buffer)) == NULL)
+ {
+ kdDebug() << "Error loading dark file " << darkFiles[i] << endl;
+ break;
+ }
+
+ reduceProgress.progressBar()->setProgress(++nprogress);
+ kapp->processEvents();
+ darkFrames.append(buffer);
+ }
+
+ /* Load flat frames */
+ for (unsigned int i=0; i < flatFiles.size(); i++)
+ {
+ if ( (buffer = viewer->loadData(flatFiles[i].ascii(), buffer)) == NULL)
+ {
+ kdDebug() << "Error loading flat file " << flatFiles[i] << endl;
+ break;
+ }
+
+ reduceProgress.progressBar()->setProgress(++nprogress);
+ kapp->processEvents();
+ flatFrames.append(buffer);
+ }
+
+ /* Load dark frames for the flat field */
+ for (unsigned int i=0; i < darkflatFiles.size(); i++)
+ {
+ if ( (buffer = viewer->loadData(darkflatFiles[i].ascii(), buffer)) == NULL)
+ {
+ kdDebug() << "Error loading dark flat file " << darkflatFiles[i] << endl;
+ break;
+ }
+
+ reduceProgress.progressBar()->setProgress(++nprogress);
+ kapp->processEvents();
+ darkflatFrames.append(buffer);
+ }
+
+ }
+
+
+ FITSProcess::~FITSProcess() {}
+
+float * FITSProcess::combine(QPtrList<float> & frames, int mode)
+ {
+ int nframes = frames.count();
+ float *dest;
+ float *narray;
+
+ if (nframes == 0)
+ {
+ dest = NULL;
+ return dest;
+ }
+ else if (nframes == 1)
+ {
+ dest = frames.at(0);
+ return dest;
+ }
+
+ dest = frames.at(0);
+ narray = (float *) malloc (nframes * sizeof(float));
+
+ switch (mode)
+ {
+ /* Average */
+ case 0:
+ for (int i=0; i < npix; i++)
+ {
+ for (int j=0; j < nframes; j++)
+ narray[j] = *((frames.at(j)) + i);
+ dest[i] = average(narray, nframes);
+
+ }
+ break;
+ /* Median */
+ case 1:
+ for (int i=0; i < npix; i++)
+ {
+ for (int j=0; j < nframes; j++)
+ narray[j] = *((frames.at(j)) + i);
+ dest[i] = quick_select(narray, nframes);
+ }
+ break;
+ }
+
+ free(narray);
+ return dest;
+}
+
+ /*
+ * This Quickselect routine is based on the algorithm described in
+ * "Numerical recipies in C", Second Edition,
+ * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
+ */
+float FITSProcess::quick_select(float * arr, int n)
+{
+ int low, high ;
+ int median;
+ int middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+ if (high <= low) /* One element only */
+ return arr[median] ;
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median] ;
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+ float FITSProcess::average(float * array, int n)
+ {
+ double total=0;
+ for (int i=0; i < n; i++)
+ total += array[i];
+
+ return (total / n);
+ }
+
+
+ void FITSProcess::subtract(float * img1, float * img2)
+{
+ for (int i=0; i < npix; i++)
+ if (img1[i] < img2[i])
+ img1[i] = 0;
+ else img1[i] -= img2[i];
+
+}
+
+ void FITSProcess::divide(float * img1, float * img2)
+{
+ for (int i=0; i < npix; i++)
+ {
+ if (img2[i] == 0)
+ img1[i] = 0;
+ else
+ img1[i] = img1[i] / img2[i];
+ }
+
+}
+
+void FITSProcess::normalize(float *buf)
+{
+
+ float avg = average(buf, npix);
+ if (!avg) return;
+
+ if (avg < 0)
+ avg += abs((int) min(buf));
+
+ for (int i=0; i < npix; i++)
+ buf[i] = buf[i] / avg;
+
+}
+
+float FITSProcess::min(float *buf)
+{
+ float lmin= buf[0];
+
+ for (int i=1; i < npix; i++)
+ if (buf[i] < lmin) lmin = buf[i];
+
+ return lmin;
+}
+
+void FITSProcess::reduce()
+{
+ KProgressDialog reduceProgress(0, 0, i18n("FITS Viewer"), i18n("Image Reduction Process..."));
+ reduceProgress.progressBar()->setTotalSteps(20);
+ reduceProgress.setMinimumWidth(300);
+ reduceProgress.show();
+
+ reduceProgress.progressBar()->setProgress(1);
+ kapp->processEvents();
+
+ /* Combine darks */
+ finalDark = combine(darkFrames, darkCombineMode);
+
+ reduceProgress.progressBar()->setProgress(5);
+ kapp->processEvents();
+
+ /* Combine flats */
+ finalFlat = combine(flatFrames, flatCombineMode);
+ reduceProgress.progressBar()->setProgress(10);
+ kapp->processEvents();
+
+ /* Combine dark flats */
+ finalDarkFlat = combine(darkflatFrames, darkflatCombineMode);
+ reduceProgress.progressBar()->setProgress(12);
+ kapp->processEvents();
+
+ /* Subtract the dark frame */
+ if (finalDark)
+ subtract( viewer->imgBuffer, finalDark);
+ reduceProgress.progressBar()->setProgress(14);
+ kapp->processEvents();
+
+
+ /* Subtract the fark frame from the flat field and then apply to the image buffer */
+ if (finalFlat)
+ {
+ if (finalDarkFlat)
+ subtract( finalFlat, finalDarkFlat);
+ reduceProgress.progressBar()->setProgress(16);
+ kapp->processEvents();
+
+ normalize(finalFlat);
+ reduceProgress.progressBar()->setProgress(18);
+ kapp->processEvents();
+
+ divide(viewer->imgBuffer, finalFlat);
+ }
+
+ reduceProgress.progressBar()->setProgress(20);
+ kapp->processEvents();
+
+}
+
+FITSProcessCommand::FITSProcessCommand(FITSViewer *parent)
+{
+
+ viewer = parent;
+ oldImage = new QImage();
+ // TODO apply maximum compression against this buffer
+ buffer = (float *) malloc (viewer->image->width * viewer->image->height * sizeof(float));
+ memcpy(buffer, viewer->imgBuffer, viewer->image->width * viewer->image->height * sizeof(float));
+
+ }
+
+FITSProcessCommand::~FITSProcessCommand()
+{
+ free (buffer);
+ delete (oldImage);
+}
+
+void FITSProcessCommand::execute()
+{
+ memcpy(viewer->imgBuffer, buffer, viewer->image->width * viewer->image->height * sizeof(float));
+ *oldImage = viewer->image->displayImage->copy();
+}
+
+void FITSProcessCommand::unexecute()
+{
+
+ memcpy( viewer->imgBuffer, buffer, viewer->image->width * viewer->image->height * sizeof(float));
+ viewer->calculateStats();
+ *viewer->image->displayImage = oldImage->copy();
+ viewer->image->zoomToCurrent();
+
+}
+
+QString FITSProcessCommand::name() const
+{
+ return i18n("Image Reduction");
+}
+
+