From 4287e322098d235b0856db00426f4887e165693e Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Sat, 1 Nov 2025 18:07:15 -0500 Subject: [PATCH 1/2] Igramarea.cpp Added e hot key command to enable outline edge zoom. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MainWindow.cpp Added igram downloader using the “u” hot key will downoad image from skysolve camera at it’s URL of 192.168.50.5:5000. (specialized and not configurable). Could be set into preferences but still only appropriate for getting images from Skysolve. Added ‘i’ hot key igram import igram from latest file in dir x where x is set in preferences. Added “s” hot key to save current wave front. main.cpp Added DPI scaling command but it did not seem to help. Profileplot.cpp Enabled context menu and added change x axis to percent, inches, or mm(default) Moved percent correction command into this menu. Simulationview.cpp Corrected Gaussian Blur calculation. Changed top pushbuttons for make scan film and make to checkboxes. Because then their text is not tiny like it was for when they were buttons on high DPI screens. Reduced file name path to last dir on the top line. Added startest movie function. --- DFTFringe_Dale.pro | 3 + IgramArea.h | 4 +- foucaultview.cpp | 2 +- igramarea.cpp | 9 +- main.cpp | 1 + mainwindow.cpp | 63 ++++++++++-- mainwindow.h | 2 + pixelstats.cpp | 9 +- profileplot.cpp | 81 +++++++++++++-- profileplot.h | 10 +- simulationsview.cpp | 162 ++++++++---------------------- simulationsview.h | 3 + simulationsview.ui | 38 +++++-- startestmoviedlg.cpp | 142 ++++++++++++++++++++++++++ startestmoviedlg.h | 47 +++++++++ startestmoviedlg.ui | 234 +++++++++++++++++++++++++++++++++++++++++++ surfacemanager.cpp | 4 +- 17 files changed, 655 insertions(+), 159 deletions(-) create mode 100644 startestmoviedlg.cpp create mode 100644 startestmoviedlg.h create mode 100644 startestmoviedlg.ui diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index c4307ac2..121723f6 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -49,6 +49,7 @@ SOURCES += main.cpp \ profileplotpicker.cpp \ psiresizeimagesdlg.cpp \ settingsigramimportconfig.cpp \ + startestmoviedlg.cpp \ surface3dcontrolsdlg.cpp \ surfacegraph.cpp \ surfacelightingproxy.cpp \ @@ -172,6 +173,7 @@ HEADERS += mainwindow.h \ profileplotpicker.h \ psiresizeimagesdlg.h \ settingsigramimportconfig.h \ + startestmoviedlg.h \ surface3dcontrolsdlg.h \ surfacegraph.h \ surfacelightingproxy.h \ @@ -295,6 +297,7 @@ FORMS += mainwindow.ui \ contourtools.ui \ psiresizeimagesdlg.ui \ settingsigramimportconfig.ui \ + startestmoviedlg.ui \ surface3dcontrolsdlg.ui \ surfaceanalysistools.ui \ metricsdisplay.ui \ diff --git a/IgramArea.h b/IgramArea.h index ac2807cb..a252956e 100644 --- a/IgramArea.h +++ b/IgramArea.h @@ -153,13 +153,14 @@ class IgramArea : public QWidget void writeOutlines(QString fileName); QString makeOutlineName(); void shiftoutline(QPointF p); - void setZoomMode(zoomMode mode); + void showAliasDialog(); cv::Mat igramToGray(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(); @@ -273,7 +274,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/foucaultview.cpp b/foucaultview.cpp index 0b917774..03469da1 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 aa546a93..b8a2e9c4 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -87,7 +87,7 @@ QImage cvMatToImage(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.; @@ -137,7 +137,7 @@ IgramArea::IgramArea(QWidget *parent, void *mw) QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(zoomIn())); shortcut = new QShortcut(QKeySequence::ZoomOut, this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(zoomOut())); - shortcut = new QShortcut(QKeySequence("1"), this); + shortcut = new QShortcut(QKeySequence("e"), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(edgeMode())); connect(colorChannel::get_instance(),SIGNAL(useChannelsChanged()), this, SLOT(colorChannelChanged())); @@ -179,8 +179,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 64364207..a56f8ec3 100644 --- a/main.cpp +++ b/main.cpp @@ -68,6 +68,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 4794b430..e6862105 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -49,7 +49,8 @@ #include "opencv2/opencv.hpp" #include "spdlog/spdlog.h" #include - +#include +#include using namespace QtConcurrent; std::vector g_wavefronts; int g_currentsurface = 0; @@ -206,12 +207,18 @@ MainWindow::MainWindow(QWidget *parent) : QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_I), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(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, SIGNAL(activated()), this, SLOT(on_actionLoad_Interferogram_triggered())); QShortcut *shortcut1 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_O), this); QObject::connect(shortcut1, SIGNAL(activated()), this, SLOT(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,SIGNAL(doDFT()),m_dftArea,SLOT(doDFT())); settingsDlg = Settings2::getInstance(); connect(settingsDlg->m_igram, SIGNAL(igramLinesChanged(outlineParms)), m_igramArea, SLOT(igramOutlineParmsChanged(outlineParms))); @@ -2096,12 +2103,6 @@ void MainWindow::on_actionastig_in_polar_triggered() void MainWindow::on_actiondebugSomething_triggered() { - - - - - - } @@ -2111,3 +2112,51 @@ 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 c549964e..3a791476 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -277,6 +277,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 56162f95..23952ce4 100644 --- a/pixelstats.cpp +++ b/pixelstats.cpp @@ -493,11 +493,10 @@ void pixelStats::updateHisto(){ ui->histo->detachItems( QwtPlotItem::Rtti_PlotCurve); ui->histo->detachItems( QwtPlotItem::Rtti_PlotMarker); ui->histo->detachItems(QwtPlotItem::Rtti_PlotItem); - // Quantize the hue to 30 levels - // and the saturation to 32 levels - int hbins = 1000, sbins = 32; - int histSize[] = {hbins, sbins}; - // hue varies from 0 to 179, see cvtColor + + int hbins = 1000; + int histSize[] = {hbins}; + cv::Mat hist; diff --git a/profileplot.cpp b/profileplot.cpp index d7a8f2ea..4982a2e3 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 = 0; QHBoxLayout * l1 = new QHBoxLayout(); @@ -88,14 +91,16 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): connect(Show16, SIGNAL(clicked()), this, SLOT(show16())); connect(OneOnly, SIGNAL(clicked()), this, SLOT(showOne())); connect(ShowAll, SIGNAL(clicked()), this, SLOT(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(" > "); @@ -114,8 +119,8 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): showSlopeError->setChecked(m_showSlopeError); connect(slopeLimitSB, SIGNAL(valueChanged(double)), this, SLOT(slopeLimit(double))); connect(showSlopeError,SIGNAL(clicked(bool)), this, SLOT(showSlope(bool))); - connect(showPercentCorrection,SIGNAL(clicked()), this, SLOT(showCorrection())); - l1->addWidget(showPercentCorrection); + + l1->addWidget(showSlopeError); l1->addWidget(slopeLimitSB); l1->addWidget(showNmCB); @@ -207,6 +212,10 @@ ProfilePlot::~ProfilePlot(){ delete m_pcdlg; } + + + + void ProfilePlot::showSlope(bool val){ m_showSlopeError = val; if (!val) @@ -402,17 +411,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){ @@ -429,7 +444,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 { @@ -520,7 +535,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); @@ -553,6 +574,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); @@ -674,7 +703,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","")) @@ -764,13 +793,45 @@ void ProfilePlot::showContextMenu(const QPoint &pos) // Create menu and insert some actions QMenu myMenu; + myMenu.setToolTipsVisible(true); QString txt = (zoomed)? "Restore to MainWindow" : "FullScreen"; 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 f00aacbd..b08bd8c9 100644 --- a/profileplot.h +++ b/profileplot.h @@ -63,6 +63,7 @@ class ProfilePlot : public QWidget bool zoomed; bool m_showSlopeError; + double slopeLimitArcSec; void setDefocusValue(double val); void setDefocusWaveFront( cv::Mat_ wf); @@ -89,19 +90,24 @@ public slots: void populate(); void showCorrection(); void make_correction_graph(); + void showXPercent(); + void showXInches(); + void showXMM(); //QPolygonF createZernProfile(wavefront *wf); private: 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: Ui::ProfilePlot *ui; bool m_defocus_mode; diff --git a/simulationsview.cpp b/simulationsview.cpp index 6aae6223..cacbf7df 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 @@ -198,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; @@ -484,29 +389,43 @@ void SimulationsView::mtf(cv::Mat star, 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')); - saveImage(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 @@ -622,6 +541,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 */ @@ -639,9 +559,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 cc52dde4..792e7430 100644 --- a/simulationsview.h +++ b/simulationsview.h @@ -23,6 +23,7 @@ #include #include #include +#include "startestmoviedlg.h" class arcSecScaleDraw; using namespace QtDataVisualization; namespace Ui { @@ -53,6 +54,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 mtf(cv::Mat magPsf, QString txt, QColor color); void initMTFPlot(); @@ -60,6 +62,7 @@ class SimulationsView : public QWidget void make3DPsf(cv::Mat surface); public slots: void on_MakePB_clicked(); + void makeFrame(double wave, startestMovieDlg * dlg); private slots: void on_defocusSB_valueChanged(double); 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 26587e7b..29b02e54 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -357,6 +357,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,BORDER_REFLECT); } @@ -418,6 +419,7 @@ void SurfaceManager::generateSurfacefromWavefront(wavefront * wf){ gaussianRad &= 0xfffffffe; ++gaussianRad; + cv::GaussianBlur( wf->nulledData.clone(), wf->workData, cv::Size( gaussianRad, gaussianRad ),0,0,BORDER_REFLECT); } @@ -1053,7 +1055,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; From 577296f0493a0de8a563bb1b1a27ccf3f87406c2 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Thu, 6 Nov 2025 15:19:39 -0600 Subject: [PATCH 2/2] Made auto invert resizable --- annulushelpdlg.ui | 29 ++-- autoinvertdlg.cpp | 1 + autoinvertdlg.ui | 299 ++++++++++++++++++---------------------- zernikesmoothingdlg.cpp | 5 - 4 files changed, 150 insertions(+), 184 deletions(-) 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/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()