diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 4161fd6b..17d54447 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -48,6 +48,7 @@ SOURCES += main.cpp \ profileplot.cpp \ profileplotpicker.cpp \ settingsigramimportconfig.cpp \ + startestmoviedlg.cpp \ surface3dcontrolsdlg.cpp \ surfacegraph.cpp \ surfacelightingproxy.cpp \ @@ -163,6 +164,7 @@ HEADERS += mainwindow.h \ profileplot.h \ profileplotpicker.h \ settingsigramimportconfig.h \ + startestmoviedlg.h \ surface3dcontrolsdlg.h \ surfacegraph.h \ surfacelightingproxy.h \ @@ -276,6 +278,7 @@ FORMS += mainwindow.ui \ profileplot.ui \ contourtools.ui \ settingsigramimportconfig.ui \ + startestmoviedlg.ui \ surface3dcontrolsdlg.ui \ surfaceanalysistools.ui \ metricsdisplay.ui \ diff --git a/IgramArea.h b/IgramArea.h index 663d7ee6..2af7f3c3 100644 --- a/IgramArea.h +++ b/IgramArea.h @@ -150,13 +150,14 @@ class IgramArea : public QWidget void writeOutlines(QString fileName); QString makeOutlineName(); void shiftoutline(QPointF p); - void setZoomMode(zoomMode mode); + void showAliasDialog(); cv::Mat igramToGray(const cv::Mat &roi); cv::Mat qImageToMat(QImage &roi); private slots: void aperatureChanged(); public slots: + void setZoomMode(zoomMode mode); void gammaChanged(bool, double); void generateSimIgram(); void clearImage(); @@ -270,7 +271,6 @@ public slots: dftThumb *m_dftThumb; QTimer *m_outlineTimer; bool hasBeenCropped; - bool m_edgeMode; int m_zoomBoxWidth; int m_usingChannel; zoomMode m_zoomMode; diff --git a/annulushelpdlg.ui b/annulushelpdlg.ui index 65fff722..5dad6662 100644 --- a/annulushelpdlg.ui +++ b/annulushelpdlg.ui @@ -6,14 +6,27 @@ 0 0 - 400 - 300 + 508 + 330 Annulus Help - + + + QLayout::SetNoConstraint + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + @@ -33,16 +46,6 @@ p, li { white-space: pre-wrap; } - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - diff --git a/autoinvertdlg.cpp b/autoinvertdlg.cpp index 50f6c4f7..817d4130 100644 --- a/autoinvertdlg.cpp +++ b/autoinvertdlg.cpp @@ -7,6 +7,7 @@ autoInvertDlg::autoInvertDlg(QWidget *parent) : ui(new Ui::autoInvertDlg) { ui->setupUi(this); + setSizeGripEnabled(true); } autoInvertDlg::~autoInvertDlg() diff --git a/autoinvertdlg.ui b/autoinvertdlg.ui index 441e325d..75bfbd71 100644 --- a/autoinvertdlg.ui +++ b/autoinvertdlg.ui @@ -6,181 +6,148 @@ 0 0 - 678 + 1078 464 + + + 3 + 1 + + Invert Wavefront Mode + + true + true - - - - 20 - 150 - 111 - 24 - - - - Manual - - - - - - 20 - 80 - 111 - 24 - - - - Match Conic - - - - - - 20 - 200 - 111 - 24 - - - - Inside Focus - - - - - - 20 - 280 - 111 - 24 - - - - Outside Focus - - - - - - 140 - 150 - 521 - 41 - - - - I'll invert the wavefront myself as needed - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - 140 - 80 - 521 - 61 - - - - Most common. This mirror is at least partially figured. DFTFringe will invert the wavefront if S.A. sign doesn't match mirror configuration conic constant sign. This option disabled if CC=0. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - 140 - 200 - 521 - 71 - - - - This and future interferograms of this mirror are inside focus (interferometer closer to mirror). DFTFringe will use that fact to invert as needed. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - 140 - 280 - 521 - 61 - - - - This and future interferograms of this mirror are outside focus (interferometer farther from mirror). DFTFringe will use that fact to invert as needed. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - 20 - 0 - 641 - 61 - - - - - 14 - - - - Your wavefront may be inverted. What do you want to do? - - - true - - - - - - 20 - 350 - 631 - 91 - - - - Once you choose an option you won't be asked again until you restart the program. You can get back to this window from within the mirror configuration window. - - - true - - + + + + + + 14 + + + + Your wavefront may be inverted. What do you want to do? + + + true + + + + + + + + + Match Conic + + + + + + + Most common. This mirror is at least partially figured. DFTFringe will invert the wavefront if S.A. sign doesn't match mirror configuration conic constant sign. This option disabled if CC=0. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + Manual + + + + + + + I'll invert the wavefront myself as needed + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + Inside Focus + + + + + + + This and future interferograms of this mirror are inside focus (interferometer closer to mirror). DFTFringe will use that fact to invert as needed. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + Outside Focus + + + + + + + This and future interferograms of this mirror are outside focus (interferometer farther from mirror). DFTFringe will use that fact to invert as needed. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Once you choose an option you won't be asked again until you restart the program. You can get back to this window from within the mirror configuration window. + + + true + + + + diff --git a/foucaultview.cpp b/foucaultview.cpp index ff3c3df4..e31d2bd7 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -546,7 +546,7 @@ void foucaultView::on_scanPb_clicked() if (ui->SaveImageCB->isChecked()){ QString num = QString("%1").arg(v, 6, 'f', 4).replace(".","_"); num.replace("-","n"); - QString fvpng = QString("%1//%2_%3.png").arg(imageDir).arg(cnt++, 6, 10, QLatin1Char('0')).arg(num); + QString fvpng = QString("%1//%2.png").arg(imageDir).arg(cnt++, 6, 10, QLatin1Char('0')); qDebug() << "fn"<< fvpng; if (ui->saveOnlyFouccault->isChecked()){ fv->m_foucultQimage.save(fvpng); diff --git a/igramarea.cpp b/igramarea.cpp index 983fd965..43df0b2a 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -87,7 +87,7 @@ QImage cvMatToImage(const cv::Mat &out){ IgramArea::IgramArea(QWidget *parent, void *mw) : QWidget(parent),m_mw(mw),m_hideOutlines(false),scale(1.),outterPcount(0), innerPcount(0), zoomIndex(1),dragMode(false),cropTotalDx(0), cropTotalDy(0), hasBeenCropped(false), - m_edgeMode(false), m_zoomMode(NORMALZOOM),m_current_boundry(OutSideOutline) + m_zoomMode(NORMALZOOM),m_current_boundry(OutSideOutline) { leftMargin = 0; searchOutlineScale = 1.; @@ -136,9 +136,11 @@ IgramArea::IgramArea(QWidget *parent, void *mw) shortcut = new QShortcut(QKeySequence::ZoomIn, this); QObject::connect(shortcut, &QShortcut::activated, this, &IgramArea::zoomIn); shortcut = new QShortcut(QKeySequence::ZoomOut, this); - QObject::connect(shortcut, &QShortcut::activated, this, &IgramArea::zoomOut); - shortcut = new QShortcut(QKeySequence("1"), this); - QObject::connect(shortcut, &QShortcut::activated, this, &IgramArea::edgeMode); + + QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(zoomOut())); + shortcut = new QShortcut(QKeySequence("e"), this); + QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(edgeMode())); + connect(colorChannel::get_instance(),&colorChannel::useChannelsChanged, this, &IgramArea::colorChannelChanged); @@ -179,8 +181,9 @@ void IgramArea::generateSimIgram() } void IgramArea::edgeMode(){ - m_edgeMode = !m_edgeMode; - update(); + + setZoomMode(EDGEZOOM); + } void IgramArea::DrawSimIgram(void){ diff --git a/main.cpp b/main.cpp index 84cc0cc3..0f1bfe62 100644 --- a/main.cpp +++ b/main.cpp @@ -123,6 +123,7 @@ static int myCvErrorCallback( int /*status*/, const char* /*func_name*/, int main(int argc, char *argv[]) { + // QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // Allow secondary instances SingleApplication app( argc, argv, true ); diff --git a/mainwindow.cpp b/mainwindow.cpp index 8af6b7bc..61750734 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -49,9 +49,14 @@ #include "colorchannel.h" #include "opencv2/opencv.hpp" #include + +#include +#include + #include "zapm_interface.h" #include "zernikeprocess.h" + using namespace QtConcurrent; std::vector g_wavefronts; int g_currentsurface = 0; @@ -206,13 +211,22 @@ MainWindow::MainWindow(QWidget *parent) : QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_I), this); QObject::connect(shortcut, &QShortcut::activated, this, &MainWindow::importIgram); + shortcut = new QShortcut(QKeySequence(Qt::Key_U), this); + QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(load_from_url())); + QShortcut *shortcutl = new QShortcut(QKeySequence(Qt::Key_L), this); QObject::connect(shortcutl, &QShortcut::activated, this, &MainWindow::on_actionLoad_Interferogram_triggered); QShortcut *shortcut1 = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_O), this); QObject::connect(shortcut1, &QShortcut::activated, this, &MainWindow::on_actionLoad_Interferogram_triggered); + + QShortcut *shortcut2 = new QShortcut(QKeySequence(Qt::Key_S), this); + QObject::connect(shortcut2, SIGNAL(activated()), this, SLOT(on_actionSave_Wavefront_triggered())); + + connect(m_dftTools,&DFTTools::doDFT,m_dftArea,&DFTArea::doDFT); + settingsDlg = Settings2::getInstance(); connect(settingsDlg->m_igram, &settingsIGram::igramLinesChanged, m_igramArea, &IgramArea::igramOutlineParmsChanged); connect(settingsDlg->m_general, &SettingsGeneral2::updateContourPlot, m_contourView, &contourView::updateRuler); @@ -2124,3 +2138,50 @@ void MainWindow::on_actionStop_auto_invert_triggered() //QMessageBox::information(this, "auto invert", "DFTFringe will now ask if it thinks it needs to invert a wave front."); } +void MainWindow::load_from_url(){ + + // Construct the URL with IP address and port + QUrl url; + url.setScheme("http"); // or "https" if using SSL + url.setHost("192.168.50.5"); // Replace with your IP address + url.setPort(5000); // Specify the port + url.setPath("/downloadImage"); + showMessage("Connecting to " + url.toString(),1); + //downloader.startDownload(url); + + QEventLoop loop; + QNetworkAccessManager nam; + QNetworkRequest req(url); + QNetworkReply *reply = nam.get(req); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + //connect(reply, &QNetworkReply::downloadProgress, this, [&](qint64 bytesReceived, qint64 bytesTotal){ + // showMessage(QString("byes received %1").arg( bytesReceived) + QString(" total %1").arg(bytesTotal),1); + //}); + loop.exec(); + QByteArray buffer = reply->readAll(); + QImage b(buffer); + QSettings set; + QString dirPath = set.value("importIgramPath",".").toString(); + // Get the current date and time + QDateTime currentDateTime = QDateTime::currentDateTime(); + + // Format the date and time into a string suitable for a filename + // Using "yyyyMMdd_HHmmss" for a clear, sortable format without illegal characters + QString dateTimeString = currentDateTime.toString("yyyyMMdd_HHmmss"); + + // Construct the full filename + QString fileName = dirPath + "/" + dateTimeString +".jpg"; + qDebug() << "download filename" << fileName; + // Create a QImage from the QByteArray + QImage image; + if (image.loadFromData(buffer, "jpg")) { // Specify format if known, otherwise omit + showMessage("Image loaded successfully " + fileName,1); + // Now you can use the 'image' QImage object + // Example: Save it to another file + image.save(fileName, "JPG"); + importIgram(); + } else { + showMessage("Failed to load image!",2); + } + +} diff --git a/mainwindow.h b/mainwindow.h index 59533e4d..f5521f84 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -274,6 +274,8 @@ private slots: void on_actionStop_auto_invert_triggered(); + void load_from_url(); + private: Ui::MainWindow *ui; diff --git a/pixelstats.cpp b/pixelstats.cpp index 0d770f6b..a7e38f0d 100644 --- a/pixelstats.cpp +++ b/pixelstats.cpp @@ -494,10 +494,10 @@ void pixelStats::updateHisto(){ ui->histo->detachItems( QwtPlotItem::Rtti_PlotCurve); ui->histo->detachItems( QwtPlotItem::Rtti_PlotMarker); ui->histo->detachItems(QwtPlotItem::Rtti_PlotItem); + int hbins = 1000; // make histogram with 1000 bins int histSize[] = {hbins}; - cv::Mat hist; cv::Mat values; diff --git a/profileplot.cpp b/profileplot.cpp index 1351fc4b..47d1d4ae 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -75,6 +75,9 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): zoomed = false; m_defocus_mode = false; m_plot = new QwtPlot(this); + m_plot->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_plot, &QwtPlot::customContextMenuRequested, this, &ProfilePlot::showContextMenu); + new profilePlotPicker(m_plot); type = ProfileType::SHOW_ONE; QHBoxLayout * l1 = new QHBoxLayout(); @@ -85,17 +88,21 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): OneOnly = new QRadioButton("one diameter of current wavefront",this); OneOnly->setChecked(true); ShowAll = new QRadioButton("All wavefronts",this); + connect(Show16, &QAbstractButton::clicked, this, &ProfilePlot::show16); connect(OneOnly, &QAbstractButton::clicked, this, &ProfilePlot::showOne); connect(ShowAll, &QAbstractButton::clicked, this, &ProfilePlot::showAll); l1->addStretch(); + showSlopeError = new QCheckBox("Show Slope: "); - showPercentCorrection = new QPushButton("Show Correction"); - showPercentCorrection->setToolTip("Show % correction of zone areas used in the Zambuto method of mirror figuring."); + + slopeLimitSB = new QDoubleSpinBox(); QSettings set; + m_displayPercent = set.value("xScalepercent", false).toBool(); + m_displayInches = set.value("xScaleInches", false).toBool(); slopeLimitArcSec = set.value("slopeLimitArcSec", 1.).toDouble(); slopeLimitSB->setValue(slopeLimitArcSec); slopeLimitSB->setPrefix(" > "); @@ -112,6 +119,10 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): if (!m_showSlopeError) slopeLimitSB->hide(); showSlopeError->setChecked(m_showSlopeError); + + connect(slopeLimitSB, SIGNAL(valueChanged(double)), this, SLOT(slopeLimit(double))); + connect(showSlopeError,SIGNAL(clicked(bool)), this, SLOT(showSlope(bool))); + #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) connect(slopeLimitSB, &QDoubleSpinBox::valueChanged, this, &ProfilePlot::slopeLimit); #else @@ -120,8 +131,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): #endif // connect(showSlopeError,&QAbstractButton::clicked, this, &ProfilePlot::showSlope); - connect(showPercentCorrection,&QAbstractButton::clicked, this, &ProfilePlot::showCorrection); - l1->addWidget(showPercentCorrection); + l1->addWidget(showSlopeError); l1->addWidget(slopeLimitSB); l1->addWidget(showNmCB); @@ -219,6 +229,10 @@ ProfilePlot::~ProfilePlot(){ delete m_pcdlg; } + + + + void ProfilePlot::showSlope(bool val){ m_showSlopeError = val; if (!val) @@ -414,17 +428,23 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf, bool allowOffs if (!allowOffset) offset = 0.; double radius = md.m_clearAperature/2.; double obs_radius = md.obs/2.; - +qDebug() << "create Profile"; for (double rad = -1.; rad < 1.; rad += steps){ int dx, dy; double radn = rad * wf->m_outside.m_radius; double radx = rad * radius; + if (m_displayInches){ + radx /= 25.4; + } double e = 1.; - + if (m_displayPercent){ + radx = 100. * radx/radius; + } if (md.isEllipse()){ e = md.m_verticalAxis/md.diameter; } + dx = radn * cos(g_angle + M_PI_2) + wf->m_outside.m_center.x(); dy = -radn * e * sin(g_angle + M_PI_2) + wf->m_outside.m_center.y(); if (dy >= wf->data.rows || dx >= wf->data.cols || dy < 0 || dx < 0){ @@ -441,7 +461,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf, bool allowOffs if (m_defocus_mode){ defocus = (m_defocusValue)* (-1. + 2. * rad * rad); - points << QPointF(radx,(units * (m_defocus_wavefront((int)dy,(int)dx) + defocus ) * + points << QPointF(radx,(units * (wf->workData((int)dy,(int)dx) + defocus ) * wf->lambda/outputLambda) +offset * units); } else { @@ -532,7 +552,13 @@ void ProfilePlot::populate() if (m_showNm == 1.) tmp = QString("waves of %1 nm").arg(outputLambda, 6, 'f', 1); m_plot->setAxisTitle( m_plot->yLeft, "Error in " + tmp ); - m_plot->setAxisTitle( m_plot->xBottom, "Radius mm" ); + QString XaxisTitle("Radius mm"); + if (m_displayInches) + XaxisTitle = "Radius Inches"; + if (m_displayPercent) + XaxisTitle = "Radius Percent"; + + m_plot->setAxisTitle( m_plot->xBottom, XaxisTitle ); QwtPlotGrid *grid = new QwtPlotGrid(); grid->enableXMin(true); @@ -565,6 +591,14 @@ void ProfilePlot::populate() // axes double lower = -m_wf->diameter/2 - 10; double upper = m_wf->diameter/2 + 10; + if (m_displayInches){ + lower = lower /= 25.4; + upper = upper /= 25.4; + } + if (m_displayPercent){ + lower = -100; + upper = 100; + } m_plot->setAxisScale(QwtPlot::xBottom, lower, upper); QwtScaleEngine * se1 = m_plot->axisScaleEngine(QwtPlot::xBottom); QwtScaleDiv sd1 = se1->divideScale(lower,upper, 40,5); @@ -686,7 +720,7 @@ void ProfilePlot::populate() for (int i = 0; i < list.size(); ++i){ QStringList path = wfs->at(list[i])->name.split("/"); QString name = path.last().replace(".wft",""); - +qDebug() << "name " << name; QwtPlotCurve *cprofile = new QwtPlotCurve(name ); int width = Settings2::m_profile->lineWidth(); if (name == m_wf->name.split("/").last().replace(".wft","")) @@ -776,13 +810,47 @@ void ProfilePlot::showContextMenu(QPoint pos) // Create menu and insert some actions QMenu myMenu; + myMenu.setToolTipsVisible(true); QString txt = (zoomed)? "Restore to MainWindow" : "FullScreen"; - myMenu.addAction(txt, this, &ProfilePlot::zoom); + + myMenu.addAction(txt, this, SLOT(zoom())); + myMenu.addAction("Change X axis to show percentage", this, SLOT(showXPercent())); + myMenu.addAction("Change X asix to show inches",this, SLOT(showXInches())); + myMenu.addAction("Change X axis to show mm",this, SLOT(showXMM())); + QAction *correctionAction = myMenu.addAction("show percent of correction",this, SLOT(showCorrection())); + correctionAction->setToolTip("Show % correction of zone areas used in the Zambuto method of mirror figuring."); + // Show context menu at handling position myMenu.exec(globalPos); } +void ProfilePlot::saveXscaleSettings(){ + QSettings set; + set.setValue("xScalepercent", m_displayPercent); + set.setValue("xScaleInches", m_displayInches); +} +void ProfilePlot::showXPercent(){ + m_displayPercent = true; + m_displayInches = false; + populate(); + m_plot->replot(); + saveXscaleSettings(); +} +void ProfilePlot::showXInches(){ + m_displayInches = true; + m_displayPercent = false; + populate(); + m_plot->replot(); + saveXscaleSettings(); +} +void ProfilePlot::showXMM(){ + m_displayInches = false; + m_displayPercent = false; + populate(); + m_plot->replot(); + saveXscaleSettings(); +} void ProfilePlot::resizeEvent( QResizeEvent *) { //m_plot->resizeEvent( event ); diff --git a/profileplot.h b/profileplot.h index d9f28ba4..474181e1 100644 --- a/profileplot.h +++ b/profileplot.h @@ -62,6 +62,7 @@ class ProfilePlot : public QWidget bool zoomed; bool m_showSlopeError; + double slopeLimitArcSec; void setDefocusValue(double val); void setDefocusWaveFront( const cv::Mat_ &wf); @@ -88,6 +89,9 @@ public slots: void populate(); void showCorrection(); void make_correction_graph(); + void showXPercent(); + void showXInches(); + void showXMM(); //QPolygonF createZernProfile(wavefront *wf); private: enum class ProfileType { @@ -97,16 +101,23 @@ public slots: }; void updateGradient(); + void saveXscaleSettings(); bool dragging; QPoint startPos; QString offsetType; QwtCompass *compass; QCheckBox *showSlopeError; - QPushButton *showPercentCorrection; + QDoubleSpinBox *slopeLimitSB; double m_defocusValue; + + bool m_displayPercent = false; + bool m_displayInches = false; +private: + ProfileType type; + Ui::ProfilePlot *ui; bool m_defocus_mode; cv::Mat_ m_defocus_wavefront; diff --git a/simulationsview.cpp b/simulationsview.cpp index 6228ba40..a7b85be8 100644 --- a/simulationsview.cpp +++ b/simulationsview.cpp @@ -35,6 +35,7 @@ #include #include #include + double M2PI = M_PI * 2.; SimulationsView *SimulationsView::m_Instance = 0; class arcSecScaleDraw: public QwtScaleDraw @@ -92,9 +93,9 @@ SimulationsView::SimulationsView(QWidget *parent) : ui->FFTSizeSB->blockSignals(false); ui->centerMagnifySB->setValue(set.value("StarTestMagnify", 4).toDouble()); ui->gammaSB->setValue(set.value("StarTestGamma", 2.).toDouble()); - connect(&m_guiTimer, &QTimer::timeout, this, &SimulationsView::on_MakePB_clicked); - connect(this, &QWidget::customContextMenuRequested, this, - &SimulationsView::showContextMenu); + connect(&m_guiTimer, SIGNAL(timeout()), this, SLOT(on_MakePB_clicked())); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(showContextMenu(QPoint))); setContextMenuPolicy(Qt::CustomContextMenu); } @@ -115,12 +116,7 @@ void SimulationsView::initMTFPlot(){ m_arcSecScaleDraw = new arcSecScaleDraw(mirrorDlg::get_Instance()->diameter); ui->MTF->setAxisScaleDraw(ui->MTF->xBottom, m_arcSecScaleDraw); QwtPlotLegendItem *customLegend = new QwtPlotLegendItem(); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - // keep compatibility with newer version of QWT used in QT6 - customLegend->setAlignmentInCanvas(Qt::AlignLeft | Qt::AlignBottom); -#else customLegend->setAlignment(Qt::AlignLeft | Qt::AlignBottom); -#endif customLegend->attach(ui->MTF); QwtPlotTextLabel *t = new QwtPlotTextLabel(); QwtText title( "MTF" ); @@ -145,17 +141,12 @@ void SimulationsView::setSurface(wavefront *wf){ if (!isHidden()) on_MakePB_clicked(); } - -void SimulationsView::saveImage(){ +void SimulationsView::saveImage(QString fileName){ QSettings settings; QString path = settings.value("lastPath","").toString(); - QString fileName = QFileDialog::getSaveFileName(0, + if (fileName == "") + fileName = QFileDialog::getSaveFileName(0, "File name for image to be saved", path); - - saveImageNamed(fileName); -} - -void SimulationsView::saveImageNamed(QString fileName){ if (!fileName.endsWith(".jpg")) fileName = fileName + ".jpg"; QImage svImage = QImage(size(),QImage::Format_ARGB32 ); @@ -164,12 +155,14 @@ void SimulationsView::saveImageNamed(QString fileName){ svImage.save(fileName); } -void SimulationsView::showContextMenu(QPoint pos){ - // Handle global position +void SimulationsView::showContextMenu(const QPoint &pos) +{ + +// Handle global position QPoint globalPos = mapToGlobal(pos); // Create menu and insert some actions QMenu myMenu; - myMenu.addAction("Save as image", this, &SimulationsView::saveImage); // connects to QAction::triggered(bool checked = false) + myMenu.addAction("Save as image", this, SLOT(saveImage())); // Show context menu at handling position myMenu.exec(globalPos); @@ -206,116 +199,20 @@ cv::Mat SimulationsView::nulledSurface(double defocus){ cv::Mat nulled_surface = zp.null_unwrapped( *(m_Instance->m_wf), newZerns, zernEnables); zernEnables[3] = saved_defocus_enable; if (GB_enabled){ - double gbValue = settings.value("GBValue", 21).toInt(); - int blurRad = .01 * gbValue * md->diameter; + double gbValue = settings.value("GBValue", 21).toInt(); + int blurRad = 2 *(m_Instance->m_wf)->m_outside.m_radius * gbValue * .01; + blurRad &= 0xfffffffe; ++blurRad; + + + qDebug() << "Blurr" << blurRad; cv::GaussianBlur( nulled_surface, nulled_surface , cv::Size( blurRad, blurRad ),0,0); } nulled_surface *= M2PI * md->lambda/outputLambda; return nulled_surface; } -#ifdef trialVersion -// create star test using pupil_size which is usually smaller than the wavefront being sampled. -cv::Mat SimulationsView::computeStarTest(cv::Mat surface, int pupil_size, double pad , bool returnComplex){ - alias = false; - cv::Mat out; - - - int nx = surface.size().width;//pupil_size; - int ny = surface.size().height; - - cv::Mat tmp[] = {cv::Mat::zeros(Size(nx,ny),CV_64FC1) - ,cv::Mat::zeros(Size(nx,ny),CV_64FC1)}; - - for (int y = 0; y < ny; ++y){ - for (int x = 0; x < nx; ++x){ - tmp[1].at(y,x) = cos(surface.at(y,x)); - tmp[0].at(y,x) = -sin(surface.at(y,x)); - - } - } - - // apply the mask - cv::Mat tmp2; - - tmp[0].copyTo(tmp2, m_wf->workMask); - tmp[0] = tmp2.clone(); - tmp[1].copyTo(tmp2, m_wf->workMask); - tmp[1] = tmp2.clone(); - //pupil_size += 1; - // now reduce the wavefront with pad to fit into the fft size; - // new padSize is fft_size/pad; - - - int padSize = pupil_size; - - dX = (m_wf->diameter/2.)/m_wf->m_outside.m_radius; - if (nx > padSize/3.){ - cv::resize(tmp[0],tmp[0],cv::Size(padSize/3.,padSize/3.),cv::INTER_AREA); - cv::resize(tmp[1],tmp[1],cv::Size(padSize/3.,padSize/3.),cv::INTER_AREA); - } - - - cv::Mat in[] = {cv::Mat::zeros(Size(pupil_size,pupil_size),CV_64FC1) - ,cv::Mat::zeros(Size(pupil_size,pupil_size),CV_64FC1)}; - - tmp[0].copyTo(in[0](cv::Rect(0,0,tmp[0].cols,tmp[0].cols))); - tmp[1].copyTo(in[1](cv::Rect(0,0,tmp[0].cols,tmp[0].cols))); - //showData("xxxxff", in[0].clone()); - cv::Mat complexIn; - - cv::merge(in,2,complexIn); - dft(complexIn,out); - shiftDFT(out); - - //cv::flip(out,out,0); // needs work. - Mat planes[2]; - split(out, planes); - magnitude(planes[0], planes[1], planes[0]); - - - // check for aliasing - // compute edge - double edge_avg = 0.; - double center_avg = 0.; - int half = out.size[0] /2; - int last = out.size[0] * .3; - - for (int i = 0; i < last; ++i) - { - edge_avg += planes[0].at(half,i); - center_avg += planes[0].at(half, i+half); - - } - - double ddd = center_avg/edge_avg; - - if (ddd < 2) - { - alias = true; -/* - AfxMessageBox(L"Warning, computed PSF was too large for the selected size of the simulation.\n" - L"Select larger simulation size from the Configuration Menu\n" - L"and try again.\n\n" - L"Note: PSF is also used to compute Foucault, Ronchi, and MTF\n" - L" Computeing MTF may cause this message 3 times\n" - L"Sometime this message is caused by the errors on the surface and so the simulatin may still be usable.\n" - L"The error usually shows up as a series of light and dark horizontal bands."); - //throw FFT_ERROR(); - */ - } - - if (returnComplex) - return out; - int start = (pupil_size/2)-pupil_size/8; - - - return (planes[0]); - -} -#endif // create star test using pupil_size which is usually smaller than the wavefront being sampled. cv::Mat SimulationsView:: computeStarTest(cv::Mat surface, int pupil_size, double pad , bool returnComplex){ alias = false; @@ -458,6 +355,7 @@ void etoxplusy(cv::Mat data) } } } + void SimulationsView::mtf(const cv::Mat &star, const QString &txt, QColor color){ cv::Mat planes[2]; cv::Mat mtfIn, mtfOut, mtfMag; @@ -492,35 +390,49 @@ void SimulationsView::mtf(const cv::Mat &star, const QString &txt, QColor color) curve1->setSamples(points1); curve1->attach(ui->MTF); } -void SimulationsView::on_film_clicked() -{ - QSettings settings; - QString filmDir = settings.value("lastPath","").toString(); +#include +#include +#include - filmDir = QFileDialog::getExistingDirectory(this, tr("Directory where images are to be saved"), - filmDir, - QFileDialog::ShowDirsOnly - | QFileDialog::DontResolveSymlinks); - if (filmDir.isEmpty()) - return; - int cnt = 0; - for (double wave = .1; wave < 10. ; wave+= .2){ +void SimulationsView::makeFrame(double defocus, startestMovieDlg * dlg){ + + + double fftSize = ui->FFTSizeSB->value(); + double gamma = ui->gammaSB->value(); - ui->defocusSB->setValue(wave); QApplication::processEvents(); - on_MakePB_clicked(); + + cv::Mat inside = computeStarTest(nulledSurface(defocus), fftSize, 3); + QScreen *screen = QGuiApplication::primaryScreen(); + int size = screen->availableSize().height()/2; + cv::Mat t = fitStarTest(inside, size,gamma); + cv::putText(t,QString("%1 waves").arg(2 * defocus, 5, 'f', 2).toStdString(),cv::Point(50,60),1,3,cv::Scalar(255, 255,255),3); + + + QImage outdisplay((uchar*)t.data, t.cols, t.rows, t.step, QImage::Format_RGB888); + + QApplication::processEvents(); - QString name = QString("/frame%1").arg(cnt++, 3 ,10, QLatin1Char('0')); - saveImageNamed(filmDir+name); - } + dlg->setImage(outdisplay); + } +void SimulationsView::on_film_clicked() +{ + ui->film->setChecked(false); + m_movieDlg = new startestMovieDlg(this); + + m_movieDlg->exec(); + + delete m_movieDlg; +} + int offset = 0; int stalkWidth; #include #include using namespace cv; -cv::Mat make_obstructionMask(const cv::Mat &mask){ +cv::Mat make_obstructionMask(cv::Mat mask){ //return; cv::Mat out = mask.clone(); int s = mask.size[0]; @@ -630,6 +542,7 @@ cv::Mat zoomMat(cv::Mat &mat, double zoom){ void SimulationsView::on_MakePB_clicked() { m_guiTimer.stop(); + ui->MakePB->setChecked(false); /************************** special test code for PSF */ @@ -647,9 +560,11 @@ void SimulationsView::on_MakePB_clicked() QString strehl = doc.toPlainText(); doc.setHtml(metrics->mCC->text()); QString bestFit = doc.toPlainText(); + QFileInfo fileInfo(m_wf->name); + QString fileName = fileInfo.fileName(); QString caption = QString("%1 Diameter: %2 ROC: %3 Best Fit CC: %4 Strehl: %5").arg( - m_wf->name).arg( + fileName).arg( m_wf->diameter, 6, 'f', 1).arg( m_wf->roc, 6, 'f', 1).arg( bestFit).arg( // clazy:exclude=qstring-arg diff --git a/simulationsview.h b/simulationsview.h index c069b66a..e7a8bfae 100644 --- a/simulationsview.h +++ b/simulationsview.h @@ -24,6 +24,8 @@ #include #include +#include "startestmoviedlg.h" + class arcSecScaleDraw; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) @@ -59,6 +61,7 @@ class SimulationsView : public QWidget Q3DSurface *m_PSF_3Dgraph; double dX; // pupil sample size based on mirror size in wave front. double dF; // psf sample size; + startestMovieDlg *m_movieDlg; void saveImageNamed(QString fn); void mtf(const cv::Mat &magPsf, const QString &txt, QColor color); @@ -67,6 +70,7 @@ class SimulationsView : public QWidget void make3DPsf(const cv::Mat &surface); public slots: void on_MakePB_clicked(); + void makeFrame(double wave, startestMovieDlg * dlg); private slots: void on_defocusSB_valueChanged(double); @@ -77,9 +81,10 @@ private slots: void on_FFTSizeSB_valueChanged(int val); - void showContextMenu(QPoint pos); - void saveImage(); + void showContextMenu(const QPoint &pos); + + void saveImage(QString fname = ""); void on_film_clicked(); diff --git a/simulationsview.ui b/simulationsview.ui index 651b3553..4ab88318 100644 --- a/simulationsview.ui +++ b/simulationsview.ui @@ -6,7 +6,7 @@ 0 0 - 828 + 935 516 @@ -21,9 +21,18 @@ font: normal 12px; padding: 2px; } - + + + 2 + + + 2 + - + + + QLayout::SetNoConstraint + @@ -45,9 +54,12 @@ - + + + <html><head/><body><p>This will scan defocus through inside to outside defocus and make images to be used in a movie to simulate moving the defocuser and watching for astig and center obstruction breakout. </p></body></html> + - film + Make Defocus Scan film @@ -156,12 +168,24 @@ - + false + + + 4 + 0 + + + + + 0 + 0 + + - Generat star tests. + Generate star tests. Make diff --git a/startestmoviedlg.cpp b/startestmoviedlg.cpp new file mode 100644 index 00000000..f6409ff4 --- /dev/null +++ b/startestmoviedlg.cpp @@ -0,0 +1,142 @@ +#include "startestmoviedlg.h" +#include "ui_startestmoviedlg.h" +#include +#include +#include +#include "simulationsview.h" +startestMovieDlg::startestMovieDlg(SimulationsView *view) : + m_view(view), ui(new Ui::startestMovieDlg) +{ + ui->setupUi(this); + QSettings set; + ui->wavestart->setValue(set.value("star test start", -10).toDouble()); + ui->waveEnd->setValue(set.value("star test end", 10).toDouble()); + ui->brightnesssb->blockSignals(true); + ui->brightnesssb->setValue(set.value("star test bright", 1).toDouble()); + ui->brightnesssb->blockSignals(false); + ui->path->setText(set.value("star test Path", "").toString()); + ui->stepsize->setValue(set.value("star test step", .1).toDouble()); + QScreen *screen = QGuiApplication::primaryScreen(); + int size = screen->availableSize().height()/2; + ui->theImage->resize(size,size); + view->makeFrame(-5., this); +} + +startestMovieDlg::~startestMovieDlg() +{ + delete ui; +} + +void startestMovieDlg::on_start_clicked() +{ + m_recording = true; + m_frameNumber = 0; + qDebug() << "started"; + for (double wave = ui->wavestart->value(); m_recording && (ui->stepsize->value() >0)? wave <= ui->waveEnd->value() : wave >= ui->waveEnd->value(); wave += ui->stepsize->value()){ + qDebug() << "wave number" << wave; + m_view->makeFrame(wave/2., this); + } + m_recording = false; +} + + +QImage brighten(QImage image ,int brightness_factor){ + QImage imaget = image.copy(); + + for (int y = 0; y < imaget.height(); ++y) { + for (int x = 0; x < imaget.width(); ++x) { + QRgb pixel = imaget.pixel(x, y); + int red = qRed(pixel); + int green = qGreen(pixel); + int blue = qBlue(pixel); + red = qMin(255, red + brightness_factor); + green = qMin(255, green + brightness_factor); + blue = qMin(255, blue + brightness_factor); + red = qBound(0, red, 255); + green = qBound(0, green, 255); + blue = qBound(0, blue, 255); + imaget.setPixel(x, y, qRgb(red, green, blue)); + } + } + return imaget; +} + +void startestMovieDlg::setImage(QImage image){ + m_image = image.copy(); + + + QImage imaget = brighten(m_image, m_bright); + + QPixmap myPixmap = QPixmap::fromImage(imaget); + + + ui->theImage->setPixmap(myPixmap.scaled(ui->theImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + ui->theImage->setScaledContents(true); // Ensures the label itself scales the content + if (m_recording){ + QString name = QString("/frame%1").arg(m_frameNumber++, 3 ,10, QLatin1Char('0')); + + imaget.save(ui->path->text()+name + ".jpg"); + } + +} +void startestMovieDlg::on_browse_clicked() +{ + QSettings settings; + QString filmDir = settings.value("lastPath","").toString(); + + filmDir = QFileDialog::getExistingDirectory(this, tr("Directory where images are to be saved"), + filmDir, + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + + if (filmDir.isEmpty()) + return; + ui->path->setText(filmDir); + settings.setValue("star test Path", filmDir); +} + + +void startestMovieDlg::on_abort_clicked() +{ + m_recording = false; +} + + +void startestMovieDlg::on_brightnesssb_valueChanged(int value) +{ + + m_bright = value; + if (m_image.isNull()) return; + QImage imaget = brighten(m_image, value); + + + QPixmap myPixmap = QPixmap::fromImage(imaget); + + + ui->theImage->setPixmap(myPixmap.scaled(ui->theImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + ui->theImage->setScaledContents(true); // Ensures the label itself scales the content +} + +void startestMovieDlg::on_wavestart_valueChanged(double arg1) +{ + QSettings set; + set.setValue("star test start", arg1); +} + + +void startestMovieDlg::on_waveEnd_valueChanged(double arg1) +{ + QSettings set; + set.setValue("star test end", arg1); +} + + +void startestMovieDlg::on_stepsize_valueChanged(double arg1) +{ + QSettings set; + set.setValue("star test step", arg1); +} + + + + diff --git a/startestmoviedlg.h b/startestmoviedlg.h new file mode 100644 index 00000000..ffe0b188 --- /dev/null +++ b/startestmoviedlg.h @@ -0,0 +1,47 @@ +#ifndef STARTESTMOVIEDLG_H +#define STARTESTMOVIEDLG_H + +#include +#include +class SimulationsView; +namespace Ui { +class startestMovieDlg; +} + +class startestMovieDlg : public QDialog +{ + Q_OBJECT + +public: + explicit startestMovieDlg(SimulationsView *view); + ~startestMovieDlg(); + void setImage(QImage image); + bool m_recording = false; + int m_frameNumber = 0; + int m_bright = 1; + SimulationsView *m_view; + QImage m_image; + +private slots: + void on_start_clicked(); + + void on_browse_clicked(); + + void on_abort_clicked(); + + void on_brightnesssb_valueChanged(int value); + + void on_wavestart_valueChanged(double arg1); + + void on_waveEnd_valueChanged(double arg1); + + void on_stepsize_valueChanged(double arg1); + +private: + Ui::startestMovieDlg *ui; + +signals: + void makeStarTest(double wave, startestMovieDlg * dlg); +}; + +#endif // STARTESTMOVIEDLG_H diff --git a/startestmoviedlg.ui b/startestmoviedlg.ui new file mode 100644 index 00000000..3d58149f --- /dev/null +++ b/startestmoviedlg.ui @@ -0,0 +1,234 @@ + + + startestMovieDlg + + + + 0 + 0 + 640 + 480 + + + + Dialog + + + + + + + + Wave start + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + -100.000000000000000 + + + 100.000000000000000 + + + 0.100000000000000 + + + + + + + Wave End + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + -100.000000000000000 + + + 0.100000000000000 + + + + + + + Step size + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + -99.000000000000000 + + + + + + + + + + + Output Directory + + + + + + + + + + ... + + + + + + + + + + + TextLabel + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + 255 + + + 0 + + + Qt::Vertical + + + QSlider::TicksBothSides + + + + + + + Brightness + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Start + + + + + + + Abort + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + startestMovieDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + startestMovieDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 0bd7dd3c..4686f7a2 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -359,6 +359,7 @@ void SurfaceManager::generateSurfacefromWavefront(wavefront * wf){ gaussianRad &= 0xfffffffe; ++gaussianRad; + qDebug() << "Blurr" << gaussianRad; cv::GaussianBlur( wf->nulledData.clone(), wf->workData, cv::Size( gaussianRad, gaussianRad ),0,0,cv::BORDER_REFLECT); } @@ -435,6 +436,7 @@ void SurfaceManager::generateSurfacefromWavefront(wavefront * wf){ gaussianRad &= 0xfffffffe; ++gaussianRad; + cv::GaussianBlur( wf->nulledData.clone(), wf->workData, cv::Size( gaussianRad, gaussianRad ),0,0,cv::BORDER_REFLECT); } @@ -1075,7 +1077,7 @@ void SurfaceManager::createSurfaceFromPhaseMap(cv::Mat phase, CircleOutline outs } if (m_wavefronts.size() >0 && (m_currentNdx == 0 && m_wavefronts[0]->name == "Demo")){ - qDebug() << "using demo"; + wf = m_wavefronts[0]; emit nameChanged(wf->name, name); wf->name = name; diff --git a/zernikesmoothingdlg.cpp b/zernikesmoothingdlg.cpp index d1def28b..e8759bf5 100644 --- a/zernikesmoothingdlg.cpp +++ b/zernikesmoothingdlg.cpp @@ -28,11 +28,6 @@ ZernikeSmoothingDlg::ZernikeSmoothingDlg(wavefront &wf, QWidget *parent) : tableModel->setValues(&m_wf.InputZerns); m_sm = SurfaceManager::get_instance(); - - m_originalSize = wf.data.cols; - m_xCen = wf.m_outside.m_center.x(); - m_yCen = wf.m_outside.m_center.y(); - m_rad = wf.m_outside.m_radius; } ZernikeSmoothingDlg::~ZernikeSmoothingDlg()