Stretch and calculate stats on demand
This commit is contained in:
+3
-5
@@ -257,21 +257,19 @@ void LoadRunable::run()
|
|||||||
rawImage = new RawImage(img);
|
rawImage = new RawImage(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rawImage)
|
|
||||||
rawImage->calcStats();
|
|
||||||
|
|
||||||
if(rawImage && m_analyzeLevel >= Statistics)
|
if(rawImage && m_analyzeLevel >= Statistics)
|
||||||
{
|
{
|
||||||
double mean, median, min, max;
|
double mean, median, min, max, mad;
|
||||||
double stdDev;
|
double stdDev;
|
||||||
timer.start();
|
timer.start();
|
||||||
rawImage->imageStats(&mean, &stdDev, &median, &min, &max);
|
rawImage->imageStats(&mean, &stdDev, &median, &min, &max, &mad);
|
||||||
qDebug() << "image stats" << timer.restart();
|
qDebug() << "image stats" << timer.restart();
|
||||||
info.append(StringPair(QObject::tr("Mean"), QString::number(mean)));
|
info.append(StringPair(QObject::tr("Mean"), QString::number(mean)));
|
||||||
info.append(StringPair(QObject::tr("Standart deviation"), QString::number(stdDev)));
|
info.append(StringPair(QObject::tr("Standart deviation"), QString::number(stdDev)));
|
||||||
info.append(StringPair(QObject::tr("Median"), QString::number(median)));
|
info.append(StringPair(QObject::tr("Median"), QString::number(median)));
|
||||||
info.append(StringPair(QObject::tr("Minimum"), QString::number(min)));
|
info.append(StringPair(QObject::tr("Minimum"), QString::number(min)));
|
||||||
info.append(StringPair(QObject::tr("Maximum"), QString::number(max)));
|
info.append(StringPair(QObject::tr("Maximum"), QString::number(max)));
|
||||||
|
info.append(StringPair(QObject::tr("MAD"), QString::number(mad)));
|
||||||
|
|
||||||
if(m_analyzeLevel >= Peaks)
|
if(m_analyzeLevel >= Peaks)
|
||||||
{
|
{
|
||||||
|
|||||||
+6
-7
@@ -1,5 +1,4 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "stretchpanel.h"
|
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
@@ -34,23 +33,24 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
infoDock->setWidget(m_info);
|
infoDock->setWidget(m_info);
|
||||||
infoDock->setObjectName("infoDock");
|
infoDock->setObjectName("infoDock");
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, infoDock);
|
addDockWidget(Qt::LeftDockWidgetArea, infoDock);
|
||||||
m_image = new ImageScrollArea(this);
|
//m_image = new ImageScrollArea(this);
|
||||||
m_image->resize(0,0);
|
//m_image->resize(0,0);
|
||||||
//setCentralWidget(m_image);
|
//setCentralWidget(m_image);
|
||||||
resize(800, 600);
|
resize(800, 600);
|
||||||
|
|
||||||
m_imageGL = new ImageScrollAreaGL(this);
|
m_imageGL = new ImageScrollAreaGL(this);
|
||||||
setCentralWidget(m_imageGL);
|
setCentralWidget(m_imageGL);
|
||||||
|
|
||||||
StretchPanel *stretchPanel = new StretchPanel(this);
|
m_stretchPanel = new StretchPanel(this);
|
||||||
connect(stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float)));
|
connect(m_stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float)));
|
||||||
|
connect(m_stretchPanel, &StretchPanel::autoStretch, [&](){ m_stretchPanel->stretchImage(m_ringList->currentImage().get()); });
|
||||||
|
|
||||||
m_ringList = new ImageRingList(this);
|
m_ringList = new ImageRingList(this);
|
||||||
m_filesystem = new FilesystemWidget(m_ringList, this);
|
m_filesystem = new FilesystemWidget(m_ringList, this);
|
||||||
connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int)));
|
connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int)));
|
||||||
|
|
||||||
QDockWidget *stretchDock = new QDockWidget(tr("Stretch"), this);
|
QDockWidget *stretchDock = new QDockWidget(tr("Stretch"), this);
|
||||||
stretchDock->setWidget(stretchPanel);
|
stretchDock->setWidget(m_stretchPanel);
|
||||||
stretchDock->setObjectName("strechDock");
|
stretchDock->setObjectName("strechDock");
|
||||||
addDockWidget(Qt::TopDockWidgetArea, stretchDock);
|
addDockWidget(Qt::TopDockWidgetArea, stretchDock);
|
||||||
|
|
||||||
@@ -62,7 +62,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
setWindowTitle(tr("Tenmon"));
|
setWindowTitle(tr("Tenmon"));
|
||||||
|
|
||||||
connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*)));
|
connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*)));
|
||||||
connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), stretchPanel, SLOT(imageLoaded(Image*)));
|
|
||||||
connect(m_ringList, SIGNAL(currentImageChanged(int)), this, SLOT(updateWindowTitle()));
|
connect(m_ringList, SIGNAL(currentImageChanged(int)), this, SLOT(updateWindowTitle()));
|
||||||
connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(ImageInfoData)));
|
connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(ImageInfoData)));
|
||||||
connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int)));
|
connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int)));
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "imageinfo.h"
|
#include "imageinfo.h"
|
||||||
#include "imagescrollareagl.h"
|
#include "imagescrollareagl.h"
|
||||||
#include "filesystemwidget.h"
|
#include "filesystemwidget.h"
|
||||||
|
#include "stretchpanel.h"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
@@ -16,6 +17,7 @@ class MainWindow : public QMainWindow
|
|||||||
ImageScrollArea *m_image;
|
ImageScrollArea *m_image;
|
||||||
ImageScrollAreaGL *m_imageGL;
|
ImageScrollAreaGL *m_imageGL;
|
||||||
ImageRingList *m_ringList;
|
ImageRingList *m_ringList;
|
||||||
|
StretchPanel *m_stretchPanel;
|
||||||
Database *m_database;
|
Database *m_database;
|
||||||
ImageInfo *m_info;
|
ImageInfo *m_info;
|
||||||
FilesystemWidget *m_filesystem;
|
FilesystemWidget *m_filesystem;
|
||||||
|
|||||||
+37
-16
@@ -52,17 +52,19 @@ int Type2CV(RawImage::ImgType type)
|
|||||||
|
|
||||||
RawImage::RawImage()
|
RawImage::RawImage()
|
||||||
{
|
{
|
||||||
|
m_stats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawImage::RawImage(int w, int h, ImgType type)
|
RawImage::RawImage(int w, int h, ImgType type)
|
||||||
{
|
{
|
||||||
m_img.create(h, w, Type2CV(type));
|
m_img.create(h, w, Type2CV(type));
|
||||||
|
m_stats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawImage::RawImage(cv::Mat &img)
|
RawImage::RawImage(cv::Mat &img)
|
||||||
{
|
{
|
||||||
m_img = img;
|
m_img = img;
|
||||||
calcStats();
|
m_stats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawImage::RawImage(const RawImage &d)
|
RawImage::RawImage(const RawImage &d)
|
||||||
@@ -73,6 +75,8 @@ RawImage::RawImage(const RawImage &d)
|
|||||||
m_median = d.m_median;
|
m_median = d.m_median;
|
||||||
m_min = d.m_min;
|
m_min = d.m_min;
|
||||||
m_max = d.m_max;
|
m_max = d.m_max;
|
||||||
|
m_mad = d.m_mad;
|
||||||
|
m_stats = d.m_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawImage::RawImage(const QImage &img)
|
RawImage::RawImage(const QImage &img)
|
||||||
@@ -91,33 +95,44 @@ RawImage::RawImage(const QImage &img)
|
|||||||
for(int i=0; i<tmp.height(); i++)
|
for(int i=0; i<tmp.height(); i++)
|
||||||
std::memcpy(m_img.ptr(i), tmp.scanLine(i), tmp.width()*3);
|
std::memcpy(m_img.ptr(i), tmp.scanLine(i), tmp.width()*3);
|
||||||
}
|
}
|
||||||
calcStats();
|
m_stats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RawImage::imageStats(double *mean, double *stdDev, double *median, double *min, double *max) const
|
bool RawImage::imageStats(double *mean, double *stdDev, double *median, double *min, double *max, double *mad)
|
||||||
{
|
{
|
||||||
|
if(!m_stats)calcStats();
|
||||||
if(mean)*mean = m_mean;
|
if(mean)*mean = m_mean;
|
||||||
if(stdDev)*stdDev = m_stdDev;
|
if(stdDev)*stdDev = m_stdDev;
|
||||||
if(median)*median = m_median;
|
if(median)*median = m_median;
|
||||||
if(min)*min = m_min;
|
if(min)*min = m_min;
|
||||||
if(max)*max = m_max;
|
if(max)*max = m_max;
|
||||||
|
if(mad)*mad = m_mad;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawImage::calcStats()
|
void RawImage::calcStats()
|
||||||
{
|
{
|
||||||
|
if(m_stats)return;
|
||||||
|
m_stats = true;
|
||||||
|
|
||||||
cv::Scalar meanS, stdDevS;
|
cv::Scalar meanS, stdDevS;
|
||||||
|
|
||||||
cv::meanStdDev(m_img, meanS, stdDevS);
|
cv::meanStdDev(m_img, meanS, stdDevS);
|
||||||
cv::minMaxIdx(m_img, &m_min, &m_max);
|
cv::minMaxIdx(m_img, &m_min, &m_max);
|
||||||
|
|
||||||
|
cv::Mat img;
|
||||||
|
if(m_img.channels() == 1)img = m_img;
|
||||||
|
else if (m_img.channels() == 3)cv::cvtColor(m_img, img, cv::COLOR_BGR2GRAY);
|
||||||
|
else if (m_img.channels() == 4)cv::cvtColor(m_img, img, cv::COLOR_BGRA2GRAY);
|
||||||
|
|
||||||
int histSize = 256;
|
int histSize = 256;
|
||||||
if(m_img.type() == CV_16U || m_img.type() == CV_32F)histSize = 65536;
|
if(img.type() == CV_16U || img.type() == CV_32F)histSize = 65536;
|
||||||
float range[] = {0, (float)histSize};
|
float range[] = {0, (float)histSize};
|
||||||
|
if(img.type() == CV_32F)range[1] = 1.0f;
|
||||||
const float *ranges[] = {range};
|
const float *ranges[] = {range};
|
||||||
cv::Mat hist;
|
cv::Mat hist;
|
||||||
cv::calcHist(&m_img, 1, nullptr, cv::Mat(), hist, 1, &histSize, ranges);
|
cv::calcHist(&img, 1, nullptr, cv::Mat(), hist, 1, &histSize, ranges);
|
||||||
|
|
||||||
m_mean = meanS[0];
|
m_mean = meanS[0];
|
||||||
m_stdDev = stdDevS[0];
|
m_stdDev = stdDevS[0];
|
||||||
@@ -133,7 +148,7 @@ void RawImage::calcStats()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cv::Mat absDev;
|
cv::Mat absDev;
|
||||||
m_img.convertTo(absDev, CV_32F, 1, -m_median);
|
img.convertTo(absDev, CV_32F, 1, -m_median);
|
||||||
absDev = cv::abs(absDev);
|
absDev = cv::abs(absDev);
|
||||||
cv::Mat madHist;
|
cv::Mat madHist;
|
||||||
medianSum = 0;
|
medianSum = 0;
|
||||||
@@ -218,6 +233,22 @@ RawImage::ImgType RawImage::type() const
|
|||||||
return CV2Type(m_img.type());
|
return CV2Type(m_img.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t RawImage::norm() const
|
||||||
|
{
|
||||||
|
switch(m_img.type())
|
||||||
|
{
|
||||||
|
case CV_8U:
|
||||||
|
case CV_8UC3:
|
||||||
|
case CV_8UC4:
|
||||||
|
return UINT8_MAX;
|
||||||
|
case CV_16U:
|
||||||
|
case CV_16UC3:
|
||||||
|
return UINT16_MAX;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* RawImage::data()
|
void* RawImage::data()
|
||||||
{
|
{
|
||||||
return m_img.ptr();
|
return m_img.ptr();
|
||||||
@@ -227,13 +258,3 @@ const void *RawImage::data() const
|
|||||||
{
|
{
|
||||||
return m_img.ptr();
|
return m_img.ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
float RawImage::stretchFactor() const
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
double RawImage::MAD() const
|
|
||||||
{
|
|
||||||
return m_mad;
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-3
@@ -35,6 +35,7 @@ class RawImage
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
cv::Mat m_img;
|
cv::Mat m_img;
|
||||||
|
bool m_stats;
|
||||||
double m_mean;
|
double m_mean;
|
||||||
double m_stdDev;
|
double m_stdDev;
|
||||||
double m_median;
|
double m_median;
|
||||||
@@ -58,7 +59,7 @@ public:
|
|||||||
RawImage(cv::Mat &img);
|
RawImage(cv::Mat &img);
|
||||||
RawImage(const RawImage &d);
|
RawImage(const RawImage &d);
|
||||||
RawImage(const QImage &img);
|
RawImage(const QImage &img);
|
||||||
bool imageStats(double *mean, double *stdDev, double *median, double *min, double *max) const;
|
bool imageStats(double *mean, double *stdDev, double *median, double *min, double *max, double *mad);
|
||||||
void calcStats();
|
void calcStats();
|
||||||
void rect(int &x, int &y, int w, int h, std::vector<double> &r) const;
|
void rect(int &x, int &y, int w, int h, std::vector<double> &r) const;
|
||||||
int findPeaks(double background, double distance, std::vector<Peak> &peaks) const;
|
int findPeaks(double background, double distance, std::vector<Peak> &peaks) const;
|
||||||
@@ -68,10 +69,9 @@ public:
|
|||||||
uint32_t height() const;
|
uint32_t height() const;
|
||||||
uint32_t size() const;
|
uint32_t size() const;
|
||||||
ImgType type() const;
|
ImgType type() const;
|
||||||
|
uint32_t norm() const;
|
||||||
void* data();
|
void* data();
|
||||||
const void* data() const;
|
const void* data() const;
|
||||||
float stretchFactor() const;
|
|
||||||
double MAD() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RAWIMAGE_H
|
#endif // RAWIMAGE_H
|
||||||
|
|||||||
+10
-5
@@ -28,18 +28,23 @@ StretchPanel::StretchPanel(QWidget *parent) : QWidget(parent)
|
|||||||
resetButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
resetButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||||
layout->addWidget(resetButton);
|
layout->addWidget(resetButton);
|
||||||
connect(resetButton, SIGNAL(pressed()), this, SLOT(resetMTF()));
|
connect(resetButton, SIGNAL(pressed()), this, SLOT(resetMTF()));
|
||||||
|
|
||||||
|
QPushButton *autoStretchButton = new QPushButton(tr("Autostretch"), this);
|
||||||
|
autoStretchButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||||
|
layout->addWidget(autoStretchButton);
|
||||||
|
connect(autoStretchButton, SIGNAL(pressed()), this, SIGNAL(autoStretch()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StretchPanel::imageLoaded(Image *img)
|
void StretchPanel::stretchImage(Image *img)
|
||||||
{
|
{
|
||||||
if(img)
|
if(img)
|
||||||
{
|
{
|
||||||
if(img->rawImage())
|
if(img->rawImage())
|
||||||
{
|
{
|
||||||
double mean, stdDev, median;
|
double median, mad;
|
||||||
img->rawImage()->imageStats(&mean, &stdDev, &median, nullptr, nullptr);
|
img->rawImage()->imageStats(nullptr, nullptr, &median, nullptr, nullptr, &mad);
|
||||||
median /= 65536;
|
median /= img->rawImage()->norm();
|
||||||
double mad = img->rawImage()->MAD() / 65536;
|
mad /= img->rawImage()->norm();
|
||||||
float bp = median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA;
|
float bp = median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA;
|
||||||
float mid = MTF(median - bp, TARGET_BACKGROUND);
|
float mid = MTF(median - bp, TARGET_BACKGROUND);
|
||||||
m_stfSlider->setMTFParams(bp, mid, 1.0f);
|
m_stfSlider->setMTFParams(bp, mid, 1.0f);
|
||||||
|
|||||||
+2
-1
@@ -13,10 +13,11 @@ class StretchPanel : public QWidget
|
|||||||
public:
|
public:
|
||||||
explicit StretchPanel(QWidget *parent = nullptr);
|
explicit StretchPanel(QWidget *parent = nullptr);
|
||||||
public slots:
|
public slots:
|
||||||
void imageLoaded(Image *img);
|
void stretchImage(Image *img);
|
||||||
void resetMTF();
|
void resetMTF();
|
||||||
signals:
|
signals:
|
||||||
void paramChanged(float low, float mid, float high);
|
void paramChanged(float low, float mid, float high);
|
||||||
|
void autoStretch();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STRETCHPANEL_H
|
#endif // STRETCHPANEL_H
|
||||||
|
|||||||
Reference in New Issue
Block a user