Commit da173169 authored by Jasem Mutlaq's avatar Jasem Mutlaq
Browse files

Adding FITS image reduction capabilities to KStars. The FITS editor allows the...

Adding FITS image reduction capabilities to KStars. The FITS editor allows the user to view a fits file, and select a number of dark frame and flat field image which can be combined using different methods. The dark frame is removed and the result is then divided by the flat field, this remove any noice from the CCD and any optical peculiarities from the telescope.

The fits viewer is still in early stages though, and _many_ features need to be implemented. My main problem is that I couldn't find any quality flat field and dark frames with an image; if you know of source where I can download raw+dark+flat FITS, I highly appreciate it.

CCMAIL: kstars-devel@kde.org
CCMAIL: james@eecs.ku.edu

svn path=/trunk/kdeedu/kstars/; revision=291214
parent 74beaaec
bin_PROGRAMS = kstars
kstars_SOURCES = kspluto.cpp addcatdialog.cpp addlinkdialog.cpp astrocalc.cpp colorscheme.cpp detaildialog.cpp dmsbox.cpp dms.cpp altvstime.cpp filesource.cpp finddialog.cpp focusdialog.cpp geolocation.cpp imageviewer.cpp indidevice.cpp indidriver.cpp indimenu.cpp infobox.cpp infoboxes.cpp jmoontool.cpp jupitermoons.cpp ksasteroid.cpp kscomet.cpp ksfilereader.cpp ksmoon.cpp ksnumbers.cpp ksplanetbase.cpp ksplanet.cpp kspopupmenu.cpp kssun.cpp kstarsactions.cpp kstars.cpp kstarsdata.cpp kstarsdcop.cpp kstarsinit.cpp kstarsoptions.cpp kstars_options_handling.cpp kstarsplotwidget.cpp kstarssplash.cpp ksutils.cpp lcgenerator.cpp locationdialog.cpp magnitudespinbox.cpp main.cpp mapcanvas.cpp modcalcapcoord.cpp modcalcazel.cpp modcalcdaylength.cpp modcalcgalcoord.cpp modcalcgeodcoord.cpp modcalcjd.cpp modcalcprec.cpp modcalcsidtime.cpp objectnamelist.cpp planetcatalog.cpp planetviewer.cpp scriptbuilder.cpp scriptfunction.cpp simclock.cpp skymap.cpp skymapdraw.cpp skymapevents.cpp skyobject.cpp skyobjectname.cpp skypoint.cpp stardatasink.cpp starobject.cpp starpixmap.cpp telescopewizardprocess.cpp timebox.cpp timedialog.cpp timespinbox.cpp timestepbox.cpp timeunitbox.cpp timezonerule.cpp toggleaction.cpp viewopsdialog.cpp wutdialog.cpp argchangeviewoption.ui arglooktoward.ui argsetaltaz.ui argsetgeolocation.ui argsetlocaltime.ui argsetradec.ui argsettrack.ui argtimescale.ui argwaitforkey.ui argwaitfor.ui argzoom.ui devmanager.ui focusdialogdlg.ui indiconf.ui indihostconf.ui modcalcapcoorddlg.ui modcalcazeldlg.ui modcalcdaylengthdlg.ui modcalcgalcoorddlg.ui modcalcgeoddlg.ui modcalcjddlg.ui modcalcprecdlg.ui modcalcsidtimedlg.ui opsadvanced.ui opscatalog.ui opscolors.ui opsguides.ui opssolarsystem.ui optionstreeview.ui scriptbuilderui.ui scriptnamedialog.ui telescopewizard.ui kstarsinterface.skel simclockinterface.skel deepskyobject.cpp wutdialogui.ui fovdialog.cpp fovdialogui.ui newfovui.ui fov.cpp altvstimeui.ui indigroup.cpp indiproperty.cpp indielement.cpp devicemanager.cpp indistd.cpp kswizardui.ui kswizard.cpp csegment.cpp fitsviewer.cpp
kstars_SOURCES = kspluto.cpp addcatdialog.cpp addlinkdialog.cpp astrocalc.cpp colorscheme.cpp detaildialog.cpp dmsbox.cpp dms.cpp altvstime.cpp filesource.cpp finddialog.cpp focusdialog.cpp geolocation.cpp imageviewer.cpp indidevice.cpp indidriver.cpp indimenu.cpp infobox.cpp infoboxes.cpp jmoontool.cpp jupitermoons.cpp ksasteroid.cpp kscomet.cpp ksfilereader.cpp ksmoon.cpp ksnumbers.cpp ksplanetbase.cpp ksplanet.cpp kspopupmenu.cpp kssun.cpp kstarsactions.cpp kstars.cpp kstarsdata.cpp kstarsdcop.cpp kstarsinit.cpp kstarsoptions.cpp kstars_options_handling.cpp kstarsplotwidget.cpp kstarssplash.cpp ksutils.cpp lcgenerator.cpp locationdialog.cpp magnitudespinbox.cpp main.cpp mapcanvas.cpp modcalcapcoord.cpp modcalcazel.cpp modcalcdaylength.cpp modcalcgalcoord.cpp modcalcgeodcoord.cpp modcalcjd.cpp modcalcprec.cpp modcalcsidtime.cpp objectnamelist.cpp planetcatalog.cpp planetviewer.cpp scriptbuilder.cpp scriptfunction.cpp simclock.cpp skymap.cpp skymapdraw.cpp skymapevents.cpp skyobject.cpp skyobjectname.cpp skypoint.cpp stardatasink.cpp starobject.cpp starpixmap.cpp telescopewizardprocess.cpp timebox.cpp timedialog.cpp timespinbox.cpp timestepbox.cpp timeunitbox.cpp timezonerule.cpp toggleaction.cpp viewopsdialog.cpp wutdialog.cpp argchangeviewoption.ui arglooktoward.ui argsetaltaz.ui argsetgeolocation.ui argsetlocaltime.ui argsetradec.ui argsettrack.ui argtimescale.ui argwaitforkey.ui argwaitfor.ui argzoom.ui devmanager.ui focusdialogdlg.ui indiconf.ui indihostconf.ui modcalcapcoorddlg.ui modcalcazeldlg.ui modcalcdaylengthdlg.ui modcalcgalcoorddlg.ui modcalcgeoddlg.ui modcalcjddlg.ui modcalcprecdlg.ui modcalcsidtimedlg.ui opsadvanced.ui opscatalog.ui opscolors.ui opsguides.ui opssolarsystem.ui optionstreeview.ui scriptbuilderui.ui scriptnamedialog.ui telescopewizard.ui kstarsinterface.skel simclockinterface.skel deepskyobject.cpp wutdialogui.ui fovdialog.cpp fovdialogui.ui newfovui.ui fov.cpp altvstimeui.ui indigroup.cpp indiproperty.cpp indielement.cpp devicemanager.cpp indistd.cpp kswizardui.ui kswizard.cpp csegment.cpp fitsviewer.cpp conbridlg.cpp contrastbrightnessgui.ui fitsimage.cpp fitsprocess.cpp imagereductiondlg.cpp imagereductionui.ui
kstars_LDADD = indi/liblilxml.a indi/libindicom.a $(top_builddir)/libkdeedu/kdeeduplot/libkdeeduplot.la -lkdeprint -lm
......@@ -95,4 +95,4 @@ messages: rc.cpp stringsfile
$(XGETTEXT) *.cpp *.h -o $(podir)/kstars.pot;
rm -f tips.cpp
noinst_HEADERS = fovdialog.h indigroup.h indiproperty.h indielement.h devicemanager.h indistd.h fitsviewer.h
noinst_HEADERS = fovdialog.h indigroup.h indiproperty.h indielement.h devicemanager.h indistd.h fitsviewer.h conbridlg.h fitsimage.h fitsprocess.h imagereductiondlg.h
/***************************************************************************
conbridlg.h - Contrast/Brightness Dialog
-------------------
begin : Fri Feb 6th 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 <klocale.h>
#include <kimageeffect.h>
#include <kdebug.h>
#include <qslider.h>
#include <knuminput.h>
#include <stdlib.h>
#include "contrastbrightnessgui.h"
#include "conbridlg.h"
#include "fitsviewer.h"
#include "fitsimage.h"
//TODO find a better and faster way to implement this, this operation can be memory and CPU intensive.
ContrastBrightnessDlg::ContrastBrightnessDlg(QWidget *parent) :
KDialogBase(KDialogBase::Plain, i18n( "Brightness/Contrast" ), Ok|Cancel, Ok, parent )
{
contrast = brightness = 0;
viewer = (FITSViewer *) parent;
width = viewer->stats.width;
height = viewer->stats.height;
ConBriDlg = new ConBriForm(this);
if (!ConBriDlg) return;
localImgBuffer = (unsigned char *) malloc (width * height * sizeof(unsigned char));
if (!localImgBuffer)
{
kdDebug() << "Not enough memory for local image buffer" << endl;
return;
}
memcpy(localImgBuffer, viewer->image->reducedImgBuffer, width * height * sizeof(unsigned char));
setMainWidget(ConBriDlg);
this->show();
connect(ConBriDlg->conSlider, SIGNAL( valueChanged(int)), this, SLOT (setContrast(int )));
connect(ConBriDlg->briSlider, SIGNAL( valueChanged(int)), this, SLOT (setBrightness(int)));
}
ContrastBrightnessDlg::~ContrastBrightnessDlg()
{
}
void ContrastBrightnessDlg::setContrast(int contrastValue)
{
int val=0;
if (!viewer) return;
// #1 Apply Contrast
for (int i=0; i < height; i++)
for (int j=0; j < width; j++)
{
val = localImgBuffer[ i * width + j];
val = (val - 255.) * (-0.01 * -contrastValue) + val;
if (val > 255) val = 255;
if (val < 0) val = 0;
viewer->image->currentImage->setPixel(j, i, qRgb(val, val, val));
}
// #2 Apply brightness
if (brightness <= 64 && brightness >= -64)
KImageEffect::intensity(*viewer->image->currentImage, brightness/64.);
else if (brightness > 64)
{
KImageEffect::intensity(*viewer->image->currentImage, 1.);
KImageEffect::intensity(*viewer->image->currentImage, (brightness - 64.) / 64.);
}
else if (brightness < -64)
{
KImageEffect::intensity(*viewer->image->currentImage, -1.);
KImageEffect::intensity(*viewer->image->currentImage, (brightness + 64.) / 64.);
}
contrast = contrastValue;
viewer->image->convertImageToPixmap();
viewer->image->update();
//viewer->paintEvent(NULL);
}
void ContrastBrightnessDlg::setBrightness(int brightnessValue)
{
int val = 0;
if (!viewer) return;
// #1 Apply Contrast
for (int i=0; i < height; i++)
for (int j=0; j < width; j++)
{
val = localImgBuffer[ i * width + j];
val = (val - 255.) * (-0.01 * -contrast) + val;
//val += brightness;
if (val > 255) val = 255;
if (val < 0) val = 0;
viewer->image->currentImage->setPixel(j, i, qRgb(val, val, val));
}
// #2 Apply brightness
if (brightness <= 64 && brightness >= -64)
KImageEffect::intensity(*viewer->image->currentImage, brightness/64.);
else if (brightness > 64)
{
KImageEffect::intensity(*viewer->image->currentImage, 1.);
KImageEffect::intensity(*viewer->image->currentImage, (brightness - 64.) / 64.);
}
else if (brightness < -64)
{
KImageEffect::intensity(*viewer->image->currentImage, -1.);
KImageEffect::intensity(*viewer->image->currentImage, (brightness + 64.) / 64.);
}
brightness = brightnessValue;
viewer->image->convertImageToPixmap();
viewer->image->update();
//viewer->paintEvent(NULL);
}
QSize ContrastBrightnessDlg::sizeHint() const
{
return QSize(400,130);
}
/***************************************************************************
conbridlg.h - Contrast/Brightness Dialog
-------------------
begin : Fri Feb 6th 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. *
* *
* *
***************************************************************************/
#ifndef CONTRASTBRIGHTNESSDLG_H
#define CONTRASTBRIGHTNESSDLG_H
#include <kdialogbase.h>
class ConBriForm;
class FITSViewer;
class ContrastBrightnessDlg : public KDialogBase {
Q_OBJECT
public:
ContrastBrightnessDlg(QWidget *parent=0);
~ContrastBrightnessDlg();
QSize sizeHint() const;
private:
int contrast;
int brightness;
int height;
int width;
FITSViewer *viewer;
ConBriForm *ConBriDlg;
unsigned char *localImgBuffer;
unsigned char *templateImgBuffer;
public slots:
void setContrast(int contrastValue);
void setBrightness(int brightnessValue);
};
#endif
<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
<class>ConBriForm</class>
<widget class="QWidget">
<property name="name">
<cstring>ConBriForm</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>398</width>
<height>88</height>
</rect>
</property>
<property name="caption">
<string>Contrast/Brightness</string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QSlider" row="0" column="1">
<property name="name">
<cstring>briSlider</cstring>
</property>
<property name="minValue">
<number>-128</number>
</property>
<property name="maxValue">
<number>128</number>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
<property name="tickmarks">
<enum>NoMarks</enum>
</property>
</widget>
<widget class="QLabel" row="1" column="0">
<property name="name">
<cstring>conLabel</cstring>
</property>
<property name="text">
<string>Contrast</string>
</property>
</widget>
<widget class="KIntSpinBox" row="0" column="2">
<property name="name">
<cstring>briSpinBox</cstring>
</property>
<property name="maxValue">
<number>128</number>
</property>
<property name="minValue">
<number>-128</number>
</property>
</widget>
<widget class="KIntSpinBox" row="1" column="2">
<property name="name">
<cstring>conSpinBox</cstring>
</property>
<property name="maxValue">
<number>128</number>
</property>
<property name="minValue">
<number>-128</number>
</property>
</widget>
<widget class="QLabel" row="0" column="0">
<property name="name">
<cstring>briLabel</cstring>
</property>
<property name="text">
<string>Brightness</string>
</property>
</widget>
<widget class="QSlider" row="1" column="1">
<property name="name">
<cstring>conSlider</cstring>
</property>
<property name="minValue">
<number>-128</number>
</property>
<property name="maxValue">
<number>128</number>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
</widget>
</grid>
</widget>
<customwidgets>
</customwidgets>
<connections>
<connection>
<sender>briSlider</sender>
<signal>sliderMoved(int)</signal>
<receiver>briSpinBox</receiver>
<slot>setValue(int)</slot>
</connection>
<connection>
<sender>briSpinBox</sender>
<signal>valueChanged(int)</signal>
<receiver>briSlider</receiver>
<slot>setValue(int)</slot>
</connection>
<connection>
<sender>conSlider</sender>
<signal>sliderMoved(int)</signal>
<receiver>conSpinBox</receiver>
<slot>setValue(int)</slot>
</connection>
<connection>
<sender>conSpinBox</sender>
<signal>valueChanged(int)</signal>
<receiver>conSlider</receiver>
<slot>setValue(int)</slot>
</connection>
</connections>
<layoutdefaults spacing="6" margin="11"/>
<includehints>
<includehint>knuminput.h</includehint>
<includehint>knuminput.h</includehint>
</includehints>
</UI>
/***************************************************************************
FITSImage.cpp - FITS Image
-------------------
begin : Thu Jan 22 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. *
* *
* Some code fragments were adapted from Peter Kirchgessner's FITS plugin*
* See http://members.aol.com/pkirchg for more details. *
***************************************************************************/
#include <klocale.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kaction.h>
#include <kaccel.h>
#include <kdebug.h>
#include <ktoolbar.h>
#include <kapplication.h>
#include <kpixmap.h>
#include <ktempfile.h>
#include <kimageeffect.h>
#include <kmenubar.h>
#include <kprogress.h>
#include <kstatusbar.h>
#include <qfile.h>
#include <qvbox.h>
#include <qcursor.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include "fitsimage.h"
#include "fitsviewer.h"
//#include "focusdialog.h"
#include "ksutils.h"
/* Load info */
typedef struct
{
uint replace; /* replacement for blank/NaN-values */
uint use_datamin;/* Use DATAMIN/MAX-scaling if possible */
uint compose; /* compose images with naxis==3 */
} FITSLoadVals;
static FITSLoadVals plvals =
{
0, /* Replace with black */
0, /* Do autoscale on pixel-values */
0 /* Dont compose images */
};
FITSImage::FITSImage(QWidget * parent, const char * name) : QScrollView(parent, name)
{
viewer = (FITSViewer *) parent;
reducedImgBuffer = NULL;
currentImage = NULL;
imgFrame = new QFrame(viewport());
addChild(imgFrame);
viewport()->setMouseTracking(true);
imgFrame->setMouseTracking(true);
}
FITSImage::~FITSImage()
{
free(reducedImgBuffer);
}
void FITSImage::drawContents ( QPainter * p, int clipx, int clipy, int clipw, int cliph )
{
//kdDebug() << "in draw contents " << endl;
bitBlt(imgFrame, 0, 0, &qpix);
}
/**Bitblt the image onto the viewer widget */
void FITSImage::paintEvent (QPaintEvent *ev)
{
// kdDebug() << "in paint event " << endl;
bitBlt(imgFrame, 0, 0, &qpix);
}
/* Resize event */
void FITSImage::resizeEvent (QResizeEvent *ev)
{
updateScrollBars();
}
void FITSImage::contentsMouseMoveEvent ( QMouseEvent * e )
{
int x,y;
bool validPoint = true;
if (!currentImage) return;
if (imgFrame->x() > 0)
x = e->x() - imgFrame->x();
else
x = e->x();
if (x < 0 || x > currentImage->width())
validPoint = false;
//kdDebug() << "regular x= " << e->x() << " -- X= " << x << " -- imgFrame->x()= " << imgFrame->x() << " - currentImageWidth= " << viewer->currentImage->width() << endl;
if (imgFrame->y() > 0)
y = e->y() - imgFrame->y();
else
y = e->y();
if (y < 0 || y > currentImage->height())
validPoint = false;
else
// invert the Y since we read FITS buttom up
y = currentImage->height() - y;
//kdDebug() << "X= " << x << " -- Y= " << y << endl;
if (viewer->imgBuffer == NULL)
kdDebug() << "viewer buffer is NULL " << endl;
if (validPoint)
{
viewer->statusBar()->changeItem(QString("(%1,%2) Value= %3").arg(x,4).arg(y,-4).arg(viewer->imgBuffer[y * imgFrame->width() + x], -6), 0);
setCursor(Qt::CrossCursor);
}
else
{
viewer->statusBar()->changeItem(QString("(X,Y)"), 0);
setCursor(Qt::ArrowCursor);
}
}
void FITSImage::viewportResizeEvent ( QResizeEvent * e)
{
int w, h, x, y;
if (!currentImage) return;
w = viewport()->width();
h = viewport()->height();
if ( w > contentsWidth() )
x = (int) ( (w - contentsWidth()) / 2.);
else
x = 0;
if ( h > contentsHeight() )
y = (int) ( (h - contentsHeight()) / 2.);
else
y = 0;
//kdDebug() << "X= " << x << " -- Y= " << y << endl;
moveChild( imgFrame, x, y );
}
void FITSImage::reLoadTemplateImage()
{
*currentImage = templateImage->copy();
}
void FITSImage::saveTemplateImage()
{
templateImage = new QImage(currentImage->copy());
//*templateImage = currentImage->copy();
}
void FITSImage::destroyTemplateImage()
{
delete (templateImage);
}
void FITSImage::rescale()
{
int val;
viewer->calculateStats();
for (int i=0; i < height; i++)
for (int j=0; j < width; j++)
{
val = (int) (255. * ( (double) (viewer->imgBuffer[i * width + j] - viewer->stats.min) / (double) (viewer->stats.max - viewer->stats.min)));
currentImage->setPixel(j, height - i - 1, qRgb(val, val, val));
}
convertImageToPixmap();
update();
}
int FITSImage::loadFits (const char *filename)
{
FILE *fp;
FITS_FILE *ifp;
FITS_HDU_LIST *hdulist;
FITS_PIX_TRANSFORM trans;
register unsigned char *dest;
unsigned char *data;
int i, j, val;
double a, b;
int err = 0;
fp = fopen (filename, "rb");
if (!fp)
{
KMessageBox::error(0, i18n("Can't open file for reading"));
return (-1);
}
fclose (fp);
ifp = fits_open (filename, "r");
if (ifp == NULL)
{
KMessageBox::error(0, i18n("Error during open of FITS file"));
return (-1);
}
if (ifp->n_pic <= 0)
{
KMessageBox::error(0, i18n("FITS file keeps no displayable images"));
fits_close (ifp);
return (-1);
}
currentImage = new QImage();
KProgressDialog fitsProgress(this, 0, i18n("FITS Viewer"), i18n("Loading FITS..."));
hdulist = fits_seek_image (ifp, 1);
if (hdulist == NULL) return (-1);
width = hdulist->naxisn[0];
height = hdulist->naxisn[1];
bitpix = hdulist->bitpix;
bpp = hdulist->bpp;
imgFrame->setGeometry(0, 0, width, height);
data = (unsigned char *) malloc (height * width * sizeof(unsigned char));
if (data == NULL)
{
KMessageBox::error(0, i18n("Not enough memory to load FITS."));
return (-1);
}
/* If the transformation from pixel value to */
/* data value has been specified, use it */
if ( plvals.use_datamin
&& hdulist->used.datamin && hdulist->used.datamax
&& hdulist->used.bzero && hdulist->used.bscale)
{
a = (hdulist->datamin - hdulist->bzero) / hdulist->bscale;
b = (hdulist->datamax - hdulist->bzero) / hdulist->bscale;
if (a < b) trans.pixmin = a, trans.pixmax = b;
else trans.pixmin = b, trans.pixmax = a;
}
else
{
trans.pixmin = hdulist->pixmin;
trans.pixmax = hdulist->pixmax;
}
trans.datamin = 0.0;
trans.datamax = 255.0;