viewer: load user mask from TIFF (replace or add)
Two Mask-menu entries read a 16-bit TIFF (via ReadTIFFFromString16) and apply it as the user mask: "replace" overwrites the current mask, "add" unions the TIFF into it. The TIFF must match the detector dimensions; any non-zero pixel masks. Both go through UpdateUserMask_i like the other mask edits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include "../common/JFJochMath.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/stat.h>
|
||||
@@ -747,6 +749,40 @@ void JFJochImageReadingWorker::SaveUserMaskTIFF(QString filename) {
|
||||
WriteTIFFToFile(filename.toStdString(), mask_image);
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::LoadUserMaskTIFF(QString filename, bool replace) {
|
||||
QMutexLocker locker(&m);
|
||||
if (!current_image_ptr)
|
||||
return;
|
||||
|
||||
std::ifstream f(filename.toStdString(), std::ios::binary);
|
||||
const std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
|
||||
uint32_t cols = 0, lines = 0;
|
||||
std::vector<uint16_t> tiff;
|
||||
try {
|
||||
tiff = ReadTIFFFromString16(content, cols, lines);
|
||||
} catch (const std::exception &e) {
|
||||
logger.Error("Could not read mask TIFF {}: {}", filename.toStdString(), e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t width = current_image_ptr->Dataset().experiment.GetXPixelsNum();
|
||||
const int64_t height = current_image_ptr->Dataset().experiment.GetYPixelsNum();
|
||||
if (static_cast<int64_t>(cols) != width || static_cast<int64_t>(lines) != height) {
|
||||
logger.Error("Mask TIFF is {}x{} but the detector is {}x{}", cols, lines, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
// replace: start from an empty mask; add: keep the current one. A non-zero TIFF pixel masks.
|
||||
auto user_mask = replace ? std::vector<uint32_t>(width * height, 0)
|
||||
: current_image_ptr->Dataset().pixel_mask.GetUserMask();
|
||||
for (size_t i = 0; i < tiff.size(); i++)
|
||||
if (tiff[i] != 0)
|
||||
user_mask[i] = 1;
|
||||
|
||||
UpdateUserMask_i(user_mask);
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::UploadUserMask() {
|
||||
QMutexLocker locker(&m);
|
||||
if (!current_image_ptr)
|
||||
|
||||
@@ -175,6 +175,7 @@ public slots:
|
||||
void UploadROIsToServer();
|
||||
|
||||
void SaveUserMaskTIFF(QString filename);
|
||||
void LoadUserMaskTIFF(QString filename, bool replace);
|
||||
void UploadUserMask();
|
||||
void ClearUserMask();
|
||||
|
||||
|
||||
@@ -44,6 +44,12 @@ JFJochViewerMenu::JFJochViewerMenu(QWidget *parent) : QMenuBar(parent) {
|
||||
const QAction *saveMaskTiff = maskMenu->addAction("Save User Mask as TIFF...");
|
||||
connect(saveMaskTiff, &QAction::triggered, this, &JFJochViewerMenu::saveUserMaskAsTiffSelected);
|
||||
|
||||
const QAction *loadMaskReplace = maskMenu->addAction("Load User Mask from TIFF (replace)...");
|
||||
connect(loadMaskReplace, &QAction::triggered, [this] { openLoadUserMaskTiff(true); });
|
||||
|
||||
const QAction *loadMaskAdd = maskMenu->addAction("Load User Mask from TIFF (add)...");
|
||||
connect(loadMaskAdd, &QAction::triggered, [this] { openLoadUserMaskTiff(false); });
|
||||
|
||||
const QAction *uploadMask = maskMenu->addAction("&Upload User Mask");
|
||||
connect(uploadMask, &QAction::triggered, this, &JFJochViewerMenu::uploadUserMaskAction);
|
||||
|
||||
@@ -185,6 +191,17 @@ void JFJochViewerMenu::saveUserMaskAsTiffSelected() {
|
||||
}
|
||||
}
|
||||
|
||||
void JFJochViewerMenu::openLoadUserMaskTiff(bool replace) {
|
||||
QString filename = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
replace ? "Load User Mask from TIFF (replace)" : "Load User Mask from TIFF (add)",
|
||||
"",
|
||||
"TIFF Images (*.tif *.tiff);;All Files (*)"
|
||||
);
|
||||
if (!filename.isEmpty())
|
||||
emit loadUserMaskTiffSelected(filename, replace);
|
||||
}
|
||||
|
||||
void JFJochViewerMenu::uploadUserMaskAction() {
|
||||
auto reply = QMessageBox::question(
|
||||
this,
|
||||
|
||||
@@ -28,6 +28,7 @@ signals:
|
||||
void fileCloseSelected();
|
||||
|
||||
void saveUserMaskTiffSelected(const QString &filename);
|
||||
void loadUserMaskTiffSelected(const QString &filename, bool replace);
|
||||
void uploadUserMaskSelected();
|
||||
void clearUserMaskSelected();
|
||||
void openDatasetInfo();
|
||||
@@ -41,4 +42,7 @@ private slots:
|
||||
|
||||
void saveUserMaskAsTiffSelected();
|
||||
void uploadUserMaskAction();
|
||||
|
||||
private:
|
||||
void openLoadUserMaskTiff(bool replace);
|
||||
};
|
||||
|
||||
@@ -208,6 +208,9 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
|
||||
connect(menuBar, &JFJochViewerMenu::saveUserMaskTiffSelected,
|
||||
reading_worker, &JFJochImageReadingWorker::SaveUserMaskTIFF);
|
||||
|
||||
connect(menuBar, &JFJochViewerMenu::loadUserMaskTiffSelected,
|
||||
reading_worker, &JFJochImageReadingWorker::LoadUserMaskTIFF);
|
||||
|
||||
connect(menuBar, &JFJochViewerMenu::uploadUserMaskSelected,
|
||||
reading_worker, &JFJochImageReadingWorker::UploadUserMask);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user