7#include "fitshistogram.h"
15#include "fitsviewer.h"
19#include <QtConcurrent>
31 ui =
new histogramUI(
this);
32 tab =
dynamic_cast<FITSTab *
>(parent);
34 customPlot = ui->histogramPlot;
47 customPlot->xAxis->setTickLabelColor(
Qt::white);
48 customPlot->yAxis->setTickLabelColor(
Qt::white);
50 customPlot->xAxis->setLabelColor(
Qt::white);
51 customPlot->yAxis->setLabelColor(
Qt::white);
54 cumulativeFrequency.
resize(3);
63 rgbWidgets[RED_CHANNEL] << ui->RLabel << ui->minREdit << ui->redSlider
65 rgbWidgets[GREEN_CHANNEL] << ui->GLabel << ui->minGEdit << ui->greenSlider
67 rgbWidgets[BLUE_CHANNEL] << ui->BLabel << ui->minBEdit << ui->blueSlider
70 minBoxes << ui->minREdit << ui->minGEdit << ui->minBEdit;
71 maxBoxes << ui->maxREdit << ui->maxGEdit << ui->maxBEdit;
72 sliders << ui->redSlider << ui->greenSlider << ui->blueSlider;
78 customPlot->xAxis->grid()->setZeroLinePen(
Qt::NoPen);
79 customPlot->yAxis->grid()->setZeroLinePen(
Qt::NoPen);
90 &FITSHistogram::driftMouseOverLine);
92 for (
int i = 0; i < 3; i++)
99 w[2]->blockSignals(
true);
101 w[2]->blockSignals(
false);
106 w[2]->blockSignals(
true);
108 w[2]->blockSignals(
false);
124void FITSHistogram::showEvent(
QShowEvent * event)
128 constructHistogram();
132void FITSHistogram::constructHistogram()
138 switch (imageData->getStatistics().dataType)
176 m_Constructed =
true;
181template <
typename T>
void FITSHistogram::constructHistogram()
184 uint16_t
width = imageData->width(),
height = imageData->height();
185 uint8_t channels = imageData->channels();
187 auto *
const buffer =
reinterpret_cast<T
const *
>(imageData->getImageBuffer());
190 for (
int i = 0 ; i < 3; i++)
192 imageData->getMinMax(&min, &max, i);
198 const uint32_t
sampleBy = samples > 1000000 ? samples / 1000000 : 1;
201 binCount =
qMin(FITSMax[0] - FITSMin[0], 400.0);
205 for (
int n = 0; n < channels; n++)
207 intensity[n].fill(0, binCount);
208 frequency[n].fill(0, binCount);
209 cumulativeFrequency[n].fill(0, binCount);
210 binWidth[n] = (FITSMax[n] - FITSMin[n]) / (binCount - 1);
212 imageData->setMedian(0, n);
217 for (
int n = 0; n < channels; n++)
221 for (
int i = 0; i < binCount; i++)
222 intensity[n][i] = FITSMin[n] + (binWidth[n] * i);
226 for (
int n = 0; n < channels; n++)
230 uint32_t offset = n * samples;
232 for (uint32_t i = 0; i < samples; i +=
sampleBy)
234 int32_t
id =
rint((buffer[i + offset] - FITSMin[n]) / binWidth[n]);
243 future.waitForFinished();
247 for (
int n = 0; n < channels; n++)
252 for (
int i = 0; i < binCount; i++)
261 future.waitForFinished();
265 for (
int n = 0; n < channels; n++)
269 double median[3] = {0};
270 const bool cutoffSpikes = ui->hideSaturated->isChecked();
271 const uint32_t
halfCumulative = cumulativeFrequency[n][binCount - 1] / 2;
275 for (
int i = 0; i < binCount; i++)
301 const uint32_t offset = n * samples;
302 for (uint32_t i = 0; i < samples; i +=
sampleBy)
305 const int32_t
id =
rint((buffer[i + offset] - FITSMin[n]) / binWidth[n]);
321 imageData->setMedian(median[n], n);
328 for (
int i = 0; i < binCount; i++)
330 if (frequency[n][i] >=
cutoff)
339 future.waitForFinished();
342 if (cumulativeFrequency[RED_CHANNEL][binCount / 4] > 0)
343 JMIndex = cumulativeFrequency[RED_CHANNEL][binCount / 8] /
static_cast<double>(cumulativeFrequency[RED_CHANNEL][binCount /
347 qCDebug(
KSTARS_FITS) <<
"FITHistogram: JMIndex " << JMIndex;
351 for (
int n = 0; n < channels; n++)
353 sliderTick <<
fabs(FITSMax[n] - FITSMin[n]) / 99.0;
354 sliderScale << 99.0 / (FITSMax[n] - FITSMin[n] - sliderTick[n]);
358void FITSHistogram::syncGUI()
364 bool isColor = imageData->channels() > 1;
366 for (
auto w : rgbWidgets[RED_CHANNEL])
369 for (
auto w : rgbWidgets[GREEN_CHANNEL])
372 for (
auto w : rgbWidgets[BLUE_CHANNEL])
378 for (
int n = 0; n < imageData->channels(); n++)
380 double median = imageData->getMedian(n);
386 else if (median > .01)
388 else if (median > .0001)
393 minBoxes[n]->setDecimals(numDecimals[n]);
394 minBoxes[n]->setSingleStep(
fabs(FITSMax[n] - FITSMin[n]) / 20.0);
395 minBoxes[n]->setMinimum(FITSMin[n]);
396 minBoxes[n]->setMaximum(FITSMax[n] - sliderTick[n]);
397 minBoxes[n]->setValue(FITSMin[n] + (sliders[n]->minimumValue() / sliderScale[n]));
399 maxBoxes[n]->setDecimals(numDecimals[n]);
400 maxBoxes[n]->setSingleStep(
fabs(FITSMax[n] - FITSMin[n]) / 20.0);
401 maxBoxes[n]->setMinimum(FITSMin[n] + sliderTick[n]);
402 maxBoxes[n]->setMaximum(FITSMax[n]);
403 maxBoxes[n]->setValue(FITSMin[n] + sliderTick[n] + (sliders[n]->maximumValue() / sliderScale[n]));
409 for (
int n = 0; n < imageData->channels(); n++)
411 graphs.append(customPlot->
addGraph());
412 graphs[n]->setData(intensity[n], frequency[n]);
415 graphs[RED_CHANNEL]->setBrush(
QBrush(
QColor(170, 40, 80)));
420 graphs[GREEN_CHANNEL]->setBrush(
QBrush(
QColor(80, 40, 170)));
423 graphs[BLUE_CHANNEL]->setBrush(
QBrush(
QColor(170, 40, 80)));
449void FITSHistogram::resizePlot()
452 constructHistogram();
454 if (customPlot->
width() < 300)
461double FITSHistogram::getJMIndex()
const
466void FITSHistogram::applyScale()
470 min << minBoxes[0]->value() << minBoxes[1]->value() << minBoxes[2]->value();
471 max << maxBoxes[0]->value() << maxBoxes[1]->value() << maxBoxes[2]->value();
473 FITSHistogramCommand *
histC;
475 if (ui->logR->isChecked())
480 histC =
new FITSHistogramCommand(tab,
this, type, min, max);
485void FITSHistogram::applyFilter(FITSScale
ftype)
489 min.append(ui->minREdit->value());
491 FITSHistogramCommand *
histC;
495 histC =
new FITSHistogramCommand(tab,
this, type, min, max);
502 return cumulativeFrequency[channel];
505FITSHistogramCommand::FITSHistogramCommand(
QWidget * parent,
511 tab =
dynamic_cast<FITSTab *
>(parent);
518FITSHistogramCommand::~FITSHistogramCommand()
523bool FITSHistogramCommand::calculateDelta(
const uint8_t * buffer)
527 uint8_t
const *
image_buffer = imageData->getImageBuffer();
529 imageData->width() * imageData->height() * imageData->channels();
536 qWarning() <<
"Error! not enough memory to create image delta" <<
endl;
545 delta =
new uint8_t[compressedBytes];
547 if (delta ==
nullptr)
551 <<
"FITSHistogram Error: Ran out of memory compressing delta";
562 <<
"FITSHistogram Error: Failed to compress raw_delta";
574bool FITSHistogramCommand::reverseDelta()
576 FITSView * image = tab->getView();
578 uint8_t
const *
image_buffer = (imageData->getImageBuffer());
581 imageData->width() * imageData->height() * imageData->channels();
588 qWarning() <<
"Error! not enough memory to create output image" <<
endl;
597 qWarning() <<
"Error! not enough memory to create image delta" <<
endl;
605 <<
"FITSHistogram compression error in reverseDelta()";
621void FITSHistogramCommand::redo()
623 FITSView * image = tab->getView();
626 uint8_t
const *
image_buffer = imageData->getImageBuffer();
627 uint8_t * buffer =
nullptr;
629 imageData->width() * imageData->height() * imageData->channels();
630 int BBP = imageData->getBytesPerPixel();
634 if (delta !=
nullptr)
641 imageData->restoreStatistics(stats);
647 imageData->saveStatistics(stats);
652 imageData->applyFilter(type);
656 buffer =
new uint8_t[size *
BBP];
658 if (buffer ==
nullptr)
661 <<
"Error! not enough memory to create image buffer in redo()"
686 imageData->applyFilter(type);
690 calculateDelta(buffer);
695 if (histogram !=
nullptr)
697 histogram->constructHistogram();
699 if (tab->getViewer()->isStarsMarked())
700 imageData->findStars().waitForFinished();
703 image->pushFilter(type);
704 image->rescale(ZOOM_KEEP_LEVEL);
705 image->updateFrame();
710void FITSHistogramCommand::undo()
712 FITSView * image = tab->getView();
717 if (delta !=
nullptr)
724 imageData->restoreStatistics(stats);
733 imageData->applyFilter(FITS_ROTATE_CCW);
735 case FITS_ROTATE_CCW:
736 imageData->applyFilter(FITS_ROTATE_CW);
740 imageData->applyFilter(type);
747 if (histogram !=
nullptr)
749 histogram->constructHistogram();
751 if (tab->getViewer()->isStarsMarked())
752 imageData->findStars().waitForFinished();
756 image->rescale(ZOOM_KEEP_LEVEL);
757 image->updateFrame();
762QString FITSHistogramCommand::text()
const
767 return i18n(
"Auto Scale");
769 return i18n(
"Linear Scale");
771 return i18n(
"Logarithmic Scale");
773 return i18n(
"Square Root Scale");
776 if (type - 1 <= FITSViewer::filterTypes.count())
777 return FITSViewer::filterTypes.at(type - 1);
781 return i18n(
"Unknown");
784void FITSHistogram::driftMouseOverLine(
QMouseEvent * event)
789 uint8_t channels = imageData->channels();
793 for (
int n = 0; n < channels; n++)
805 if (customPlot->
xAxis->range().contains(intensity))
807 for (
int n = 0; n < channels; n++)
809 int index = graphs[n]->findBegin(intensity,
true);
810 freq[n] = graphs[n]->dataMainValue(index);
813 if (channels == 1 &&
freq[0] > 0)
817 i18nc(
"Histogram tooltip; %1 is intensity; %2 is frequency;",
819 "<tr><td>Intensity: </td><td>%1</td></tr>"
820 "<tr><td>R Frequency: </td><td>%2</td></tr>"
825 else if (
freq[1] > 0)
829 i18nc(
"Histogram tooltip; %1 is intensity; %2 is frequency;",
831 "<tr><td>Intensity: </td><td>%1</td></tr>"
832 "<tr><td>R Frequency: </td><td>%2</td></tr>"
833 "<tr><td>G Frequency: </td><td>%3</td></tr>"
834 "<tr><td>B Frequency: </td><td>%4</td></tr>"
The FITSTab class holds information on the current view (drawing area) in addition to the undo/redo s...
void setRangeZoom(Qt::Orientations orientations)
void setRangeDrag(Qt::Orientations orientations)
void setTickLabels(bool show)
void setLabel(const QString &str)
void rescale(bool onlyVisiblePlottables=false)
double pixelToCoord(double value) const
QSharedPointer< QCPAxisTicker > ticker() const
QCPGraph * addGraph(QCPAxis *keyAxis=nullptr, QCPAxis *valueAxis=nullptr)
void setInteraction(const QCP::Interaction &interaction, bool enabled=true)
void mouseMove(QMouseEvent *event)
Q_SLOT void replot(QCustomPlot::RefreshPriority refreshPriority=QCustomPlot::rpRefreshHint)
QCPAxisRect * axisRect(int index=0) const
void minimumValueChanged(int min)
This signal is emitted when the slider minimum value has changed, with the new slider value as argume...
void maximumValueChanged(int max)
This signal is emitted when the slider maximum value has changed, with the new slider value as argume...
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
@ iRangeDrag
0x001 Axis ranges are draggable (see QCPAxisRect::setRangeDrag, QCPAxisRect::setRangeDragAxes)
@ iSelectPlottables
0x008 Plottables are selectable (e.g. graphs, curves, bars,... see QCPAbstractPlottable)
@ iRangeZoom
0x002 Axis ranges are zoomable with the mouse wheel (see QCPAxisRect::setRangeZoom,...
void stateChanged(int state)
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
QString number(double n, char format, int precision)
QTextStream & endl(QTextStream &stream)
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
void push(QUndoCommand *cmd)