4#include "moc_ImageViewer.cpp"
5#include "ui_ImageViewer.h"
11 : QModuleWidget(Owner, parent),
13 HistogramContextMenu(new QMenu(this)), HistogramLinLogActionGroup(new QActionGroup(this)),
14 HistogramBarSetI(nullptr), HistogramBarSetR(nullptr), HistogramBarSetG(nullptr), HistogramBarSetB(nullptr),
15 HistogramBarSeries(new QBarSeries(this)), HistogramChart(nullptr), HistogramXAxis(new QValueAxis(this)), HistogramYAxis(new QValueAxis(this)),
16 GraphicsView(nullptr), GraphicsPixmapItem(nullptr), GraphicsScene(new QGraphicsScene(this))
20 ui->action_Zoom_fit->setChecked(
true);
37 ui->Histogram->setRenderHint(QPainter::Antialiasing);
53 QSizePolicy ImageSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
54 ImageSizePolicy.setHorizontalStretch(1);
55 ImageSizePolicy.setVerticalStretch(0);
56 ImageSizePolicy.setHeightForWidth(
GraphicsView->sizePolicy().hasHeightForWidth());
59 GraphicsView->viewport()->setProperty(
"cursor", QVariant(QCursor(Qt::CrossCursor)));
60 GraphicsView->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
64 GraphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
71 Pixmap = QPixmap::fromImage(NewImage);
83 IntensityHistogram = std::move(NewIntensityHistogram);
88 RGBHistogram = std::move(NewRGBHistogram);
95 if (!
ui->ExposureTimeGroupBox->isVisible() ||
ui->ExposureTimeGroupBox->visibleRegion().isEmpty())
96 return CHT::NoHistogram;
99 return HistogramColorAction->isChecked() ? CHT::IntensityAndRGBHistogram : CHT::IntensityHistogram;
101 return CHT::RGBHistogram;
103 return CHT::NoHistogram;
116 if (
ui->ExposureTimeGroupBox->isVisible() && !
ui->ExposureTimeGroupBox->visibleRegion().isEmpty())
119 ui->ImageGeometry->setText(QString::number(
Pixmap.width()) +
" x " + QString::number(
Pixmap.height()));
125 if (event->type() == QEvent::MouseMove)
132 return QObject::eventFilter(obj, event);
145 if (ComputeHistogram == CHT::NoHistogram ||
IntensityHistogram.size() >= std::numeric_limits<int>::max())
169 if (ComputeHistogram == CHT::IntensityHistogram ||
170 ComputeHistogram == CHT::IntensityAndRGBHistogram)
177 if (ComputeHistogram == CHT::RGBHistogram ||
178 ComputeHistogram == CHT::IntensityAndRGBHistogram)
233 if (Filename.isEmpty())
241 ui->action_Zoom_fit->setChecked(
false);
247 ui->action_Zoom_fit->setChecked(
false);
253 ui->action_Zoom_fit->setChecked(
false);
265 auto LocalPoint =
GraphicsView->mapFromGlobal(Event->globalPosition().toPoint());
269 auto Point =
GraphicsView->mapToScene(LocalPoint).toPoint();
271 ui->CursorPosition->setText(
"X:" + QString::number(Point.x()) +
", Y:" + QString::number(Point.y()));
288 return std::numeric_limits<double>::quiet_NaN();
290 const auto GrayImage =
CurrentImage.convertToFormat(QImage::Format::Format_Grayscale8);
291 auto RawImage = GrayImage.constBits();
293 double BrennerGradient = .0;
294 for (
int y = 0; y < GrayImage.height(); ++y)
296 for (
int x = 0; x < GrayImage.width() - 2; ++x)
298 BrennerGradient += std::pow((
static_cast<double>(*RawImage) -
static_cast<double>(*(RawImage + 2))) / 255.0, 2);
307 return BrennerGradient / GrayImage.width() / GrayImage.height() * 1e3;
333 : QModuleBase(OwnerThreadID, std::move(Params)),
334 StateMachine(ReadyState,
335 AutofocusInitState, AutofocusGotoSampleState, AutofocusWaitBeforeCaptureState,
336 AutofocusWaitForImageState, AutofocusStepState, AutofocusFinishedState),
337 PauseUpdatingUI(std::make_shared<std::atomic<bool>>(false))
353 if (!Image.save(Filename))
390 auto Widget = std::make_unique<ImageViewerWidget>(*
this);
408 auto Widget = GetWidget<ImageViewerWidget>();
409 auto ModuleData = DynExp::dynamic_ModuleData_cast<ImageViewer>(ModuleDataGetter());
420 Widget->ui->CameraModeGroupBox->setVisible(
false);
423 for (
const auto& Mode :
ModuleData->CameraModes)
425 Widget->ui->CBCameraMode->insertItem(
Widget->ui->CBCameraMode->count(), QString::fromStdString(Mode));
426 Widget->ui->CBCameraMode->setItemData(
Widget->ui->CBCameraMode->count() - 1, QString::fromStdString(Mode), Qt::ToolTipRole);
430 Widget->ui->CBCameraMode->setCurrentIndex(0);
437 Widget->ui->action_Capture_Frame->setEnabled(
Ready);
438 Widget->ui->action_Capture_continuously->setEnabled(
Ready);
440 Widget->ui->ImageModifiersGroupBox->setEnabled(
Ready);
445 Widget->ui->ExposureTimeMinValue->setText(
"min. " + QString::number(
ModuleData->MinExposureTime.count()) +
" ms");
446 Widget->ui->ExposureTimeMaxValue->setText(
"max. " + QString::number(
ModuleData->MaxExposureTime.count()) +
" ms");
450 if (!
Widget->ui->ExposureTime->hasFocus())
452 const QSignalBlocker Blocker(
Widget->ui->ExposureTime);
453 Widget->ui->ExposureTime->setValue(Util::NumToT<int>(
ModuleData->CurrentExposureTime.count()));
456 if (!Autofocusing && !
ModuleData->ImageCapturingPaused)
459 if (
Widget->ui->ImageModifiersGroupBox->isChecked())
463 ImageTransformation.
ContrastFactor = std::pow(10,
Widget->ui->ImageModifiersContrast->value() / 10.f);
468 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
469 CameraData->SetImageTransformation(ImageTransformation);
481 if (
ModuleData->ComputeHistogram == CHT::IntensityHistogram ||
482 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
484 if (
ModuleData->ComputeHistogram == CHT::RGBHistogram ||
485 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
491 if (
Ready && !
Widget->GetSaveImageFilename().isEmpty())
496 Widget->ResetSaveImageFilename();
500 Widget->ui->action_Autofocus->setChecked(Autofocusing);
503 Widget->ui->CurrentFPS->setText(
"Autofocusing...");
505 Widget->ui->CurrentFPS->setText(
"Capturing frame...");
509 Widget->ui->CurrentFPS->setText(
"Capturing... (FPS: " + QString::number(
ModuleData->CurrentFPS,
'f', 1) +
510 +
", Brenner gradient: " + QString::number(
ModuleData->CalcBrennerGradientFromImage(),
'f', 3) +
")");
512 Widget->ui->CurrentFPS->setText(
"Capturing... (FPS: " + QString::number(
ModuleData->CurrentFPS,
'f', 1) +
")");
516 Widget->ui->CurrentFPS->setText(
"Stopped");
521 const auto CurrentState =
StateMachine.GetCurrentState()->GetState();
528 const auto CurrentState =
StateMachine.GetCurrentState()->GetState();
541 ModuleData->Communicator->PostEvent(*
this, Event);
556 auto ModuleParams = DynExp::dynamic_Params_cast<ImageViewer>(Instance->
ParamsGetter());
560 if (ModuleParams->Focus.ContainsID())
567 if (ModuleParams->Communicator.ContainsID())
570 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
571 ModuleData->CameraModes = CameraData->GetCameraModes();
598 ModuleData->Camera->SetCameraMode(Util::NumToT<size_t>(Index),
614 ModuleData->Camera->SetExposureTime(std::chrono::milliseconds(Value),
657 ModuleData->AutoSaveFilename = SaveFilename +
".png";
688 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
691 ModuleData->CaptureAfterPause = CameraData->IsCapturingContinuously();
693 if (ResetImageTransformation)
694 CameraData->SetImageTransformation({});
749 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
751 if (ResetImageTransformation)
752 CameraData->SetImageTransformation({});
754 ModuleData->CaptureAfterPause = CameraData->IsCapturingContinuously();
760 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
761 CameraData->SetComputeHistogram(CHT::NoHistogram);
772 bool ImageAvailable =
false;
775 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
777 ModuleData->CapturingState = CameraData->GetCapturingState();
778 ModuleData->MinExposureTime = CameraData->GetMinExposureTime();
779 ModuleData->MaxExposureTime = CameraData->GetMaxExposureTime();
780 ModuleData->CurrentExposureTime = CameraData->GetExposureTime();
781 ModuleData->CurrentFPS = CameraData->GetCurrentFPS();
783 CameraData->SetComputeHistogram(
ModuleData->ComputeHistogram);
785 ImageAvailable = CameraData->IsImageAvailbale() && !
ModuleData->ImageCapturingPaused;
788 ModuleData->CurrentImage = CameraData->GetImage();
791 if (
ModuleData->ComputeHistogram == CHT::IntensityHistogram ||
792 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
793 ModuleData->IntensityHistogram = CameraData->GetIntensityHistogram();
794 if (
ModuleData->ComputeHistogram == CHT::RGBHistogram ||
795 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
796 ModuleData->RGBHistogram = CameraData->GetRGBHistogram();
800 if (ImageAvailable && !
ModuleData->AutoSaveFilename.empty())
802 QImage Image =
ModuleData->CurrentImage.copy();
803 if (!Image.save(QString::fromStdString(
ModuleData->AutoSaveFilename)))
818 auto ModuleParams = DynExp::dynamic_Params_cast<ImageViewer>(Instance.
ParamsGetter());
829 AutofocusSamples.emplace_back(Voltage, std::numeric_limits<double>::quiet_NaN());
855 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
857 CameraData->ClearImage();
869 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
871 if (CameraData->IsImageAvailbale())
873 ModuleData->CurrentExposureTime = CameraData->GetExposureTime();
874 ModuleData->CurrentImage = CameraData->GetImage();
892 return a.Result < b.Result;
903 AutofocusSamples.emplace_back(Voltage, std::numeric_limits<double>::quiet_NaN());
Implementation of a module to display images recorded by camera instruments.
@ CapturingSingle
The camera is caturing a single image and will stop afterwards.
@ CapturingContinuously
The camera is capturing one image after the other.
@ Stopped
The camera is not capturing.
float BrightnessFactor
Factor to enhance the image brightness (between -1 and 1).
bool IsEnabled
Determines whether the image transformation is to be applied (enabled).
ComputeHistogramType
Type indicating whether histograms should be computed for newly captured images.
@ NoHistogram
Histogram computation is disabled.
float ContrastFactor
Factor to enhance the image contrast. Valid interval is (0, Inf).
This event signals that an action (like a measurement) started by a TriggerEvent has been completed.
Util::ImageRGBHistogramType RGBHistogram
void ResetImpl(dispatch_tag< QModuleDataBase >) override final
bool ImageCapturingPaused
double CalcBrennerGradientFromImage() const
Calculates the Brenner gradient of CurrentImage. Refer to J. F. Brenner et al. J. Histochem....
DynExpInstr::CameraData::TimeType TimeType
std::string AutoSaveFilename
DynExpInstr::CameraData::CameraModesType CameraModes
DynExpInstr::CameraData::ComputeHistogramType ComputeHistogram
DynExpInstr::CameraData::CapturingStateType CapturingState
TimeType CurrentExposureTime
Util::ImageHistogramType IntensityHistogram
StateType AutofocusStepStateFunc(DynExp::ModuleInstance &Instance)
StateType AutofocusInitStateFunc(DynExp::ModuleInstance &Instance)
void FinishAutofocus(Util::SynchronizedPointer< ModuleDataType > &ModuleData, const FinishedAutofocusEvent &Event) const
void OnResumeImageCapturing(DynExp::ModuleInstance *Instance) const
void OnAutofocus(DynExp::ModuleInstance *Instance, bool ResetImageTransformation=false) const
StateType AutofocusFinishedStateFunc(DynExp::ModuleInstance &Instance)
void OnCaptureSingle(DynExp::ModuleInstance *Instance, bool) const
std::unique_ptr< DynExp::QModuleWidget > MakeUIWidget() override final
Used by InitUI() as a factory function for the module's user interface widget. Create the widget here...
void OnInit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread starts. Override it to lock instruments this m...
void OnSetFilename(DynExp::ModuleInstance *Instance, const std::string &SaveFilename) const
void OnStop(DynExp::ModuleInstance *Instance) const
Util::DynExpErrorCodes::DynExpErrorCodes ModuleMainLoop(DynExp::ModuleInstance &Instance) override final
Module main loop. The function is executed periodically by the module thread. Also refer to GetMainLo...
void OnCaptureContinuously(DynExp::ModuleInstance *Instance, bool Checked) const
bool IsAutofocusingState() const
AutofocusParamsType AutofocusParams
void OnTrigger(DynExp::ModuleInstance *Instance) const
StateType ReadyStateFunc(DynExp::ModuleInstance &Instance)
StateType AutofocusGotoSampleStateFunc(DynExp::ModuleInstance &Instance)
void OnExposureTimeChanged(DynExp::ModuleInstance *Instance, int Value) const
void OnExit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread terminates (not due to an exception,...
StateType AutofocusWaitForImageStateFunc(DynExp::ModuleInstance &Instance)
std::vector< AutofocusSampleType >::iterator AutofocusCurrentSample
std::vector< AutofocusSampleType > AutofocusSamples
StateType AutofocusWaitBeforeCaptureStateFunc(DynExp::ModuleInstance &Instance)
bool IsReadyState() const
bool AutofocusIsPerformingFineSweep
void OnAutofocusClicked(DynExp::ModuleInstance *Instance, bool Checked) const
void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter) override final
AutofocusResultsType AutofocusResults
const std::shared_ptr< std::atomic< bool > > PauseUpdatingUI
Util::StateMachine< StateMachineStateType > StateMachine
size_t NumFailedUpdateAttempts
void ResetImpl(dispatch_tag< QModuleBase >) override final
void OnCameraModeChanged(DynExp::ModuleInstance *Instance, int Index) const
void OnSaveImage(DynExp::ModuleInstance *Instance, QString Filename) const
std::chrono::system_clock::time_point AutofocusWaitingEndTimePoint
void OnPauseImageCapturing(DynExp::ModuleInstance *Instance, bool ResetImageTransformation=false) const
Wrapper holding a pointer to an exception and providing functionality for accessing it....
static void Register(const ModuleBase &Listener, CallableT EventFunc, ItemIDType CommunicatorID=ItemIDNotSet)
Registers/Subscribes module Listener to the event with the event function EventFunc....
static void Deregister(const ModuleBase &Listener)
Deregisters/unsubscribes module Listener from the event, regardless of the inter-module communicator ...
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
void MakeAndEnqueueEvent(ReceiverType *Receiver, EventType EventFuncPtr, ArgsTs &&...Args) const
Calls MakeEvent() to construct a new event and subsequently enqueues the event into the module's even...
Refer to ParamsBase::dispatch_tag.
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
const ModuleBase::ModuleDataGetterType ModuleDataGetter
Getter for module's data. Refer to ModuleBase::ModuleDataGetterType.
Refer to ParamsBase::dispatch_tag.
QModuleWidget * Widget
User interface widget belonging to the module.
void Connect(SenderType *Sender, SignalType Signal, ReceiverType *Receiver, EventType Event)
Uses Qt's connect mechanism to connect a QObject's signal to a DynExp module's event....
const Object::ParamsGetterType ParamsGetter
Invoke to obtain the parameters (derived from ParamsBase) of Owner.
void UnlockObject(LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer)
Unlocks an Object instance stored in the LinkedObjectWrapperContainer ObjectWrapperContainer....
void LockObject(const ParamsBase::Param< ObjectLink< ObjectT > > &LinkParam, LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer, std::chrono::milliseconds Timeout=ObjectLinkBase::LockObjectTimeoutDefault)
Locks an Object instance referenced by a parameter LinkParam of type ParamsBase::Param< ObjectLink< O...
const auto & GetOwner() const noexcept
Returns Owner.
std::function< void(const TaskBase *, ExceptionContainer &)> FuncType
Type of the owned callback function. The function receives a pointer to the task the CallbackType ins...
Base class for all tasks being processed by instruments. The class must not contain public virtual fu...
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
Implements a QGraphicsView the user can interact with to insert graphical markers....
void ZoomReset()
Resets the zoom.
void ZoomIn()
Zooms in one step.
void ZoomOut()
Zooms out one step.
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
@ AutofocusWaitBeforeCapture
constexpr auto DefaultQChartTheme
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
DynExpErrorCodes
DynExp's error codes
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
std::array< unsigned long long, 256 > ImageHistogramType
Alias which represents a histogram as a std::array with 256 numeric bins. The lowest (highest) index ...
std::tuple< ImageHistogramType, ImageHistogramType, ImageHistogramType > ImageRGBHistogramType
Alias which represents a RGB histogram as a std::tuple of three ImageHistogramType elements....
QString PromptSaveFilePathModule(DynExp::QModuleWidget *Parent, const QString &Title, const QString &DefaultSuffix, const QString &NameFilter)
Works as PromptOpenFilePath() but asks the user to select a single file which does not need to exist....
Accumulates include statements to provide a precompiled header.
DynExpInstr::AnalogOutData::SampleStreamType::SampleType MinVoltage
ParamsConfigDialog::NumberType NumSteps
constexpr auto GetVoltageIncrement(bool Fine=false) const noexcept
DynExpInstr::AnalogOutData::SampleStreamType::SampleType MaxVoltage
std::chrono::milliseconds WaitTimeBeforeCapture