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

More progress on gradient star detection. Adding option to select which...

More progress on gradient star detection. Adding option to select which algorithm to use in Focus module
parent a663435e
......@@ -77,6 +77,8 @@ Focus::Focus()
reverseDir = false;
initialFocuserAbsPosition = -1;
focusAlgorithm = ALGORITHM_GRADIENT;
state = Ekos::FOCUS_IDLE;
pulseDuration = 1000;
......@@ -120,6 +122,16 @@ Focus::Focus()
// Reset star center on auto star check toggle
connect(autoStarCheck, &QCheckBox::toggled, this, [&](){starCenter = QVector3D();});
focusAlgorithm = static_cast<StarAlgorithm>(Options::focusAlgorithm());
focusAlgorithmCombo->setCurrentIndex(focusAlgorithm);
connect(focusAlgorithmCombo, static_cast<void (QComboBox::*) (int)>(&QComboBox::activated), this, [&](int index)
{
focusAlgorithm=static_cast<StarAlgorithm>(index);
thresholdSpin->setEnabled(focusAlgorithm == ALGORITHM_THRESHOLD);
Options::setFocusAlgorithm(index);
});
activeBin=Options::focusXBin();
binningCombo->setCurrentIndex(activeBin-1);
......@@ -214,10 +226,10 @@ Focus::Focus()
lockFilterCheck->setChecked(Options::lockFocusFilter());
darkFrameCheck->setChecked(Options::useFocusDarkFrame());
thresholdSpin->setValue(Options::focusThreshold());
focusFramesSpin->setValue(Options::focusFrames());
//focusFramesSpin->setValue(Options::focusFrames());
connect(thresholdSpin, SIGNAL(valueChanged(double)), this, SLOT(setThreshold(double)));
connect(focusFramesSpin, SIGNAL(valueChanged(int)), this, SLOT(setFrames(int)));
//connect(focusFramesSpin, SIGNAL(valueChanged(int)), this, SLOT(setFrames(int)));
focusView = new FITSView(focusingWidget);
focusView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
......@@ -226,6 +238,8 @@ Focus::Focus()
vlayout->addWidget(focusView);
focusingWidget->setLayout(vlayout);
connect(focusView, SIGNAL(trackingStarSelected(int,int)), this, SLOT(focusStarSelected(int,int)), Qt::UniqueConnection);
focusView->setStarsEnabled(true);
}
Focus::~Focus()
......@@ -696,7 +710,7 @@ void Focus::start()
if (Options::focusLogging())
qDebug() << "Focus: Starting focus with box size: " << focusBoxSize->value() << " Step Size: " << stepIN->value() << " Threshold: " << thresholdSpin->value() << " Tolerance: " << toleranceIN->value()
<< " Frames: " << focusFramesSpin->value() << " Maximum Travel: " << maxTravelIN->value();
<< " Frames: " << 1 /*focusFramesSpin->value()*/ << " Maximum Travel: " << maxTravelIN->value();
if (autoStarCheck->isChecked())
appendLogText(i18n("Autofocus in progress..."));
......@@ -1011,37 +1025,21 @@ void Focus::setCaptureComplete()
{
if (image_data->areStarsSearched() == false)
{
if (starSelected == false && autoStarCheck->isChecked())
{
image_data->findStars();
currentHFR= image_data->getHFR(HFR_MAX);
}
if (starSelected == false && autoStarCheck->isChecked() && subFramed == false)
focusView->findStars(ALGORITHM_CENTROID);
else if (focusView->isTrackingBoxEnabled())
{
Edge *center = FITSData::findCannyStar(image_data, focusView->getTrackingBox());
if (center)
currentHFR = center->HFR;
else
currentHFR = -1;
focusView->findStars(focusAlgorithm);
focusView->toggleStars(true);
//image_data->findStars(focusView->getTrackingBox());
}
focusView->updateFrame();
currentHFR= image_data->getHFR(HFR_MAX);
}
/*if (currentHFR == -1)
{
currentHFR = image_data->getHFR();
}*/
if (Options::focusLogging())
qDebug() << "Focus newFITS #" << frameNum+1 << ": Current HFR " << currentHFR;
HFRFrames[frameNum++] = currentHFR;
if (frameNum >= focusFramesSpin->value())
if (frameNum >= 1 /*focusFramesSpin->value()*/)
{
currentHFR=0;
for (int i=0; i < frameNum; i++)
......@@ -1261,9 +1259,6 @@ void Focus::setCaptureComplete()
drawProfilePlot();
if (inAutoFocus==false)
return;
if (Options::focusLogging())
{
QDir dir;
......@@ -1274,6 +1269,9 @@ void Focus::setCaptureComplete()
focusView->getImageData()->saveFITS(filename);
}
if (inAutoFocus==false)
return;
if (state != Ekos::FOCUS_PROGRESS)
{
state = Ekos::FOCUS_PROGRESS;
......@@ -2301,10 +2299,11 @@ void Focus::setThreshold(double value)
Options::setFocusThreshold(value);
}
void Focus::setFrames(int value)
// TODO remove from kstars.kcfg
/*void Focus::setFrames(int value)
{
Options::setFocusFrames(value);
}
}*/
void Focus::syncTrackingBoxPosition()
{
......
......@@ -48,7 +48,7 @@ public:
~Focus();
typedef enum { FOCUS_NONE, FOCUS_IN, FOCUS_OUT } FocusDirection;
typedef enum { FOCUS_AUTO, FOCUS_LOOP } FocusType;
typedef enum { FOCUS_AUTO, FOCUS_LOOP } FocusType;
/** @defgroup FocusDBusInterface Ekos DBus Interface - Focus Module
* Ekos::Focus interface provides advanced scripting capabilities to perform manual and automatic focusing operations.
......@@ -324,7 +324,7 @@ private slots:
void setThreshold(double value);
void setFrames(int value);
//void setFrames(int value);
void setCaptureComplete();
......@@ -374,6 +374,8 @@ private:
FocusDirection lastFocusDirection;
// What type of focusing are we doing right now?
FocusType focusType;
// Focus HFR & Centeroid algorithms
StarAlgorithm focusAlgorithm = ALGORITHM_GRADIENT;
/*********************
* HFR Club variables
......
......@@ -458,13 +458,13 @@ Otherwise, the autofocus process will utilize whatever filter currently set by t
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="3">
<widget class="QSpinBox" name="focusFramesSpin">
<property name="minimum">
<number>1</number>
<item row="4" column="2">
<widget class="QLabel" name="label_21">
<property name="toolTip">
<string>Star detection algorithm</string>
</property>
<property name="maximum">
<number>5</number>
<property name="text">
<string>Algorithm:</string>
</property>
</widget>
</item>
......@@ -478,26 +478,6 @@ Otherwise, the autofocus process will utilize whatever filter currently set by t
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_19">
<property name="toolTip">
<string>Increase to restrict the centroid to bright cores. Decrease to enclose fuzzy stars.</string>
</property>
<property name="text">
<string>Threshold (%):</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="whatsThis">
<string>Delay between two consequent focus images</string>
</property>
<property name="text">
<string>Box Size:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QDoubleSpinBox" name="maxTravelIN">
<property name="minimum">
......@@ -514,61 +494,68 @@ Otherwise, the autofocus process will utilize whatever filter currently set by t
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="thresholdSpin">
<item row="2" column="1">
<widget class="QSpinBox" name="stepIN">
<property name="minimum">
<double>90.000000000000000</double>
<number>1</number>
</property>
<property name="maximum">
<double>500.000000000000000</double>
<number>10000</number>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
<number>10</number>
</property>
<property name="value">
<double>150.000000000000000</double>
<number>250</number>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QDoubleSpinBox" name="toleranceIN">
<property name="minimum">
<double>0.010000000000000</double>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>&lt;b&gt;Initial&lt;/b&gt; step size in ticks to cause a noticeable change in HFR value. For timer based focuser, it is the initial time in milliseconds to move the focuser inward or outward</string>
</property>
<property name="maximum">
<double>20.000000000000000</double>
<property name="whatsThis">
<string/>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
<property name="text">
<string>Step:</string>
</property>
<property name="value">
<double>1.000000000000000</double>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_12">
<property name="toolTip">
<string>Maximum travel in ticks before the autofocus process aborts</string>
</property>
<property name="text">
<string>Max Travel:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="stepIN">
<item row="2" column="3">
<widget class="QDoubleSpinBox" name="toleranceIN">
<property name="minimum">
<number>1</number>
<double>0.010000000000000</double>
</property>
<property name="maximum">
<number>10000</number>
<double>20.000000000000000</double>
</property>
<property name="singleStep">
<number>10</number>
<double>0.100000000000000</double>
</property>
<property name="value">
<number>250</number>
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="label_21">
<item row="4" column="0">
<widget class="QLabel" name="label_19">
<property name="toolTip">
<string>Number of frames to average</string>
<string>Increase to restrict the centroid to bright cores. Decrease to enclose fuzzy stars.</string>
</property>
<property name="text">
<string>Frames:</string>
<string>Threshold (%):</string>
</property>
</widget>
</item>
......@@ -588,29 +575,54 @@ Otherwise, the autofocus process will utilize whatever filter currently set by t
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>&lt;b&gt;Initial&lt;/b&gt; step size in ticks to cause a noticeable change in HFR value. For timer based focuser, it is the initial time in milliseconds to move the focuser inward or outward</string>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="thresholdSpin">
<property name="enabled">
<bool>false</bool>
</property>
<property name="whatsThis">
<string/>
<property name="minimum">
<double>90.000000000000000</double>
</property>
<property name="text">
<string>Step:</string>
<property name="maximum">
<double>500.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>150.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_12">
<property name="toolTip">
<string>Maximum travel in ticks before the autofocus process aborts</string>
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="whatsThis">
<string>Delay between two consequent focus images</string>
</property>
<property name="text">
<string>Max Travel:</string>
<string>Box Size:</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QComboBox" name="focusAlgorithmCombo">
<item>
<property name="text">
<string>Gradient</string>
</property>
</item>
<item>
<property name="text">
<string>Centroid</string>
</property>
</item>
<item>
<property name="text">
<string>Threshold</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
......@@ -856,7 +868,6 @@ Otherwise, the autofocus process will utilize whatever filter currently set by t
<tabstop>stepIN</tabstop>
<tabstop>toleranceIN</tabstop>
<tabstop>thresholdSpin</tabstop>
<tabstop>focusFramesSpin</tabstop>
<tabstop>HFROut</tabstop>
<tabstop>clearDataB</tabstop>
</tabstops>
......
......@@ -22,5 +22,6 @@ typedef enum { FITS_WCS, FITS_VALUE, FITS_POSITION, FITS_ZOOM , FITS_RESOLUTION,
typedef enum { FITS_NONE, FITS_AUTO_STRETCH, FITS_HIGH_CONTRAST, FITS_EQUALIZE, FITS_HIGH_PASS, FITS_MEDIAN, FITS_ROTATE_CW, FITS_ROTATE_CCW, FITS_FLIP_H, FITS_FLIP_V, FITS_AUTO , FITS_LINEAR, FITS_LOG, FITS_SQRT, FITS_CUSTOM } FITSScale;
typedef enum { ZOOM_FIT_WINDOW, ZOOM_KEEP_LEVEL, ZOOM_FULL } FITSZoom;
typedef enum { HFR_AVERAGE, HFR_MAX } HFRType;
typedef enum { ALGORITHM_GRADIENT, ALGORITHM_CENTROID, ALGORITHM_THRESHOLD} StarAlgorithm;
#endif // FITSCOMMON_H
......@@ -556,16 +556,18 @@ bool FITSData::checkCollision(Edge* s1, Edge*s2)
return false;
}
Edge* FITSData::findCannyStar(FITSData *data, const QRect &boundary)
int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
{
int subX = boundary.isNull() ? 0 : boundary.x();
int subY = boundary.isNull() ? 0 : boundary.y();
int subW = subX + (boundary.isNull() ? data->getWidth() : boundary.width());
int subH = subY + (boundary.isNull() ? data->getHeight(): boundary.height());
int subW = (boundary.isNull() ? data->getWidth() : boundary.width());
int subH = (boundary.isNull() ? data->getHeight(): boundary.height());
uint16_t dataWidth = data->getWidth();
// #1 Find offsets
uint32_t size = subW * subH;
uint32_t offset = subX + subY * subW;
uint32_t offset = subX + subY * dataWidth;
// #2 Create new buffer
float *buffer = new float[size];
......@@ -596,6 +598,9 @@ Edge* FITSData::findCannyStar(FITSData *data, const QRect &boundary)
// and discarded whenever necessary. It won't work on noisy images unless this is done.
boundedImage->sobel(gradients, directions);
// Not needed anymore
delete boundedImage;
// #7 Calculate center of mass
float massX=0, massY=0, totalMass=0;
......@@ -609,20 +614,17 @@ Edge* FITSData::findCannyStar(FITSData *data, const QRect &boundary)
massX += x * pixel;
massY += y * pixel;
}
}
qDebug() << "Weighted Center is X: " << massX/totalMass << " Y: " << massY/totalMass;
}
Edge *center = new Edge;
center->width = -1;
center->x = massX/totalMass + 0.5;
center->y = massY/totalMass + 0.5;
center->HFR = 1;
center->HFR = 1;
// Maximum Radius
int maxR = qMin(subW-1, subH-1) / 2;
for (int r=maxR; r > 1; r--)
{
int pass=0;
......@@ -649,14 +651,18 @@ Edge* FITSData::findCannyStar(FITSData *data, const QRect &boundary)
}
}
qDebug() << "Weighted Center is X: " << center->x << " Y: " << center->y << " Width: " << center->width;
// If no stars were detected
if (center->width == -1)
return NULL;
{
delete center;
return 0;
}
// 30% fuzzy
//center->width += center->width*0.3 * (running_threshold / threshold);
double FSum=0, HF=0, TF=0;
const double resolution = 1.0/20.0;
......@@ -672,13 +678,13 @@ Edge* FITSData::findCannyStar(FITSData *data, const QRect &boundary)
QDebug deb = qDebug();
for (int i=0; i < subW; i++)
deb << origBuffer[i + cen_y * subW] << ",";
for (int i=subX; i < (subX+subW); i++)
deb << origBuffer[i + cen_y * dataWidth] << ",";
for (double x=leftEdge; x <= rightEdge; x += resolution)
{
//subPixels[x] = resolution * (image_buffer[static_cast<int>(floor(x)) + cen_y * stats.width] - min);
double slice = resolution * (origBuffer[static_cast<int>(floor(x)) + cen_y * subW]);
double slice = resolution * (origBuffer[static_cast<int>(floor(x)) + cen_y * dataWidth]);
FSum += slice;
subPixels.append(slice);
}
......@@ -710,7 +716,8 @@ Edge* FITSData::findCannyStar(FITSData *data, const QRect &boundary)
}
data->appendStar(center);
return center;
return 1;
}
......@@ -842,7 +849,7 @@ int FITSData::findOneStar(const QRectF &boundary)
// #1 Approximate HFR, accurate and reliable but quite variable to small changes in star flux
center->HFR = (k - 1 + ( (HF-lastTF)/(TF-lastTF) ) ) * resolution;
center->HFR = (k - 1 + ( (HF-lastTF)/(TF-lastTF) )*2 ) * resolution;
// #2 Not exactly HFR, but much more stable
//center->HFR = (k*resolution) * (HF/TF);
......@@ -852,8 +859,7 @@ int FITSData::findOneStar(const QRectF &boundary)
lastTF = TF;
}
return starCenters.size();
return 1;
}
/*** Find center of stars and calculate Half Flux Radius */
......@@ -1595,7 +1601,6 @@ int FITSData::findStars(const QRectF &boundary, bool force)
{
qDeleteAll(starCenters);
starCenters.clear();
findCentroid(boundary);
getHFR();
}
......
......@@ -73,7 +73,7 @@ class FITSData
{
public:
typedef enum { CHANNEL_ONE, CHANNEL_TWO, CHANNEL_THREE } ColorChannel;
typedef enum { CHANNEL_ONE, CHANNEL_TWO, CHANNEL_THREE } ColorChannel;
FITSData(FITSMode mode=FITS_NORMAL);
~FITSData();
......@@ -133,7 +133,7 @@ public:
int findOneStar(const QRectF &boundary);
// Find single star based on partially customized Canny edge detection
static Edge *findCannyStar(FITSData *data, const QRect &boundary = QRect());
static int findCannyStar(FITSData *data, const QRect &boundary = QRect());
// Half Flux Radius
Edge * getMaxHFRStar() { return maxHFRStar;}
......
......@@ -542,6 +542,8 @@ bool FITSView::loadFITS (const QString &inFilename , bool silent)
}
}
starsSearched = false;
setAlignment(Qt::AlignCenter);
if (isVisible())
......@@ -1204,30 +1206,56 @@ void FITSView::togglePixelGrid()
}
int FITSView::findStars(StarAlgorithm algorithm)
{
int count = 0;
if (trackingBoxEnabled)
{
switch (algorithm)
{
case ALGORITHM_GRADIENT:
count = FITSData::findCannyStar(image_data, trackingBox);
break;
case ALGORITHM_CENTROID:
count = image_data->findStars(trackingBox);
break;
case ALGORITHM_THRESHOLD:
count = image_data->findOneStar(trackingBox);
break;
}
}
else if (algorithm == ALGORITHM_GRADIENT)
{
QRect boundary(0,0, image_data->getWidth(), image_data->getHeight());
count = FITSData::findCannyStar(image_data, boundary);
}
else
{
count = image_data->findStars();
}
starAlgorithm = algorithm;
starsSearched = true;
return count;
}
void FITSView::toggleStars(bool enable)
{
markStars = enable;
if (markStars == true)
if (markStars == true && starsSearched == false)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
emit newStatus(i18n("Finding stars..."), FITS_MESSAGE);
qApp->processEvents();
int count = -1;
#if 0
if (trackingBoxEnabled)
{
count = image_data->findStars(trackingBox, trackingBoxUpdated);
trackingBoxUpdated=false;
}
else
count = image_data->findStars();
#endif
//QRectF boundary(0,0, image_data->getWidth(), image_data->getHeight());
//count = image_data->findOneStar(boundary);
FITSData::findCannyStar(image_data);
count = findStars(starAlgorithm);
if (count >= 0 && isVisible())
emit newStatus(i18np("1 star detected.", "%1 stars detected.", count), FITS_MESSAGE);
......
......@@ -90,8 +90,9 @@ signals:
class FITSView : public QScrollArea
{
Q_OBJECT
public:
FITSVie