4 #include "moc_ImageViewer.cpp"
10 : QModuleWidget(Owner, parent),
11 HistogramContextMenu(new QMenu(this)), HistogramLinLogActionGroup(new QActionGroup(this)),
12 HistogramBarSetI(nullptr), HistogramBarSetR(nullptr), HistogramBarSetG(nullptr), HistogramBarSetB(nullptr),
13 HistogramBarSeries(new QBarSeries(this)), HistogramChart(nullptr), HistogramXAxis(new QValueAxis(this)), HistogramYAxis(new QValueAxis(this)),
14 GraphicsView(nullptr), GraphicsPixmapItem(nullptr), GraphicsScene(new QGraphicsScene(this))
18 ui.action_Zoom_fit->setChecked(
true);
35 ui.Histogram->setRenderHint(QPainter::Antialiasing);
51 QSizePolicy ImageSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
52 ImageSizePolicy.setHorizontalStretch(1);
53 ImageSizePolicy.setVerticalStretch(0);
54 ImageSizePolicy.setHeightForWidth(
GraphicsView->sizePolicy().hasHeightForWidth());
57 GraphicsView->viewport()->setProperty(
"cursor", QVariant(QCursor(Qt::CrossCursor)));
58 GraphicsView->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
62 GraphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
69 Pixmap = QPixmap::fromImage(NewImage);
81 IntensityHistogram = std::move(NewIntensityHistogram);
86 RGBHistogram = std::move(NewRGBHistogram);
93 if (!
ui.ExposureTimeGroupBox->isVisible() ||
ui.ExposureTimeGroupBox->visibleRegion().isEmpty())
94 return CHT::NoHistogram;
97 return HistogramColorAction->isChecked() ? CHT::IntensityAndRGBHistogram : CHT::IntensityHistogram;
99 return CHT::RGBHistogram;
101 return CHT::NoHistogram;
114 if (
ui.ExposureTimeGroupBox->isVisible() && !
ui.ExposureTimeGroupBox->visibleRegion().isEmpty())
117 ui.ImageGeometry->setText(QString::number(
Pixmap.width()) +
" x " + QString::number(
Pixmap.height()));
123 if (event->type() == QEvent::MouseMove)
130 return QObject::eventFilter(obj, event);
143 if (ComputeHistogram == CHT::NoHistogram ||
IntensityHistogram.size() >= std::numeric_limits<int>::max())
167 if (ComputeHistogram == CHT::IntensityHistogram ||
168 ComputeHistogram == CHT::IntensityAndRGBHistogram)
175 if (ComputeHistogram == CHT::RGBHistogram ||
176 ComputeHistogram == CHT::IntensityAndRGBHistogram)
231 if (Filename.isEmpty())
239 ui.action_Zoom_fit->setChecked(
false);
245 ui.action_Zoom_fit->setChecked(
false);
251 ui.action_Zoom_fit->setChecked(
false);
263 auto LocalPoint =
GraphicsView->mapFromGlobal(Event->globalPos());
267 auto Point =
GraphicsView->mapToScene(LocalPoint).toPoint();
269 ui.CursorPosition->setText(
"X:" + QString::number(Point.x()) +
", Y:" + QString::number(Point.y()));
286 return std::numeric_limits<double>::quiet_NaN();
288 const auto GrayImage =
CurrentImage.convertToFormat(QImage::Format::Format_Grayscale8);
289 auto RawImage = GrayImage.constBits();
291 double BrennerGradient = .0;
292 for (
int y = 0; y < GrayImage.height(); ++y)
294 for (
int x = 0; x < GrayImage.width() - 2; ++x)
296 BrennerGradient += std::pow((
static_cast<double>(*RawImage) -
static_cast<double>(*(RawImage + 2))) / 255.0, 2);
305 return BrennerGradient / GrayImage.width() / GrayImage.height() * 1e3;
330 : QModuleBase(OwnerThreadID, std::move(Params)),
331 StateMachine(ReadyState,
332 AutofocusInitState, AutofocusGotoSampleState, AutofocusWaitBeforeCaptureState,
333 AutofocusWaitForImageState, AutofocusStepState, AutofocusFinishedState),
334 PauseUpdatingUI(std::make_shared<std::atomic<bool>>(false))
338 ImageViewer::~ImageViewer()
350 if (!Image.save(Filename))
385 std::unique_ptr<DynExp::QModuleWidget> ImageViewer::MakeUIWidget()
387 auto Widget = std::make_unique<ImageViewerWidget>(*
this);
398 void ImageViewer::UpdateUIChild(
const ModuleBase::ModuleDataGetterType& ModuleDataGetter)
405 auto Widget = GetWidget<ImageViewerWidget>();
406 auto ModuleData = DynExp::dynamic_ModuleData_cast<ImageViewer>(ModuleDataGetter());
417 Widget->ui.CameraModeGroupBox->setVisible(
false);
420 for (
const auto& Mode :
ModuleData->CameraModes)
422 Widget->ui.CBCameraMode->insertItem(
Widget->ui.CBCameraMode->count(), QString::fromStdString(Mode));
423 Widget->ui.CBCameraMode->setItemData(
Widget->ui.CBCameraMode->count() - 1, QString::fromStdString(Mode), Qt::ToolTipRole);
427 Widget->ui.CBCameraMode->setCurrentIndex(0);
433 Widget->ui.action_Save_Image->setEnabled(Ready);
434 Widget->ui.action_Capture_Frame->setEnabled(Ready);
435 Widget->ui.action_Capture_continuously->setEnabled(Ready);
436 Widget->ui.CameraModeGroupBox->setEnabled(Ready);
437 Widget->ui.ImageModifiersGroupBox->setEnabled(Ready);
438 Widget->ui.Histogram->setEnabled(Ready);
439 Widget->SetImageViewEnabled(Ready);
441 Widget->ui.ExposureTimeGroupBox->setEnabled(Ready &&
ModuleData->Camera->CanSetExposureTime());
442 Widget->ui.ExposureTimeMinValue->setText(
"min. " + QString::number(
ModuleData->MinExposureTime.count()) +
" ms");
443 Widget->ui.ExposureTimeMaxValue->setText(
"max. " + QString::number(
ModuleData->MaxExposureTime.count()) +
" ms");
447 if (!
Widget->ui.ExposureTime->hasFocus())
449 const QSignalBlocker Blocker(
Widget->ui.ExposureTime);
450 Widget->ui.ExposureTime->setValue(Util::NumToT<int>(
ModuleData->CurrentExposureTime.count()));
453 if (!Autofocusing && !
ModuleData->ImageCapturingPaused)
456 if (
Widget->ui.ImageModifiersGroupBox->isChecked())
460 ImageTransformation.
ContrastFactor = std::pow(10,
Widget->ui.ImageModifiersContrast->value() / 10.f);
465 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
466 CameraData->SetImageTransformation(ImageTransformation);
478 if (
ModuleData->ComputeHistogram == CHT::IntensityHistogram ||
479 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
481 if (
ModuleData->ComputeHistogram == CHT::RGBHistogram ||
482 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
488 if (Ready && !
Widget->GetSaveImageFilename().isEmpty())
493 Widget->ResetSaveImageFilename();
497 Widget->ui.action_Autofocus->setChecked(Autofocusing);
500 Widget->ui.CurrentFPS->setText(
"Autofocusing...");
502 Widget->ui.CurrentFPS->setText(
"Capturing frame...");
506 Widget->ui.CurrentFPS->setText(
"Capturing... (FPS: " + QString::number(
ModuleData->CurrentFPS,
'f', 1) +
507 +
", Brenner gradient: " + QString::number(
ModuleData->CalcBrennerGradientFromImage(),
'f', 3) +
")");
509 Widget->ui.CurrentFPS->setText(
"Capturing... (FPS: " + QString::number(
ModuleData->CurrentFPS,
'f', 1) +
")");
513 Widget->ui.CurrentFPS->setText(
"Stopped");
516 bool ImageViewer::IsReadyState()
const
518 const auto CurrentState =
StateMachine.GetCurrentState()->GetState();
523 bool ImageViewer::IsAutofocusingState()
const
525 const auto CurrentState =
StateMachine.GetCurrentState()->GetState();
538 ModuleData->Communicator->PostEvent(*
this, Event);
550 auto ModuleParams = DynExp::dynamic_Params_cast<ImageViewer>(Instance->
ParamsGetter());
554 if (ModuleParams->Focus.ContainsID())
561 if (ModuleParams->Communicator.ContainsID())
564 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
565 ModuleData->CameraModes = CameraData->GetCameraModes();
589 ModuleData->Camera->SetCameraMode(Util::NumToT<size_t>(Index),
605 ModuleData->Camera->SetExposureTime(std::chrono::milliseconds(Value),
646 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
649 ModuleData->CaptureAfterPause = CameraData->IsCapturingContinuously();
651 if (ResetImageTransformation)
652 CameraData->SetImageTransformation({});
707 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
709 if (ResetImageTransformation)
710 CameraData->SetImageTransformation({});
712 ModuleData->CaptureAfterPause = CameraData->IsCapturingContinuously();
718 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
719 CameraData->SetComputeHistogram(CHT::NoHistogram);
730 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
732 ModuleData->CapturingState = CameraData->GetCapturingState();
733 ModuleData->MinExposureTime = CameraData->GetMinExposureTime();
734 ModuleData->MaxExposureTime = CameraData->GetMaxExposureTime();
735 ModuleData->CurrentExposureTime = CameraData->GetExposureTime();
736 ModuleData->CurrentFPS = CameraData->GetCurrentFPS();
738 CameraData->SetComputeHistogram(
ModuleData->ComputeHistogram);
740 if (CameraData->IsImageAvailbale() && !
ModuleData->ImageCapturingPaused)
742 ModuleData->CurrentImage = CameraData->GetImage();
745 if (
ModuleData->ComputeHistogram == CHT::IntensityHistogram ||
746 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
747 ModuleData->IntensityHistogram = CameraData->GetIntensityHistogram();
748 if (
ModuleData->ComputeHistogram == CHT::RGBHistogram ||
749 ModuleData->ComputeHistogram == CHT::IntensityAndRGBHistogram)
750 ModuleData->RGBHistogram = CameraData->GetRGBHistogram();
759 auto ModuleParams = DynExp::dynamic_Params_cast<ImageViewer>(Instance.
ParamsGetter());
770 AutofocusSamples.emplace_back(Voltage, std::numeric_limits<double>::quiet_NaN());
796 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
798 CameraData->ClearImage();
810 auto CameraData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Camera>(
ModuleData->Camera->GetInstrumentData());
812 if (CameraData->IsImageAvailbale())
814 ModuleData->CurrentExposureTime = CameraData->GetExposureTime();
815 ModuleData->CurrentImage = CameraData->GetImage();
833 return a.Result < b.Result;
844 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).
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
DynExpInstr::CameraData::CameraModesType CameraModes
DynExpInstr::CameraData::ComputeHistogramType ComputeHistogram
DynExpInstr::CameraData::CapturingStateType CapturingState
TimeType CurrentExposureTime
Util::ImageHistogramType IntensityHistogram
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
void OnCaptureSingle(DynExp::ModuleInstance *Instance, bool) const
void OnCaptureContinuously(DynExp::ModuleInstance *Instance, bool Checked) const
bool IsAutofocusingState() const
AutofocusParamsType AutofocusParams
void OnExposureTimeChanged(DynExp::ModuleInstance *Instance, int Value) const
std::vector< AutofocusSampleType >::iterator AutofocusCurrentSample
std::vector< AutofocusSampleType > AutofocusSamples
bool IsReadyState() const
bool AutofocusIsPerformingFineSweep
void OnAutofocusClicked(DynExp::ModuleInstance *Instance, bool Checked) const
AutofocusResultsType AutofocusResults
const std::shared_ptr< std::atomic< bool > > PauseUpdatingUI
Util::StateMachine< StateMachineStateType > StateMachine
size_t NumFailedUpdateAttempts
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)
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. Indirectly calls ModuleBase::RemoveRegistere...
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.
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
const QColor green("lime")
const QColor blue(42, 130, 218)
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