Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ set(SCOPEONE_UI_SOURCES
src/PositionListFile.cpp
src/CollapsibleSection.cpp
src/ToolIcons.cpp
src/ImageOps.cpp
src/ParameterDialog.cpp
src/ResultsWindow.cpp
src/RoiManagerWindow.cpp
src/ProfilePlotWindow.cpp
src/ImageAnalysis.cpp
src/OrthogonalViewsDialog.cpp
src/UpdateChecker.cpp
src/DevicePropertyWidget.cpp
src/ConfigPresetWidget.cpp
Expand All @@ -106,6 +113,13 @@ set(SCOPEONE_UI_HEADERS
src/PositionListFile.h
src/CollapsibleSection.h
src/ToolIcons.h
src/ImageOps.h
src/ParameterDialog.h
src/ResultsWindow.h
src/RoiManagerWindow.h
src/ProfilePlotWindow.h
src/ImageAnalysis.h
src/OrthogonalViewsDialog.h
src/UpdateChecker.h
src/DevicePropertyWidget.h
src/ConfigPresetWidget.h
Expand Down
7 changes: 7 additions & 0 deletions ScopeOneCore/include/scopeone/ScopeOneCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@ namespace scopeone::core
return recordedFrameCount() > 0;
}

// One recorded frame, from memory or from the files that were written. Invalid when
// there is no such frame.
ImageFrame recordedFrame(const QString& cameraId, int index) const
{
return imageFrameAt(cameraId, index);
}

bool isSaved() const { return m_saved; }
const QString& saveMessage() const { return m_saveMessage; }

Expand Down
645 changes: 645 additions & 0 deletions src/ImageAnalysis.cpp

Large diffs are not rendered by default.

98 changes: 98 additions & 0 deletions src/ImageAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#pragma once

#include "ImageOps.h"
#include "scopeone/ScopeOneCore.h"

#include <QList>
#include <QObject>
#include <QPointer>
#include <QString>

#include <functional>
#include <memory>

class QAction;
class QMenu;
class QMenuBar;
class QWidget;

namespace scopeone::ui
{
class ImageWorkspace;
class ProfilePlotWindow;
class ResultsWindow;
class RoiManagerWindow;

// The Image, Process and Analyze menus in the manner of ImageJ. Every command works on the
// active image, or on all of its slices, and puts its result in a new image.
class ImageAnalysis : public QObject
{
Q_OBJECT

public:
using Presenter = std::function<void(
const std::shared_ptr<scopeone::core::ScopeOneCore::RecordingSessionData>&, const QString&)>;

ImageAnalysis(scopeone::core::ScopeOneCore* core, ImageWorkspace* workspace, QWidget* window,
QObject* parent = nullptr);

// Where a new image is shown
void setPresenter(Presenter presenter) { m_presenter = std::move(presenter); }
// Adds the menus to the menu bar in front of the given action
void addMenus(QMenuBar* menuBar, QAction* before);

private:
// The image that a command works on
struct Source
{
QList<scopeone::core::ImageFrame> frames;
int index{0};
QString title;
QString layerKey;
scopeone::core::ImageSceneModel* scene{nullptr};
};
enum class Scope { Cancel, Current, All };

bool activeSource(Source& source) const;
double pixelScale(const Source& source) const;
bool selectedShape(const Source& source, scopeone::core::ImageSceneModel::Markup& shape) const;
Scope chooseScope(const Source& source, const QString& command) const;
// Makes a new image from the slices that a command works on
void present(const QList<scopeone::core::ImageFrame>& frames, const QString& title);
using FrameOperation = std::function<scopeone::core::ImageFrame(const scopeone::core::ImageFrame&)>;
void apply(const QString& title, const FrameOperation& operation);

void buildImageMenu(QMenu* menu);
void buildProcessMenu(QMenu* menu);
void buildAnalyzeMenu(QMenu* menu);
void addFilter(QMenu* menu, const QString& text, imageops::Filter filter, double radius);
void addMath(QMenu* menu, const QString& text, imageops::MathOperation operation, bool needsValue,
double value);
void addBinary(QMenu* menu, const QString& text, imageops::BinaryOperation operation);

void duplicateImage();
void cropImage();
void scaleImage();
void rotateImage();
void thresholdImage();
void zProject();
void makeSubstack();
void makeMontage();
void plotZProfile();
void showOrthogonalViews();
void subtractBackground();
void unsharpMask();
void calculate();
void measure();
void measureShapes(const QList<scopeone::core::ImageSceneModel::Markup>& shapes, bool allSlices);

scopeone::core::ScopeOneCore* m_core{nullptr};
ImageWorkspace* m_workspace{nullptr};
QWidget* m_window{nullptr};
Presenter m_presenter;
QPointer<ResultsWindow> m_results;
QPointer<RoiManagerWindow> m_roiManager;
QPointer<ProfilePlotWindow> m_profile;
int m_resultCount{0};
};
}
Loading