mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-02-21 02:08:41 +01:00
Dev/multiple rois in aare (#263)
Reading multiple ROI's for aare - read_frame, read_n etc throws for multiple ROIs - new functions read_ROIs, read_n_ROIs - read_roi_into (used for python bindings - to not copy) all these functions use get_frame or get_frame_into where one passes the roi_index ## Refactoring: - each roi keeps track of its subfiles that one has to open e.g. subfiles can be opened several times - refactored class DetectorGeometry - keep track of the updated module geometries in new class ROIGeometry. - ModuleGeometry updates based on ROI ## ROIGeometry: - stores number of modules overlapping with ROI and its indices - size of ROI Note: only tested size of the resulting frames not the actual values --------- Co-authored-by: Erik Fröjdh <erik.frojdh@psi.ch> Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com>
This commit is contained in:
@@ -41,31 +41,16 @@ DetectorGeometry::DetectorGeometry(const xy &geometry,
|
||||
m_modules_x = geometry.col;
|
||||
m_modules_y = geometry.row;
|
||||
m_pixels_y += static_cast<size_t>((geometry.row - 1) * cfg.module_gap_row);
|
||||
|
||||
modules_in_roi.resize(num_modules);
|
||||
std::iota(modules_in_roi.begin(), modules_in_roi.end(), 0);
|
||||
}
|
||||
|
||||
size_t DetectorGeometry::n_modules() const { return m_modules_x * m_modules_y; }
|
||||
|
||||
size_t DetectorGeometry::n_modules_in_roi() const {
|
||||
return modules_in_roi.size();
|
||||
};
|
||||
|
||||
size_t DetectorGeometry::pixels_x() const { return m_pixels_x; }
|
||||
size_t DetectorGeometry::pixels_y() const { return m_pixels_y; }
|
||||
|
||||
size_t DetectorGeometry::modules_x() const { return m_modules_x; };
|
||||
size_t DetectorGeometry::modules_y() const { return m_modules_y; };
|
||||
|
||||
const std::vector<ssize_t> &DetectorGeometry::get_modules_in_roi() const {
|
||||
return modules_in_roi;
|
||||
}
|
||||
|
||||
ssize_t DetectorGeometry::get_modules_in_roi(const size_t index) const {
|
||||
return modules_in_roi[index];
|
||||
}
|
||||
|
||||
const std::vector<ModuleGeometry> &
|
||||
DetectorGeometry::get_module_geometries() const {
|
||||
return module_geometries;
|
||||
@@ -76,77 +61,8 @@ DetectorGeometry::get_module_geometries(const size_t index) const {
|
||||
return module_geometries[index];
|
||||
}
|
||||
|
||||
void DetectorGeometry::update_geometry_with_roi(ROI roi) {
|
||||
#ifdef AARE_VERBOSE
|
||||
fmt::println("update_geometry_with_roi() called with ROI: {} {} {} {}",
|
||||
roi.xmin, roi.xmax, roi.ymin, roi.ymax);
|
||||
fmt::println("Geometry: {} {} {} {} {} {}", m_modules_x, m_modules_y,
|
||||
m_pixels_x, m_pixels_y, cfg.module_gap_row,
|
||||
cfg.module_gap_col);
|
||||
|
||||
#endif
|
||||
|
||||
modules_in_roi.clear();
|
||||
modules_in_roi.reserve(m_modules_x * m_modules_y);
|
||||
int pos_y = 0;
|
||||
int pos_y_increment = 0;
|
||||
for (size_t row = 0; row < m_modules_y; row++) {
|
||||
int pos_x = 0;
|
||||
for (size_t col = 0; col < m_modules_x; col++) {
|
||||
auto &m = module_geometries[row * m_modules_x + col];
|
||||
|
||||
auto original_height = m.height;
|
||||
auto original_width = m.width;
|
||||
|
||||
// module is to the left of the roi
|
||||
if (m.origin_x + m.width < roi.xmin) {
|
||||
m.width = 0;
|
||||
|
||||
// roi is in module
|
||||
} else {
|
||||
// here we only arrive when the roi is in or to the left of
|
||||
// the module
|
||||
if (roi.xmin > m.origin_x) {
|
||||
m.width -= roi.xmin - m.origin_x;
|
||||
}
|
||||
if (roi.xmax < m.origin_x + original_width) {
|
||||
m.width -= m.origin_x + original_width - roi.xmax;
|
||||
}
|
||||
m.origin_x = pos_x;
|
||||
pos_x += m.width;
|
||||
}
|
||||
|
||||
if (m.origin_y + m.height < roi.ymin) {
|
||||
m.height = 0;
|
||||
} else {
|
||||
if ((roi.ymin > m.origin_y) &&
|
||||
(roi.ymin < m.origin_y + m.height)) {
|
||||
m.height -= roi.ymin - m.origin_y;
|
||||
}
|
||||
if (roi.ymax < m.origin_y + original_height) {
|
||||
m.height -= m.origin_y + original_height - roi.ymax;
|
||||
}
|
||||
m.origin_y = pos_y;
|
||||
pos_y_increment = m.height;
|
||||
}
|
||||
|
||||
if (m.height != 0 && m.width != 0) {
|
||||
modules_in_roi.push_back(row * m_modules_x + col);
|
||||
}
|
||||
|
||||
#ifdef AARE_VERBOSE
|
||||
fmt::println("Module {} {} {} {}", m.origin_x, m.origin_y, m.width,
|
||||
m.height);
|
||||
#endif
|
||||
}
|
||||
// increment pos_y
|
||||
pos_y += pos_y_increment;
|
||||
}
|
||||
|
||||
// m_rows = roi.height();
|
||||
// m_cols = roi.width();
|
||||
m_pixels_x = roi.width();
|
||||
m_pixels_y = roi.height();
|
||||
ModuleGeometry &DetectorGeometry::get_module_geometries(const size_t index) {
|
||||
return module_geometries[index];
|
||||
}
|
||||
|
||||
} // namespace aare
|
||||
@@ -7,17 +7,20 @@
|
||||
#include <filesystem>
|
||||
|
||||
#include "aare/DetectorGeometry.hpp"
|
||||
#include "aare/ROIGeometry.hpp"
|
||||
#include "test_config.hpp"
|
||||
|
||||
TEST_CASE("Simple ROIs on one module") {
|
||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
||||
// roi)
|
||||
TEST_CASE("Simple ROIs on one module", "[DetectorGeometry]") {
|
||||
aare::DetectorGeometry geo(aare::xy{1, 1}, 1024, 512);
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).origin_x == 0);
|
||||
REQUIRE(geo.get_module_geometries(0).origin_y == 0);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 1024);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
||||
REQUIRE(geo.modules_x() == 1);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.pixels_x() == 1024);
|
||||
REQUIRE(geo.pixels_y() == 512);
|
||||
|
||||
SECTION("ROI is the whole module") {
|
||||
aare::ROI roi;
|
||||
@@ -25,14 +28,18 @@ TEST_CASE("Simple ROIs on one module") {
|
||||
roi.xmax = 1024;
|
||||
roi.ymin = 0;
|
||||
roi.ymax = 512;
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 1024);
|
||||
REQUIRE(geo.pixels_y() == 512);
|
||||
REQUIRE(geo.modules_x() == 1);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 1024);
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
|
||||
REQUIRE(roi_geometry.pixels_x() == 1024);
|
||||
REQUIRE(roi_geometry.pixels_y() == 512);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 1);
|
||||
auto module_geometry =
|
||||
geo.get_module_geometries(roi_geometry.module_indices_in_roi(0));
|
||||
REQUIRE(module_geometry.height == 512);
|
||||
REQUIRE(module_geometry.width == 1024);
|
||||
REQUIRE(module_geometry.origin_x == 0);
|
||||
REQUIRE(module_geometry.origin_y == 0);
|
||||
}
|
||||
SECTION("ROI is the top left corner of the module") {
|
||||
aare::ROI roi;
|
||||
@@ -40,51 +47,22 @@ TEST_CASE("Simple ROIs on one module") {
|
||||
roi.xmax = 200;
|
||||
roi.ymin = 150;
|
||||
roi.ymax = 200;
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 100);
|
||||
REQUIRE(geo.pixels_y() == 50);
|
||||
REQUIRE(geo.modules_x() == 1);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 50);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 100);
|
||||
}
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
|
||||
SECTION("ROI is a small square") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 1000;
|
||||
roi.xmax = 1010;
|
||||
roi.ymin = 500;
|
||||
roi.ymax = 510;
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 10);
|
||||
REQUIRE(geo.pixels_y() == 10);
|
||||
REQUIRE(geo.modules_x() == 1);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 10);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 10);
|
||||
}
|
||||
SECTION("ROI is a few columns") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 750;
|
||||
roi.xmax = 800;
|
||||
roi.ymin = 0;
|
||||
roi.ymax = 512;
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 50);
|
||||
REQUIRE(geo.pixels_y() == 512);
|
||||
REQUIRE(geo.modules_x() == 1);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 50);
|
||||
REQUIRE(roi_geometry.pixels_x() == 100);
|
||||
REQUIRE(roi_geometry.pixels_y() == 50);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 1);
|
||||
auto module_geometry =
|
||||
geo.get_module_geometries(roi_geometry.module_indices_in_roi(0));
|
||||
REQUIRE(module_geometry.height == 50);
|
||||
REQUIRE(module_geometry.width == 100);
|
||||
REQUIRE(module_geometry.origin_x == 0);
|
||||
REQUIRE(module_geometry.origin_y == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Two modules side by side") {
|
||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
||||
// roi)
|
||||
TEST_CASE("Two modules side by side", "[DetectorGeometry]") {
|
||||
aare::DetectorGeometry geo(aare::xy{1, 2}, 1024, 512);
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).origin_x == 0);
|
||||
@@ -93,6 +71,10 @@ TEST_CASE("Two modules side by side") {
|
||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
||||
REQUIRE(geo.get_module_geometries(1).origin_x == 1024);
|
||||
REQUIRE(geo.get_module_geometries(1).origin_y == 0);
|
||||
REQUIRE(geo.modules_x() == 2);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.pixels_x() == 2048);
|
||||
REQUIRE(geo.pixels_y() == 512);
|
||||
|
||||
SECTION("ROI is the whole image") {
|
||||
aare::ROI roi;
|
||||
@@ -100,12 +82,24 @@ TEST_CASE("Two modules side by side") {
|
||||
roi.xmax = 2048;
|
||||
roi.ymin = 0;
|
||||
roi.ymax = 512;
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 2048);
|
||||
REQUIRE(geo.pixels_y() == 512);
|
||||
REQUIRE(geo.modules_x() == 2);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
|
||||
REQUIRE(roi_geometry.pixels_x() == 2048);
|
||||
REQUIRE(roi_geometry.pixels_y() == 512);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 2);
|
||||
|
||||
auto module_geometry_0 = geo.get_module_geometries(0);
|
||||
auto module_geometry_1 = geo.get_module_geometries(1);
|
||||
|
||||
REQUIRE(module_geometry_0.height == 512);
|
||||
REQUIRE(module_geometry_0.width == 1024);
|
||||
REQUIRE(module_geometry_1.height == 512);
|
||||
REQUIRE(module_geometry_1.width == 1024);
|
||||
REQUIRE(module_geometry_0.origin_x == 0);
|
||||
REQUIRE(module_geometry_1.origin_x == 1024);
|
||||
REQUIRE(module_geometry_0.origin_y == 0);
|
||||
REQUIRE(module_geometry_1.origin_y == 0);
|
||||
}
|
||||
SECTION("rectangle on both modules") {
|
||||
aare::ROI roi;
|
||||
@@ -113,28 +107,30 @@ TEST_CASE("Two modules side by side") {
|
||||
roi.xmax = 1300;
|
||||
roi.ymin = 200;
|
||||
roi.ymax = 499;
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 500);
|
||||
REQUIRE(geo.pixels_y() == 299);
|
||||
REQUIRE(geo.modules_x() == 2);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 299);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 224);
|
||||
REQUIRE(geo.get_module_geometries(1).height == 299);
|
||||
REQUIRE(geo.get_module_geometries(1).width == 276);
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
|
||||
REQUIRE(roi_geometry.pixels_x() == 500);
|
||||
REQUIRE(roi_geometry.pixels_y() == 299);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 2);
|
||||
|
||||
auto module_geometry_0 = geo.get_module_geometries(0);
|
||||
auto module_geometry_1 = geo.get_module_geometries(1);
|
||||
|
||||
REQUIRE(module_geometry_0.height == 299);
|
||||
REQUIRE(module_geometry_0.width == 224);
|
||||
REQUIRE(module_geometry_1.height == 299);
|
||||
REQUIRE(module_geometry_1.width == 276);
|
||||
REQUIRE(module_geometry_0.origin_x == 0);
|
||||
REQUIRE(module_geometry_1.origin_x == 224);
|
||||
REQUIRE(module_geometry_0.origin_y == 0);
|
||||
REQUIRE(module_geometry_1.origin_y == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Three modules side by side") {
|
||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
||||
// roi)
|
||||
TEST_CASE("Three modules side by side", "[DetectorGeometry]") {
|
||||
|
||||
aare::DetectorGeometry geo(aare::xy{1, 3}, 1024, 512);
|
||||
aare::ROI roi;
|
||||
roi.xmin = 700;
|
||||
roi.xmax = 2500;
|
||||
roi.ymin = 0;
|
||||
roi.ymax = 123;
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).origin_x == 0);
|
||||
REQUIRE(geo.get_module_geometries(0).origin_y == 0);
|
||||
@@ -142,24 +138,78 @@ TEST_CASE("Three modules side by side") {
|
||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
||||
REQUIRE(geo.get_module_geometries(1).origin_x == 1024);
|
||||
REQUIRE(geo.get_module_geometries(2).origin_x == 2048);
|
||||
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 1800);
|
||||
REQUIRE(geo.pixels_y() == 123);
|
||||
REQUIRE(geo.modules_x() == 3);
|
||||
REQUIRE(geo.modules_y() == 1);
|
||||
REQUIRE(geo.get_module_geometries(0).height == 123);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 324);
|
||||
REQUIRE(geo.get_module_geometries(1).height == 123);
|
||||
REQUIRE(geo.get_module_geometries(1).width == 1024);
|
||||
REQUIRE(geo.get_module_geometries(2).height == 123);
|
||||
REQUIRE(geo.get_module_geometries(2).width == 452);
|
||||
REQUIRE(geo.pixels_x() == 3072);
|
||||
REQUIRE(geo.pixels_y() == 512);
|
||||
|
||||
SECTION("ROI overlapping all three modules") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 500;
|
||||
roi.xmax = 2500;
|
||||
roi.ymin = 0;
|
||||
roi.ymax = 123;
|
||||
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
REQUIRE(roi_geometry.pixels_x() == 2000);
|
||||
REQUIRE(roi_geometry.pixels_y() == 123);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 3);
|
||||
|
||||
auto module_geometry_0 = geo.get_module_geometries(0);
|
||||
auto module_geometry_1 = geo.get_module_geometries(1);
|
||||
auto module_geometry_2 = geo.get_module_geometries(2);
|
||||
|
||||
REQUIRE(module_geometry_0.height == 123);
|
||||
REQUIRE(module_geometry_0.width == 524);
|
||||
REQUIRE(module_geometry_0.origin_x == 0);
|
||||
REQUIRE(module_geometry_0.origin_y == 0);
|
||||
|
||||
REQUIRE(module_geometry_1.height == 123);
|
||||
REQUIRE(module_geometry_1.width == 1024);
|
||||
REQUIRE(module_geometry_1.origin_x == 524);
|
||||
REQUIRE(module_geometry_1.origin_y == 0);
|
||||
|
||||
REQUIRE(module_geometry_2.height == 123);
|
||||
REQUIRE(module_geometry_2.width == 452);
|
||||
REQUIRE(module_geometry_2.origin_x == 1548);
|
||||
REQUIRE(module_geometry_2.origin_y == 0);
|
||||
}
|
||||
|
||||
SECTION("ROI overlapping last two modules") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 1050;
|
||||
roi.xmax = 2500;
|
||||
roi.ymin = 0;
|
||||
roi.ymax = 123;
|
||||
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
|
||||
REQUIRE(roi_geometry.pixels_x() == 1450);
|
||||
REQUIRE(roi_geometry.pixels_y() == 123);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 2);
|
||||
|
||||
auto module_geometry_0 = geo.get_module_geometries(0);
|
||||
auto module_geometry_1 = geo.get_module_geometries(1);
|
||||
auto module_geometry_2 = geo.get_module_geometries(2);
|
||||
|
||||
REQUIRE(module_geometry_0.height == 512);
|
||||
REQUIRE(module_geometry_0.width == 1024);
|
||||
REQUIRE(module_geometry_0.origin_x == 0);
|
||||
REQUIRE(module_geometry_0.origin_y == 0);
|
||||
|
||||
REQUIRE(module_geometry_1.height == 123);
|
||||
REQUIRE(module_geometry_1.width == 998);
|
||||
REQUIRE(module_geometry_1.origin_x == 0);
|
||||
REQUIRE(module_geometry_1.origin_y == 0);
|
||||
|
||||
REQUIRE(module_geometry_2.height == 123);
|
||||
REQUIRE(module_geometry_2.width == 452);
|
||||
REQUIRE(module_geometry_2.origin_x == 998);
|
||||
REQUIRE(module_geometry_2.origin_y == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Four modules as a square") {
|
||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
||||
// roi)
|
||||
TEST_CASE("Four modules as a square", "[DetectorGeometry]") {
|
||||
aare::DetectorGeometry geo(aare::xy{2, 2}, 1024, 512, aare::xy{1, 2});
|
||||
aare::ROI roi;
|
||||
roi.xmin = 500;
|
||||
@@ -177,19 +227,99 @@ TEST_CASE("Four modules as a square") {
|
||||
REQUIRE(geo.get_module_geometries(2).origin_y == 512);
|
||||
REQUIRE(geo.get_module_geometries(3).origin_x == 1024);
|
||||
REQUIRE(geo.get_module_geometries(3).origin_y == 512);
|
||||
|
||||
geo.update_geometry_with_roi(roi);
|
||||
|
||||
REQUIRE(geo.pixels_x() == 1500);
|
||||
REQUIRE(geo.pixels_y() == 100);
|
||||
REQUIRE(geo.modules_x() == 2);
|
||||
REQUIRE(geo.modules_y() == 2);
|
||||
REQUIRE(geo.pixels_x() == 2048);
|
||||
REQUIRE(geo.pixels_y() == 1024);
|
||||
|
||||
aare::ROIGeometry roi_geometry(roi, geo);
|
||||
|
||||
REQUIRE(roi_geometry.pixels_x() == 1500);
|
||||
REQUIRE(roi_geometry.pixels_y() == 100);
|
||||
REQUIRE(roi_geometry.num_modules_in_roi() == 4);
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).height == 12);
|
||||
REQUIRE(geo.get_module_geometries(0).width == 524);
|
||||
REQUIRE(geo.get_module_geometries(0).origin_x == 0);
|
||||
REQUIRE(geo.get_module_geometries(0).origin_y == 0);
|
||||
|
||||
REQUIRE(geo.get_module_geometries(1).height == 12);
|
||||
REQUIRE(geo.get_module_geometries(1).width == 976);
|
||||
REQUIRE(geo.get_module_geometries(1).origin_x == 524);
|
||||
REQUIRE(geo.get_module_geometries(1).origin_y == 0);
|
||||
|
||||
REQUIRE(geo.get_module_geometries(2).height == 88);
|
||||
REQUIRE(geo.get_module_geometries(2).width == 524);
|
||||
REQUIRE(geo.get_module_geometries(2).origin_x == 0);
|
||||
REQUIRE(geo.get_module_geometries(2).origin_y == 12);
|
||||
|
||||
REQUIRE(geo.get_module_geometries(3).height == 88);
|
||||
REQUIRE(geo.get_module_geometries(3).width == 976);
|
||||
REQUIRE(geo.get_module_geometries(3).origin_x == 524);
|
||||
REQUIRE(geo.get_module_geometries(3).origin_y == 12);
|
||||
}
|
||||
|
||||
TEST_CASE("check if module in ROI", "[DetectorGeometry]") {
|
||||
aare::DetectorGeometry geo(aare::xy{2, 2}, 1024, 512, aare::xy{1, 2});
|
||||
|
||||
SECTION("all modules in ROI") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 500;
|
||||
roi.xmax = 2000;
|
||||
roi.ymin = 500;
|
||||
roi.ymax = 600;
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(1).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(2).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(3).module_in_roi(roi) == true);
|
||||
}
|
||||
SECTION("some modules on border of ROI") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 1024;
|
||||
roi.xmax = 2000;
|
||||
roi.ymin = 500;
|
||||
roi.ymax = 600;
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).module_in_roi(roi) == false);
|
||||
REQUIRE(geo.get_module_geometries(1).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(2).module_in_roi(roi) == false);
|
||||
REQUIRE(geo.get_module_geometries(3).module_in_roi(roi) == true);
|
||||
}
|
||||
SECTION("one module on border of ROI") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 1025;
|
||||
roi.xmax = 2000;
|
||||
roi.ymin = 513;
|
||||
roi.ymax = 600;
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).module_in_roi(roi) == false);
|
||||
REQUIRE(geo.get_module_geometries(1).module_in_roi(roi) == false);
|
||||
REQUIRE(geo.get_module_geometries(2).module_in_roi(roi) == false);
|
||||
REQUIRE(geo.get_module_geometries(3).module_in_roi(roi) == true);
|
||||
}
|
||||
SECTION("some modules to the left of ROI") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 500;
|
||||
roi.xmax = 1024;
|
||||
roi.ymin = 500;
|
||||
roi.ymax = 600;
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(1).module_in_roi(roi) == false);
|
||||
REQUIRE(geo.get_module_geometries(2).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(3).module_in_roi(roi) == false);
|
||||
}
|
||||
SECTION("all modules in ROI") {
|
||||
aare::ROI roi;
|
||||
roi.xmin = 500;
|
||||
roi.xmax = 2000;
|
||||
roi.ymin = 10;
|
||||
roi.ymax = 513;
|
||||
|
||||
REQUIRE(geo.get_module_geometries(0).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(1).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(2).module_in_roi(roi) == true);
|
||||
REQUIRE(geo.get_module_geometries(3).module_in_roi(roi) == true);
|
||||
}
|
||||
}
|
||||
42
src/ROIGeometry.cpp
Normal file
42
src/ROIGeometry.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "aare/ROIGeometry.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace aare {
|
||||
|
||||
ROIGeometry::ROIGeometry(const ROI &roi, DetectorGeometry &geometry)
|
||||
: m_pixels_x(roi.width()), m_pixels_y(roi.height()), m_geometry(geometry) {
|
||||
m_module_indices_in_roi.reserve(m_geometry.n_modules());
|
||||
// determine which modules are in the roi
|
||||
for (size_t i = 0; i < m_geometry.n_modules(); ++i) {
|
||||
auto &module_geometry = m_geometry.get_module_geometries(i);
|
||||
if (module_geometry.module_in_roi(roi)) {
|
||||
module_geometry.update_geometry_with_roi(roi);
|
||||
m_module_indices_in_roi.push_back(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ROIGeometry::ROIGeometry(DetectorGeometry &geometry)
|
||||
: m_pixels_x(geometry.pixels_x()), m_pixels_y(geometry.pixels_y()),
|
||||
m_geometry(geometry) {
|
||||
m_module_indices_in_roi.resize(m_geometry.n_modules());
|
||||
std::iota(m_module_indices_in_roi.begin(), m_module_indices_in_roi.end(),
|
||||
0);
|
||||
};
|
||||
|
||||
size_t ROIGeometry::num_modules_in_roi() const {
|
||||
return m_module_indices_in_roi.size();
|
||||
}
|
||||
|
||||
const std::vector<size_t> &ROIGeometry::module_indices_in_roi() const {
|
||||
return m_module_indices_in_roi;
|
||||
}
|
||||
|
||||
size_t ROIGeometry::module_indices_in_roi(const size_t module_index) const {
|
||||
return m_module_indices_in_roi.at(module_index);
|
||||
}
|
||||
|
||||
size_t ROIGeometry::pixels_x() const { return m_pixels_x; }
|
||||
size_t ROIGeometry::pixels_y() const { return m_pixels_y; }
|
||||
|
||||
} // namespace aare
|
||||
330
src/RawFile.cpp
330
src/RawFile.cpp
@@ -2,6 +2,7 @@
|
||||
#include "aare/RawFile.hpp"
|
||||
#include "aare/DetectorGeometry.hpp"
|
||||
#include "aare/PixelMap.hpp"
|
||||
#include "aare/ROIGeometry.hpp"
|
||||
#include "aare/algorithm.hpp"
|
||||
#include "aare/defs.hpp"
|
||||
#include "aare/logger.hpp"
|
||||
@@ -17,28 +18,98 @@ RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode)
|
||||
: m_master(fname),
|
||||
m_geometry(m_master.geometry(), m_master.pixels_x(), m_master.pixels_y(),
|
||||
m_master.udp_interfaces_per_module(), m_master.quad()) {
|
||||
|
||||
m_mode = mode;
|
||||
|
||||
m_subfiles.resize(m_master.rois().has_value() ? m_master.rois()->size()
|
||||
: 1);
|
||||
|
||||
if (mode == "r") {
|
||||
if (m_master.roi()) {
|
||||
m_geometry.update_geometry_with_roi(m_master.roi().value());
|
||||
if (m_master.rois().has_value()) {
|
||||
m_ROI_geometries.reserve(m_master.rois()->size());
|
||||
|
||||
// iterate over all ROIS
|
||||
size_t roi_index = 0;
|
||||
const auto rois = m_master.rois().value();
|
||||
for (const auto &roi : rois) {
|
||||
m_ROI_geometries.push_back(ROIGeometry(roi, m_geometry));
|
||||
// open subfiles
|
||||
open_subfiles(roi_index);
|
||||
++roi_index;
|
||||
}
|
||||
|
||||
} else {
|
||||
// no ROI use full detector
|
||||
m_ROI_geometries.reserve(1);
|
||||
m_ROI_geometries.push_back(ROIGeometry(m_geometry));
|
||||
open_subfiles(0);
|
||||
}
|
||||
open_subfiles();
|
||||
} else {
|
||||
throw std::runtime_error(LOCATION +
|
||||
" Unsupported mode. Can only read RawFiles.");
|
||||
}
|
||||
}
|
||||
|
||||
Frame RawFile::read_frame() { return get_frame(m_current_frame++); }
|
||||
Frame RawFile::read_roi(const size_t roi_index) {
|
||||
|
||||
if (!m_master.rois()) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"No ROIs defined in the master file.");
|
||||
}
|
||||
if (roi_index >= m_ROI_geometries.size()) {
|
||||
throw std::runtime_error(LOCATION + "ROI index out of range.");
|
||||
}
|
||||
return get_frame(m_current_frame++, roi_index);
|
||||
}
|
||||
|
||||
|
||||
std::vector<Frame> RawFile::read_rois() {
|
||||
|
||||
if (!m_master.rois()) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"No ROIs defined in the master file.");
|
||||
}
|
||||
|
||||
const size_t num_rois = m_ROI_geometries.size();
|
||||
|
||||
std::vector<Frame> frames;
|
||||
frames.reserve(num_rois);
|
||||
|
||||
for (size_t roi_idx = 0; roi_idx < num_rois; ++roi_idx) {
|
||||
frames.push_back(get_frame(m_current_frame, roi_idx));
|
||||
}
|
||||
++m_current_frame;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Frame RawFile::read_frame() {
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Multiple ROIs defined in the master file. "
|
||||
"Use read_ROIs() instead.");
|
||||
}
|
||||
return get_frame(m_current_frame++);
|
||||
}
|
||||
|
||||
Frame RawFile::read_frame(size_t frame_number) {
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(
|
||||
LOCATION + "Multiple ROIs defined in the master file. "
|
||||
"Use read_ROIs(const size_t frame_number) instead.");
|
||||
}
|
||||
seek(frame_number);
|
||||
return read_frame();
|
||||
}
|
||||
|
||||
void RawFile::read_into(std::byte *image_buf, size_t n_frames) {
|
||||
// TODO: implement this in a more efficient way
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Cannot use read_into for multiple ROIs.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n_frames; i++) {
|
||||
this->get_frame_into(m_current_frame++, image_buf);
|
||||
@@ -47,33 +118,83 @@ void RawFile::read_into(std::byte *image_buf, size_t n_frames) {
|
||||
}
|
||||
|
||||
void RawFile::read_into(std::byte *image_buf) {
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Cannot use read_into for multiple ROIs. Use "
|
||||
"read_roi_into() for a single ROI instead.");
|
||||
}
|
||||
return get_frame_into(m_current_frame++, image_buf);
|
||||
}
|
||||
|
||||
void RawFile::read_into(std::byte *image_buf, DetectorHeader *header) {
|
||||
void RawFile::read_roi_into(std::byte *image_buf, const size_t roi_index,
|
||||
const size_t frame_number, DetectorHeader *header) {
|
||||
if (!m_master.rois().has_value()) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"No ROIs defined in the master file.");
|
||||
}
|
||||
if (roi_index >= num_rois()) {
|
||||
throw std::runtime_error(LOCATION + "ROI index out of range.");
|
||||
}
|
||||
return get_frame_into(frame_number, image_buf, roi_index, header);
|
||||
}
|
||||
|
||||
return get_frame_into(m_current_frame++, image_buf, header);
|
||||
void RawFile::read_into(std::byte *image_buf, DetectorHeader *header) {
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Cannot use read_into for multiple ROIs. Use "
|
||||
"read_roi_into() for a single ROI instead.");
|
||||
}
|
||||
return get_frame_into(m_current_frame++, image_buf, 0, header);
|
||||
}
|
||||
|
||||
void RawFile::read_into(std::byte *image_buf, size_t n_frames,
|
||||
DetectorHeader *header) {
|
||||
// return get_frame_into(m_current_frame++, image_buf, header);
|
||||
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(
|
||||
LOCATION +
|
||||
"Cannot use read_into for multiple ROIs."); // TODO: maybe pass
|
||||
// roi_index so one can
|
||||
// use read_into for a
|
||||
// specific ROI
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n_frames; i++) {
|
||||
this->get_frame_into(m_current_frame++, image_buf, header);
|
||||
this->get_frame_into(m_current_frame++, image_buf, 0, header);
|
||||
image_buf += bytes_per_frame();
|
||||
if (header)
|
||||
header += m_geometry.n_modules_in_roi();
|
||||
header += m_ROI_geometries[0].num_modules_in_roi();
|
||||
}
|
||||
}
|
||||
|
||||
size_t RawFile::bytes_per_frame() {
|
||||
return m_geometry.pixels_x() * m_geometry.pixels_y() * m_master.bitdepth() /
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(
|
||||
LOCATION + "Pass the desired roi_index to bytes_per_frame to get "
|
||||
"bytes_per_frame for the specific ROI. ");
|
||||
}
|
||||
return bytes_per_frame(0);
|
||||
}
|
||||
|
||||
size_t RawFile::bytes_per_frame(const size_t roi_index) {
|
||||
return m_ROI_geometries.at(roi_index).pixels_x() *
|
||||
m_ROI_geometries.at(roi_index).pixels_y() * m_master.bitdepth() /
|
||||
bits_per_byte;
|
||||
}
|
||||
|
||||
size_t RawFile::pixels_per_frame() {
|
||||
// return m_rows * m_cols;
|
||||
return m_geometry.pixels_x() * m_geometry.pixels_y();
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(
|
||||
LOCATION + "Pass the desired roi_index to pixels_per_frame to get "
|
||||
"pixels_per_frame for the specific ROI. ");
|
||||
}
|
||||
return pixels_per_frame(0);
|
||||
}
|
||||
|
||||
size_t RawFile::pixels_per_frame(const size_t roi_index) {
|
||||
return m_ROI_geometries.at(roi_index).pixels_x() *
|
||||
m_ROI_geometries.at(roi_index).pixels_y();
|
||||
}
|
||||
|
||||
DetectorType RawFile::detector_type() const { return m_master.detector_type(); }
|
||||
@@ -93,8 +214,29 @@ void RawFile::seek(size_t frame_index) {
|
||||
size_t RawFile::tell() { return m_current_frame; }
|
||||
|
||||
size_t RawFile::total_frames() const { return m_master.frames_in_file(); }
|
||||
size_t RawFile::rows() const { return m_geometry.pixels_y(); }
|
||||
size_t RawFile::cols() const { return m_geometry.pixels_x(); }
|
||||
|
||||
size_t RawFile::rows() const {
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Pass the desired roi_index to rows to get "
|
||||
"rows for the specific ROI. ");
|
||||
}
|
||||
return rows(0);
|
||||
}
|
||||
size_t RawFile::rows(const size_t roi_index) const {
|
||||
return m_ROI_geometries.at(roi_index).pixels_y();
|
||||
}
|
||||
size_t RawFile::cols() const {
|
||||
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Pass the desired roi_index to cols to get "
|
||||
"cols for the specific ROI. ");
|
||||
}
|
||||
return cols(0);
|
||||
}
|
||||
size_t RawFile::cols(const size_t roi_index) const {
|
||||
return m_ROI_geometries.at(roi_index).pixels_x();
|
||||
}
|
||||
size_t RawFile::bitdepth() const { return m_master.bitdepth(); }
|
||||
xy RawFile::geometry() const {
|
||||
return xy{static_cast<uint32_t>(m_geometry.modules_y()),
|
||||
@@ -102,19 +244,46 @@ xy RawFile::geometry() const {
|
||||
}
|
||||
|
||||
size_t RawFile::n_modules() const { return m_geometry.n_modules(); };
|
||||
size_t RawFile::n_modules_in_roi() const {
|
||||
return m_geometry.n_modules_in_roi();
|
||||
|
||||
size_t RawFile::num_rois() const {
|
||||
if (m_master.rois().has_value()) {
|
||||
return m_master.rois()->size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
void RawFile::open_subfiles() {
|
||||
if (m_mode == "r")
|
||||
for (size_t i : m_geometry.get_modules_in_roi()) {
|
||||
auto pos = m_geometry.get_module_geometries(i);
|
||||
m_subfiles.emplace_back(std::make_unique<RawSubFile>(
|
||||
const ROIGeometry &RawFile::roi_geometries(size_t roi_index) const {
|
||||
return m_ROI_geometries[roi_index];
|
||||
}
|
||||
|
||||
std::vector<size_t> RawFile::n_modules_in_roi() const {
|
||||
|
||||
std::vector<size_t> results(m_ROI_geometries.size());
|
||||
std::transform(
|
||||
m_ROI_geometries.begin(), m_ROI_geometries.end(), results.begin(),
|
||||
[](const ROIGeometry &roi) { return roi.num_modules_in_roi(); });
|
||||
return results;
|
||||
};
|
||||
|
||||
void RawFile::open_subfiles(const size_t roi_index) {
|
||||
|
||||
if (m_mode == "r") {
|
||||
|
||||
m_subfiles[roi_index].reserve(
|
||||
m_ROI_geometries[roi_index].num_modules_in_roi());
|
||||
|
||||
auto module_indices =
|
||||
m_ROI_geometries[roi_index].module_indices_in_roi();
|
||||
|
||||
for (const size_t i :
|
||||
m_ROI_geometries[roi_index].module_indices_in_roi()) {
|
||||
const auto pos = m_geometry.get_module_geometries(i);
|
||||
m_subfiles[roi_index].emplace_back(std::make_unique<RawSubFile>(
|
||||
m_master.data_fname(i, 0), m_master.detector_type(), pos.height,
|
||||
pos.width, m_master.bitdepth(), pos.row_index, pos.col_index));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Unsupported mode. Can only read RawFiles.");
|
||||
}
|
||||
@@ -139,33 +308,37 @@ DetectorHeader RawFile::read_header(const std::filesystem::path &fname) {
|
||||
|
||||
RawMasterFile RawFile::master() const { return m_master; }
|
||||
|
||||
Frame RawFile::get_frame(size_t frame_index) {
|
||||
auto f = Frame(m_geometry.pixels_y(), m_geometry.pixels_x(),
|
||||
Frame RawFile::get_frame(size_t frame_index, const size_t roi_index) {
|
||||
auto f = Frame(m_ROI_geometries[roi_index].pixels_y(),
|
||||
m_ROI_geometries[roi_index].pixels_x(),
|
||||
Dtype::from_bitdepth(m_master.bitdepth()));
|
||||
std::byte *frame_buffer = f.data();
|
||||
get_frame_into(frame_index, frame_buffer);
|
||||
get_frame_into(frame_index, frame_buffer, roi_index);
|
||||
return f;
|
||||
}
|
||||
|
||||
size_t RawFile::bytes_per_pixel() const { return m_master.bitdepth() / 8; }
|
||||
|
||||
void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
||||
DetectorHeader *header) {
|
||||
const size_t roi_index, DetectorHeader *header) {
|
||||
LOG(logDEBUG) << "RawFile::get_frame_into(" << frame_index << ")";
|
||||
if (frame_index >= total_frames()) {
|
||||
throw std::runtime_error(LOCATION + "Frame number out of range");
|
||||
}
|
||||
std::vector<size_t> frame_numbers(m_geometry.n_modules_in_roi());
|
||||
std::vector<size_t> frame_indices(m_geometry.n_modules_in_roi(),
|
||||
frame_index);
|
||||
std::vector<size_t> frame_numbers(
|
||||
m_ROI_geometries[roi_index].num_modules_in_roi());
|
||||
std::vector<size_t> frame_indices(
|
||||
m_ROI_geometries[roi_index].num_modules_in_roi(), frame_index);
|
||||
|
||||
// sync the frame numbers
|
||||
|
||||
if (m_geometry.n_modules() != 1) { // if we have more than one module
|
||||
for (size_t part_idx = 0; part_idx != m_geometry.n_modules_in_roi();
|
||||
if (m_ROI_geometries[roi_index].num_modules_in_roi() !=
|
||||
1) { // if we have more than one module
|
||||
for (size_t part_idx = 0;
|
||||
part_idx != m_ROI_geometries[roi_index].num_modules_in_roi();
|
||||
++part_idx) {
|
||||
frame_numbers[part_idx] =
|
||||
m_subfiles[part_idx]->frame_number(frame_index);
|
||||
m_subfiles[roi_index][part_idx]->frame_number(frame_index);
|
||||
}
|
||||
|
||||
// 1. if frame number vector is the same break
|
||||
@@ -176,7 +349,8 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
||||
frame_numbers.begin(),
|
||||
std::min_element(frame_numbers.begin(), frame_numbers.end()));
|
||||
|
||||
// 3. increase its index and update its respective frame number
|
||||
// 3. increase its index and update its respective frame
|
||||
// number
|
||||
frame_indices[min_frame_idx]++;
|
||||
|
||||
// 4. if we can't increase its index => throw error
|
||||
@@ -186,42 +360,50 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
||||
}
|
||||
|
||||
frame_numbers[min_frame_idx] =
|
||||
m_subfiles[min_frame_idx]->frame_number(
|
||||
m_subfiles[roi_index][min_frame_idx]->frame_number(
|
||||
frame_indices[min_frame_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_master.geometry().col == 1) {
|
||||
// get the part from each subfile and copy it to the frame
|
||||
for (size_t part_idx = 0; part_idx != m_geometry.n_modules_in_roi();
|
||||
for (size_t part_idx = 0;
|
||||
part_idx != m_ROI_geometries[roi_index].num_modules_in_roi();
|
||||
++part_idx) {
|
||||
auto corrected_idx = frame_indices[part_idx];
|
||||
|
||||
// This is where we start writing
|
||||
auto offset = (m_geometry
|
||||
.get_module_geometries(
|
||||
m_geometry.get_modules_in_roi(part_idx))
|
||||
.origin_y *
|
||||
m_geometry.pixels_x() +
|
||||
m_geometry
|
||||
.get_module_geometries(
|
||||
m_geometry.get_modules_in_roi(part_idx))
|
||||
.origin_x) *
|
||||
m_master.bitdepth() / 8;
|
||||
auto offset =
|
||||
(m_geometry
|
||||
.get_module_geometries(
|
||||
m_ROI_geometries[roi_index].module_indices_in_roi(
|
||||
part_idx))
|
||||
.origin_y *
|
||||
m_ROI_geometries[roi_index].pixels_x() +
|
||||
m_geometry
|
||||
.get_module_geometries(
|
||||
m_ROI_geometries[roi_index].module_indices_in_roi(
|
||||
part_idx))
|
||||
.origin_x) *
|
||||
m_master.bitdepth() / 8;
|
||||
|
||||
if (m_geometry
|
||||
.get_module_geometries(
|
||||
m_geometry.get_modules_in_roi(part_idx))
|
||||
m_ROI_geometries[roi_index].module_indices_in_roi(
|
||||
part_idx))
|
||||
.origin_x != 0)
|
||||
throw std::runtime_error(
|
||||
LOCATION +
|
||||
" Implementation error. x pos not 0."); // TODO: origin
|
||||
" Implementation error. x pos not 0."); // TODO:
|
||||
// origin
|
||||
// can still
|
||||
// change if roi
|
||||
// change if
|
||||
// roi
|
||||
// changes
|
||||
// TODO! What if the files don't match?
|
||||
m_subfiles[part_idx]->seek(corrected_idx);
|
||||
m_subfiles[part_idx]->read_into(frame_buffer + offset, header);
|
||||
m_subfiles[roi_index][part_idx]->seek(corrected_idx);
|
||||
m_subfiles[roi_index][part_idx]->read_into(frame_buffer + offset,
|
||||
header);
|
||||
if (header)
|
||||
++header;
|
||||
}
|
||||
@@ -230,23 +412,25 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
||||
// TODO! should we read row by row?
|
||||
|
||||
// create a buffer large enough to hold a full module
|
||||
auto bytes_per_part = m_master.pixels_y() * m_master.pixels_x() *
|
||||
m_master.bitdepth() /
|
||||
8; // TODO! replace with image_size_in_bytes
|
||||
auto bytes_per_part =
|
||||
m_master.pixels_y() * m_master.pixels_x() * m_master.bitdepth() /
|
||||
8; // TODO! replace with image_size_in_bytes // TODO
|
||||
// shouldnt it only be the module size? - check
|
||||
|
||||
auto *part_buffer = new std::byte[bytes_per_part];
|
||||
|
||||
// TODO! if we have many submodules we should reorder them on the
|
||||
// module level
|
||||
// TODO! if we have many submodules we should reorder them on
|
||||
// the module level
|
||||
|
||||
for (size_t part_idx = 0; part_idx != m_geometry.n_modules_in_roi();
|
||||
for (size_t part_idx = 0;
|
||||
part_idx != m_ROI_geometries[roi_index].num_modules_in_roi();
|
||||
++part_idx) {
|
||||
auto pos = m_geometry.get_module_geometries(
|
||||
m_geometry.get_modules_in_roi(part_idx));
|
||||
m_ROI_geometries[roi_index].module_indices_in_roi(part_idx));
|
||||
auto corrected_idx = frame_indices[part_idx];
|
||||
|
||||
m_subfiles[part_idx]->seek(corrected_idx);
|
||||
m_subfiles[part_idx]->read_into(part_buffer, header);
|
||||
m_subfiles[roi_index][part_idx]->seek(corrected_idx);
|
||||
m_subfiles[roi_index][part_idx]->read_into(part_buffer, header);
|
||||
if (header)
|
||||
++header;
|
||||
|
||||
@@ -255,7 +439,8 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
||||
|
||||
auto irow = (pos.origin_y + cur_row);
|
||||
auto icol = pos.origin_x;
|
||||
auto dest = (irow * this->m_geometry.pixels_x() + icol);
|
||||
auto dest =
|
||||
(irow * m_ROI_geometries[roi_index].pixels_x() + icol);
|
||||
dest = dest * m_master.bitdepth() / 8;
|
||||
memcpy(frame_buffer + dest,
|
||||
part_buffer +
|
||||
@@ -269,7 +454,17 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
||||
|
||||
std::vector<Frame> RawFile::read_n(size_t n_frames) {
|
||||
// TODO: implement this in a more efficient way
|
||||
if (num_rois() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Multiple ROIs defined in the master "
|
||||
"file. Use "
|
||||
"read_num_rois for a specific ROI or use "
|
||||
"read_ROIs to read one frame after "
|
||||
"the other.");
|
||||
}
|
||||
|
||||
std::vector<Frame> frames;
|
||||
frames.reserve(n_frames);
|
||||
for (size_t i = 0; i < n_frames; i++) {
|
||||
frames.push_back(this->get_frame(m_current_frame));
|
||||
m_current_frame++;
|
||||
@@ -277,11 +472,26 @@ std::vector<Frame> RawFile::read_n(size_t n_frames) {
|
||||
return frames;
|
||||
}
|
||||
|
||||
std::vector<Frame> RawFile::read_n_with_roi(const size_t n_frames,
|
||||
const size_t roi_index) {
|
||||
if (roi_index >= num_rois()) {
|
||||
throw std::runtime_error(LOCATION + "ROI index out of range.");
|
||||
}
|
||||
|
||||
std::vector<Frame> frames;
|
||||
frames.reserve(n_frames);
|
||||
for (size_t i = 0; i < n_frames; i++) {
|
||||
frames.push_back(this->get_frame(m_current_frame, roi_index));
|
||||
m_current_frame++;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
size_t RawFile::frame_number(size_t frame_index) {
|
||||
if (frame_index >= m_master.frames_in_file()) {
|
||||
throw std::runtime_error(LOCATION + " Frame number out of range");
|
||||
}
|
||||
return m_subfiles[0]->frame_number(frame_index);
|
||||
return m_subfiles[0][0]->frame_number(frame_index);
|
||||
}
|
||||
|
||||
} // namespace aare
|
||||
|
||||
@@ -14,7 +14,8 @@ using aare::File;
|
||||
using aare::RawFile;
|
||||
using namespace aare;
|
||||
|
||||
TEST_CASE("Read number of frames from a jungfrau raw file", "[.with-data]") {
|
||||
TEST_CASE("Read number of frames from a jungfrau raw file",
|
||||
"[.with-data][RawFile]") {
|
||||
|
||||
auto fpath =
|
||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||
@@ -24,7 +25,8 @@ TEST_CASE("Read number of frames from a jungfrau raw file", "[.with-data]") {
|
||||
REQUIRE(f.total_frames() == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Read frame numbers from a jungfrau raw file", "[.with-data]") {
|
||||
TEST_CASE("Read frame numbers from a jungfrau raw file",
|
||||
"[.with-data][RawFile]") {
|
||||
auto fpath =
|
||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
@@ -41,7 +43,7 @@ TEST_CASE("Read frame numbers from a jungfrau raw file", "[.with-data]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read a frame number too high throws", "[.with-data]") {
|
||||
TEST_CASE("Read a frame number too high throws", "[.with-data][RawFile]") {
|
||||
auto fpath =
|
||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
@@ -57,7 +59,7 @@ TEST_CASE("Read a frame number too high throws", "[.with-data]") {
|
||||
}
|
||||
|
||||
TEST_CASE("Read a frame numbers where the subfile is missing throws",
|
||||
"[.with-data]") {
|
||||
"[.with-data][RawFile]") {
|
||||
auto fpath = test_data_path() / "raw/jungfrau" /
|
||||
"jungfrau_missing_subfile_master_0.json";
|
||||
|
||||
@@ -80,7 +82,7 @@ TEST_CASE("Read a frame numbers where the subfile is missing throws",
|
||||
}
|
||||
|
||||
TEST_CASE("Read data from a jungfrau 500k single port raw file",
|
||||
"[.with-data]") {
|
||||
"[.with-data][RawFile]") {
|
||||
auto fpath =
|
||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
@@ -99,7 +101,7 @@ TEST_CASE("Read data from a jungfrau 500k single port raw file",
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read frame numbers from a raw file", "[.with-data]") {
|
||||
TEST_CASE("Read frame numbers from a raw file", "[.with-data][RawFile]") {
|
||||
auto fpath =
|
||||
test_data_path() / "raw/eiger" / "eiger_500k_16bit_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
@@ -113,7 +115,8 @@ TEST_CASE("Read frame numbers from a raw file", "[.with-data]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Compare reading from a numpy file with a raw file", "[.with-data]") {
|
||||
TEST_CASE("Compare reading from a numpy file with a raw file",
|
||||
"[.with-data][RawFile]") {
|
||||
|
||||
SECTION("jungfrau data") {
|
||||
auto fpath_raw =
|
||||
@@ -155,6 +158,11 @@ TEST_CASE("Compare reading from a numpy file with a raw file", "[.with-data]") {
|
||||
auto raw_frame = raw.read_frame();
|
||||
|
||||
auto npy_frame = npy.read_frame();
|
||||
CHECK(raw_frame.rows() == 512);
|
||||
CHECK(raw_frame.cols() == 512);
|
||||
CHECK(npy_frame.rows() == 512);
|
||||
CHECK(npy_frame.cols() == 512);
|
||||
|
||||
CHECK((raw_frame.view<uint32_t>() == npy_frame.view<uint32_t>()));
|
||||
}
|
||||
SECTION("eiger data") {
|
||||
@@ -176,7 +184,7 @@ TEST_CASE("Compare reading from a numpy file with a raw file", "[.with-data]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read multipart files", "[.with-data]") {
|
||||
TEST_CASE("Read multipart files", "[.with-data][RawFile]") {
|
||||
auto fpath =
|
||||
test_data_path() / "raw/jungfrau" / "jungfrau_double_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
@@ -217,7 +225,7 @@ struct TestParameters {
|
||||
std::vector<ModuleGeometry> module_geometries{};
|
||||
};
|
||||
|
||||
TEST_CASE("check find_geometry", "[.with-data]") {
|
||||
TEST_CASE("check find_geometry", "[.with-data][RawFile]") {
|
||||
|
||||
auto test_parameters = GENERATE(
|
||||
TestParameters{"raw/jungfrau_2modules_version6.1.2/run_master_0.raw", 2,
|
||||
@@ -290,7 +298,8 @@ TEST_CASE("check find_geometry", "[.with-data]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Open multi module file with ROI", "[.with-data]") {
|
||||
TEST_CASE("Open multi module file with ROI",
|
||||
"[.with-data][read_rois][RawFile]") {
|
||||
|
||||
auto fpath =
|
||||
test_data_path() / "raw/ROITestData/SingleChipROI/Data_master_0.json";
|
||||
@@ -304,7 +313,8 @@ TEST_CASE("Open multi module file with ROI", "[.with-data]") {
|
||||
|
||||
CHECK(f.n_modules() == 2);
|
||||
|
||||
CHECK(f.n_modules_in_roi() == 1);
|
||||
REQUIRE(f.n_modules_in_roi().size() == 1);
|
||||
CHECK(f.n_modules_in_roi()[0] == 1);
|
||||
|
||||
auto frames = f.read_n(2);
|
||||
|
||||
@@ -315,7 +325,70 @@ TEST_CASE("Open multi module file with ROI", "[.with-data]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read file with unordered frames", "[.with-data]") {
|
||||
TEST_CASE("Open multi module file with ROI spanning over multiple modules",
|
||||
"[.width-data][read_rois][RawFile]") {
|
||||
|
||||
auto fpath =
|
||||
test_data_path() / "raw/ROITestData/MultipleChipROI/run_master_2.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
|
||||
RawFile f(fpath, "r");
|
||||
|
||||
CHECK(f.n_modules() == 2);
|
||||
CHECK(f.n_modules_in_roi().size() == 1);
|
||||
CHECK(f.n_modules_in_roi()[0] == 2);
|
||||
|
||||
auto frame = f.read_frame();
|
||||
|
||||
CHECK(frame.rows() == 301);
|
||||
CHECK(frame.cols() == 101);
|
||||
|
||||
CHECK(f.rows() == 301);
|
||||
CHECK(f.cols() == 101);
|
||||
}
|
||||
|
||||
TEST_CASE("Open multi module file with two ROIs",
|
||||
"[.width-data][read_rois][RawFile]") {
|
||||
|
||||
auto fpath =
|
||||
test_data_path() / "raw/ROITestData/MultipleROIs/run_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
|
||||
RawFile f(fpath, "r");
|
||||
|
||||
CHECK(f.n_modules() == 2);
|
||||
REQUIRE(f.n_modules_in_roi().size() == 2);
|
||||
CHECK(f.n_modules_in_roi()[0] == 1);
|
||||
CHECK(f.n_modules_in_roi()[1] == 1);
|
||||
|
||||
CHECK_THROWS(f.read_frame());
|
||||
|
||||
CHECK(f.tell() == 0);
|
||||
|
||||
auto frame = f.read_rois();
|
||||
|
||||
CHECK(f.tell() == 1);
|
||||
|
||||
REQUIRE(frame.size() == 2);
|
||||
|
||||
CHECK(frame[0].rows() == 301);
|
||||
CHECK(frame[0].cols() == 101);
|
||||
CHECK(frame[1].rows() == 101);
|
||||
CHECK(frame[1].cols() == 101);
|
||||
|
||||
CHECK_THROWS(f.rows());
|
||||
CHECK(f.rows(0) == 301);
|
||||
|
||||
auto frames = f.read_n_with_roi(2, 1);
|
||||
REQUIRE(frames.size() == 2);
|
||||
CHECK(f.tell() == 3);
|
||||
for (const auto &frm : frames) {
|
||||
CHECK(frm.rows() == 101);
|
||||
CHECK(frm.cols() == 101);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read file with unordered frames", "[.with-data][RawFile]") {
|
||||
// TODO! Better explanation and error message
|
||||
auto fpath = test_data_path() / "raw/mythen/scan242_master_3.raw";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
@@ -323,7 +396,7 @@ TEST_CASE("Read file with unordered frames", "[.with-data]") {
|
||||
REQUIRE_THROWS((f.read_frame()));
|
||||
}
|
||||
|
||||
TEST_CASE("Read Mythenframe", "[.with-data]") {
|
||||
TEST_CASE("Read Mythenframe", "[.with-data][RawFile]") {
|
||||
auto fpath = test_data_path() / "raw/newmythen03/run_2_master_1.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
RawFile f(fpath);
|
||||
|
||||
@@ -71,7 +71,7 @@ ScanParameters::ScanParameters(const bool enabled, const DACIndex dac,
|
||||
const int start, const int stop, const int step,
|
||||
const int64_t settleTime)
|
||||
: m_enabled(enabled), m_dac(dac), m_start(start), m_stop(stop),
|
||||
m_step(step), m_settleTime(settleTime) {};
|
||||
m_step(step), m_settleTime(settleTime){};
|
||||
|
||||
// "[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]"
|
||||
ScanParameters::ScanParameters(const std::string &par) {
|
||||
@@ -193,7 +193,18 @@ ScanParameters RawMasterFile::scan_parameters() const {
|
||||
return m_scan_parameters;
|
||||
}
|
||||
|
||||
std::optional<ROI> RawMasterFile::roi() const { return m_roi; }
|
||||
std::optional<ROI> RawMasterFile::roi() const {
|
||||
if (m_rois.value().size() > 1) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Multiple ROIs present, use rois() method.");
|
||||
} else {
|
||||
return m_rois.has_value()
|
||||
? std::optional<ROI>(m_rois.value().at(0))
|
||||
: std::nullopt; // TODO: maybe throw if no roi exists
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::vector<ROI>> RawMasterFile::rois() const { return m_rois; }
|
||||
|
||||
void RawMasterFile::parse_json(std::istream &is) {
|
||||
json j;
|
||||
@@ -255,9 +266,9 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
m_frame_discard_policy = string_to<FrameDiscardPolicy>(
|
||||
j["Frame Discard Policy"].get<std::string>());
|
||||
|
||||
if(j.contains("Number of rows") && j["Number of rows"].is_number()){
|
||||
if (j.contains("Number of rows") && j["Number of rows"].is_number()) {
|
||||
m_number_of_rows = j["Number of rows"];
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Special treatment of analog flag because of Moench03
|
||||
@@ -338,34 +349,35 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
ROI tmp_roi;
|
||||
if (v < 8.0) {
|
||||
auto obj = j.at("Receiver Roi");
|
||||
tmp_roi.xmin = obj.at("xmin");
|
||||
tmp_roi.xmax = obj.at("xmax");
|
||||
tmp_roi.ymin = obj.at("ymin");
|
||||
tmp_roi.ymax = obj.at("ymax");
|
||||
} else {
|
||||
// TODO: for now only handle single ROI
|
||||
auto obj = j.at("Receiver Rois");
|
||||
tmp_roi.xmin = obj[0].at("xmin");
|
||||
tmp_roi.xmax = obj[0].at("xmax");
|
||||
tmp_roi.ymin = obj[0].at("ymin");
|
||||
tmp_roi.ymax = obj[0].at("ymax");
|
||||
}
|
||||
|
||||
// if any of the values are set update the roi
|
||||
// TODO: doesnt it write garbage if one of them is not set
|
||||
if (tmp_roi.xmin != 4294967295 || tmp_roi.xmax != 4294967295 ||
|
||||
tmp_roi.ymin != 4294967295 || tmp_roi.ymax != 4294967295) {
|
||||
tmp_roi.xmax++;
|
||||
// Handle Mythen
|
||||
if (tmp_roi.ymin == -1 && tmp_roi.ymax == -1) {
|
||||
tmp_roi.ymin = 0;
|
||||
tmp_roi.ymax = 0;
|
||||
if (obj.at("xmin") != 4294967295 || obj.at("xmax") != 4294967295 ||
|
||||
obj.at("ymin") != 4294967295 || obj.at("ymax") != 4294967295) {
|
||||
// Handle Mythen
|
||||
if (obj.at("ymin") == -1 && obj.at("ymax") == -1) {
|
||||
obj.at("ymin") = 0;
|
||||
obj.at("ymax") = 0;
|
||||
}
|
||||
m_rois.emplace();
|
||||
m_rois.value().push_back(ROI{
|
||||
obj.at("xmin"), static_cast<ssize_t>(obj.at("xmax")) + 1,
|
||||
obj.at("ymin"), static_cast<ssize_t>(obj.at("ymax")) + 1});
|
||||
}
|
||||
} else {
|
||||
auto obj = j.at("Receiver Rois");
|
||||
m_rois.emplace();
|
||||
for (auto &elem : obj) {
|
||||
// handle Mythen
|
||||
if (elem.at("ymin") == -1 && elem.at("ymax") == -1) {
|
||||
elem.at("ymin") = 0;
|
||||
elem.at("ymax") = 0;
|
||||
}
|
||||
|
||||
m_rois.value().push_back(ROI{
|
||||
elem.at("xmin"), static_cast<ssize_t>(elem.at("xmax")) + 1,
|
||||
elem.at("ymin"),
|
||||
static_cast<ssize_t>(elem.at("ymax")) + 1});
|
||||
}
|
||||
tmp_roi.ymax++;
|
||||
m_roi = tmp_roi;
|
||||
}
|
||||
|
||||
} catch (const json::out_of_range &e) {
|
||||
@@ -379,7 +391,6 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
m_counter_mask =
|
||||
std::stoi(j["Counter Mask"].get<std::string>(), nullptr, 16);
|
||||
}
|
||||
|
||||
|
||||
// Update detector type for Moench
|
||||
// TODO! How does this work with old .raw master files?
|
||||
|
||||
Reference in New Issue
Block a user