mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-02-19 20:18:42 +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:
@@ -352,6 +352,7 @@ set(PUBLICHEADERS
|
|||||||
include/aare/FilePtr.hpp
|
include/aare/FilePtr.hpp
|
||||||
include/aare/Frame.hpp
|
include/aare/Frame.hpp
|
||||||
include/aare/GainMap.hpp
|
include/aare/GainMap.hpp
|
||||||
|
include/aare/ROIGeometry.hpp
|
||||||
include/aare/DetectorGeometry.hpp
|
include/aare/DetectorGeometry.hpp
|
||||||
include/aare/JungfrauDataFile.hpp
|
include/aare/JungfrauDataFile.hpp
|
||||||
include/aare/logger.hpp
|
include/aare/logger.hpp
|
||||||
@@ -374,6 +375,7 @@ set(SourceFiles
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/CtbRawFile.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/CtbRawFile.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/defs.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/defs.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/ROIGeometry.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/DetectorGeometry.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/DetectorGeometry.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/File.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/File.cpp
|
||||||
|
|||||||
@@ -12,6 +12,10 @@
|
|||||||
- Removed redundant arr.value(ix,iy...) on NDArray use arr(ix,iy...)
|
- Removed redundant arr.value(ix,iy...) on NDArray use arr(ix,iy...)
|
||||||
- Removed Print/Print_some/Print_all form NDArray (operator << still works)
|
- Removed Print/Print_some/Print_all form NDArray (operator << still works)
|
||||||
- Added const* version of .data()
|
- Added const* version of .data()
|
||||||
|
- reading multiple ROI's supported for aare.
|
||||||
|
- Use ``read_roi/rois`` to read multiple ROIs for one frame, the index of a specific ROI to only read that ROI
|
||||||
|
- Use ``read_n_with_roi`` to read multiple frames for a specific ROI.
|
||||||
|
- Note ``read_frame`` and ``read_n`` is not supported for multiple ROI's.
|
||||||
|
|
||||||
### Bugfixes:
|
### Bugfixes:
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "aare/ROIGeometry.hpp"
|
||||||
#include "aare/RawMasterFile.hpp" //ROI refactor away
|
#include "aare/RawMasterFile.hpp" //ROI refactor away
|
||||||
#include "aare/defs.hpp"
|
#include "aare/defs.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace aare {
|
namespace aare {
|
||||||
|
|
||||||
struct ModuleConfig {
|
struct ModuleConfig {
|
||||||
@@ -18,16 +21,69 @@ struct ModuleConfig {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class to hold the geometry of a module. Where pixel 0 is located and
|
* @brief Class to hold the geometry of a module. Where pixel 0 is located
|
||||||
* the size of the module
|
* relative to full Detector/ROI and the size of the module e.g. size of ROI
|
||||||
|
* occupied by the module
|
||||||
*/
|
*/
|
||||||
struct ModuleGeometry {
|
struct ModuleGeometry {
|
||||||
|
/// @brief start x coordinate of the module in the full detector/ROI
|
||||||
int origin_x{};
|
int origin_x{};
|
||||||
|
/// @brief start y coordinate of the module in the full detector/ROI
|
||||||
int origin_y{};
|
int origin_y{};
|
||||||
|
/// @brief height of the module in pixels
|
||||||
int height{};
|
int height{};
|
||||||
|
/// @brief width of the module in pixels
|
||||||
int width{};
|
int width{};
|
||||||
|
/// @brief module index of the module in the detector
|
||||||
int row_index{};
|
int row_index{};
|
||||||
|
/// @brief module index of the module in the detector
|
||||||
int col_index{};
|
int col_index{};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief checks if module is in the region of interest
|
||||||
|
*/
|
||||||
|
bool module_in_roi(const ROI &roi) {
|
||||||
|
// module is to the left of the roi
|
||||||
|
bool to_the_left = origin_x + width - 1 < roi.xmin;
|
||||||
|
bool to_the_right = origin_x >= roi.xmax;
|
||||||
|
bool above = origin_y + height - 1 < roi.ymin;
|
||||||
|
bool below = origin_y >= roi.ymax;
|
||||||
|
|
||||||
|
return !(to_the_left || to_the_right || below || above);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the module geometry given a region of interest
|
||||||
|
*/
|
||||||
|
void update_geometry_with_roi(const ROI &roi) {
|
||||||
|
|
||||||
|
if (!(module_in_roi(roi))) {
|
||||||
|
return; // do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_width = std::min(origin_x + width, static_cast<int>(roi.xmax)) -
|
||||||
|
std::max(origin_x, static_cast<int>(roi.xmin));
|
||||||
|
|
||||||
|
// ROI starts inside module
|
||||||
|
if (roi.xmin >= origin_x && roi.xmin < origin_x + width) {
|
||||||
|
origin_x = 0;
|
||||||
|
} else {
|
||||||
|
origin_x -= roi.xmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_height =
|
||||||
|
std::min(origin_y + height, static_cast<int>(roi.ymax)) -
|
||||||
|
std::max(origin_y, static_cast<int>(roi.ymin));
|
||||||
|
|
||||||
|
if (roi.ymin >= origin_y && roi.ymin < origin_y + height) {
|
||||||
|
origin_y = 0;
|
||||||
|
} else {
|
||||||
|
origin_y -= roi.ymin;
|
||||||
|
}
|
||||||
|
|
||||||
|
height = new_height;
|
||||||
|
width = new_width;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,34 +105,33 @@ class DetectorGeometry {
|
|||||||
* @param roi
|
* @param roi
|
||||||
* @return DetectorGeometry
|
* @return DetectorGeometry
|
||||||
*/
|
*/
|
||||||
void update_geometry_with_roi(ROI roi);
|
|
||||||
|
|
||||||
size_t n_modules() const;
|
size_t n_modules() const;
|
||||||
|
|
||||||
size_t n_modules_in_roi() const;
|
|
||||||
|
|
||||||
size_t pixels_x() const;
|
size_t pixels_x() const;
|
||||||
size_t pixels_y() const;
|
size_t pixels_y() const;
|
||||||
|
|
||||||
size_t modules_x() const;
|
size_t modules_x() const;
|
||||||
size_t modules_y() const;
|
size_t modules_y() const;
|
||||||
|
|
||||||
const std::vector<ssize_t> &get_modules_in_roi() const;
|
|
||||||
|
|
||||||
ssize_t get_modules_in_roi(const size_t index) const;
|
|
||||||
|
|
||||||
const std::vector<ModuleGeometry> &get_module_geometries() const;
|
const std::vector<ModuleGeometry> &get_module_geometries() const;
|
||||||
|
|
||||||
const ModuleGeometry &get_module_geometries(const size_t index) const;
|
const ModuleGeometry &get_module_geometries(const size_t index) const;
|
||||||
|
|
||||||
|
ModuleGeometry &get_module_geometries(const size_t index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_modules_x{};
|
size_t m_modules_x{};
|
||||||
size_t m_modules_y{};
|
size_t m_modules_y{};
|
||||||
size_t m_pixels_x{};
|
size_t m_pixels_x{};
|
||||||
size_t m_pixels_y{};
|
size_t m_pixels_y{};
|
||||||
static constexpr ModuleConfig cfg{0, 0};
|
static constexpr ModuleConfig cfg{0, 0};
|
||||||
std::vector<ModuleGeometry> module_geometries{};
|
|
||||||
std::vector<ssize_t> modules_in_roi{};
|
// TODO: maybe remove - should be a member in ROIGeometry - in particular
|
||||||
|
// only works as no overlap between ROIs allowed? maybe just have another
|
||||||
|
// additional vector of ModuleGeometry for each ROIGeometry - some
|
||||||
|
// duplication but nicer design?
|
||||||
|
std::vector<ModuleGeometry> module_geometries;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aare
|
} // namespace aare
|
||||||
48
include/aare/ROIGeometry.hpp
Normal file
48
include/aare/ROIGeometry.hpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "aare/DetectorGeometry.hpp"
|
||||||
|
#include "aare/defs.hpp"
|
||||||
|
|
||||||
|
namespace aare {
|
||||||
|
|
||||||
|
class DetectorGeometry; // forward declaration to avoid circular dependency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class to hold the geometry of a region of interest (ROI)
|
||||||
|
*/
|
||||||
|
class ROIGeometry {
|
||||||
|
public:
|
||||||
|
/** @brief Constructor
|
||||||
|
* @param roi
|
||||||
|
* @param geometry general detector geometry
|
||||||
|
*/
|
||||||
|
ROIGeometry(const ROI &roi, DetectorGeometry &geometry);
|
||||||
|
|
||||||
|
/** @brief Constructor for ROI geometry expanding over full detector
|
||||||
|
* @param geometry general detector geometry
|
||||||
|
*/
|
||||||
|
ROIGeometry(DetectorGeometry &geometry);
|
||||||
|
|
||||||
|
/// @brief Get number of modules in the ROI
|
||||||
|
size_t num_modules_in_roi() const;
|
||||||
|
|
||||||
|
/// @brief Get the indices of modules in the ROI
|
||||||
|
const std::vector<size_t> &module_indices_in_roi() const;
|
||||||
|
|
||||||
|
size_t module_indices_in_roi(const size_t module_index) const;
|
||||||
|
|
||||||
|
size_t pixels_x() const;
|
||||||
|
size_t pixels_y() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief Size of the ROI in pixels in x direction
|
||||||
|
size_t m_pixels_x{};
|
||||||
|
/// @brief Size of the ROI in pixels in y direction
|
||||||
|
size_t m_pixels_y{};
|
||||||
|
|
||||||
|
DetectorGeometry &m_geometry;
|
||||||
|
|
||||||
|
/// @brief Indices of modules included in the ROI
|
||||||
|
std::vector<size_t> m_module_indices_in_roi;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aare
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "aare/FileInterface.hpp"
|
#include "aare/FileInterface.hpp"
|
||||||
#include "aare/Frame.hpp"
|
#include "aare/Frame.hpp"
|
||||||
#include "aare/NDArray.hpp" //for pixel map
|
#include "aare/NDArray.hpp" //for pixel map
|
||||||
|
#include "aare/ROIGeometry.hpp"
|
||||||
#include "aare/RawMasterFile.hpp"
|
#include "aare/RawMasterFile.hpp"
|
||||||
#include "aare/RawSubFile.hpp"
|
#include "aare/RawSubFile.hpp"
|
||||||
|
|
||||||
@@ -23,13 +24,17 @@ namespace aare {
|
|||||||
*/
|
*/
|
||||||
class RawFile : public FileInterface {
|
class RawFile : public FileInterface {
|
||||||
|
|
||||||
std::vector<std::unique_ptr<RawSubFile>> m_subfiles;
|
std::vector<std::vector<std::unique_ptr<RawSubFile>>>
|
||||||
|
m_subfiles; // [ROI][modules_per_ROI]
|
||||||
|
|
||||||
RawMasterFile m_master;
|
RawMasterFile m_master;
|
||||||
size_t m_current_frame{};
|
size_t m_current_frame{};
|
||||||
|
|
||||||
DetectorGeometry m_geometry;
|
DetectorGeometry m_geometry;
|
||||||
|
|
||||||
|
/// @brief Geometries e.g. number of modules, size etc. for each ROI
|
||||||
|
std::vector<ROIGeometry> m_ROI_geometries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief RawFile constructor
|
* @brief RawFile constructor
|
||||||
@@ -43,26 +48,94 @@ class RawFile : public FileInterface {
|
|||||||
Frame read_frame() override;
|
Frame read_frame() override;
|
||||||
Frame read_frame(size_t frame_number) override;
|
Frame read_frame(size_t frame_number) override;
|
||||||
std::vector<Frame> read_n(size_t n_frames) override;
|
std::vector<Frame> read_n(size_t n_frames) override;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read one ROI defined in the master file
|
||||||
|
* @param roi_index index of the ROI to read
|
||||||
|
* @return Frame
|
||||||
|
* @note the frame index is incremented after calling this function so
|
||||||
|
* reading rois one after the other wont work.
|
||||||
|
*/
|
||||||
|
Frame read_roi(const size_t roi_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read all ROIs defined in the master file
|
||||||
|
* @return vector of Frames (one Frame per ROI)
|
||||||
|
*/
|
||||||
|
std::vector<Frame>read_rois();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read n frames for the given ROI index
|
||||||
|
* @param n_frames number of frames to read
|
||||||
|
* @param roi_index index of the ROI to read
|
||||||
|
* @return vector of Frames
|
||||||
|
*/
|
||||||
|
std::vector<Frame> read_n_with_roi(const size_t n_frames,
|
||||||
|
const size_t roi_index);
|
||||||
|
|
||||||
void read_into(std::byte *image_buf) override;
|
void read_into(std::byte *image_buf) override;
|
||||||
void read_into(std::byte *image_buf, size_t n_frames) override;
|
void read_into(std::byte *image_buf, size_t n_frames) override;
|
||||||
|
|
||||||
// TODO! do we need to adapt the API?
|
// TODO! do we need to adapt the API?
|
||||||
void read_into(std::byte *image_buf, DetectorHeader *header);
|
void read_into(std::byte *image_buf, DetectorHeader *header = nullptr);
|
||||||
void read_into(std::byte *image_buf, size_t n_frames,
|
void read_into(std::byte *image_buf, size_t n_frames,
|
||||||
DetectorHeader *header);
|
DetectorHeader *header);
|
||||||
|
|
||||||
|
void read_roi_into(std::byte *image_buf, const size_t roi_index,
|
||||||
|
const size_t frame_number,
|
||||||
|
DetectorHeader *header =
|
||||||
|
nullptr); // maybe just make get_frame_into public
|
||||||
|
|
||||||
size_t frame_number(size_t frame_index) override;
|
size_t frame_number(size_t frame_index) override;
|
||||||
size_t bytes_per_frame() override;
|
size_t bytes_per_frame() override;
|
||||||
|
// TODO: mmh maybe also pass roi_index in Base class File. Leave it unused
|
||||||
|
// for NumpyFile and JungfrauDataFile
|
||||||
|
/**
|
||||||
|
* @brief bytes per frame for the given ROI
|
||||||
|
* @param roi_index index of the ROI
|
||||||
|
*/
|
||||||
|
size_t bytes_per_frame(const size_t roi_index);
|
||||||
size_t pixels_per_frame() override;
|
size_t pixels_per_frame() override;
|
||||||
|
/**
|
||||||
|
* @brief pixels per frame for the given ROI
|
||||||
|
* @param roi_index index of the ROI
|
||||||
|
*/
|
||||||
|
size_t pixels_per_frame(const size_t roi_index);
|
||||||
size_t bytes_per_pixel() const;
|
size_t bytes_per_pixel() const;
|
||||||
void seek(size_t frame_index) override;
|
void seek(size_t frame_index) override;
|
||||||
size_t tell() override;
|
size_t tell() override;
|
||||||
size_t total_frames() const override;
|
size_t total_frames() const override;
|
||||||
size_t rows() const override;
|
size_t rows() const override;
|
||||||
|
/**
|
||||||
|
* @brief rows for the given ROI
|
||||||
|
* @param roi_index index of the ROI
|
||||||
|
*/
|
||||||
|
size_t rows(const size_t roi_index) const;
|
||||||
size_t cols() const override;
|
size_t cols() const override;
|
||||||
|
/**
|
||||||
|
* @brief cols for the given ROI
|
||||||
|
* @param roi_index index of the ROI
|
||||||
|
*/
|
||||||
|
size_t cols(const size_t roi_index) const;
|
||||||
size_t bitdepth() const override;
|
size_t bitdepth() const override;
|
||||||
size_t n_modules() const;
|
size_t n_modules() const;
|
||||||
size_t n_modules_in_roi() const;
|
|
||||||
|
/**
|
||||||
|
* @brief number of ROIs defined
|
||||||
|
*/
|
||||||
|
size_t num_rois() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the ROI geometry for the given ROI index
|
||||||
|
* @param roi_index index of the ROI
|
||||||
|
*/
|
||||||
|
const ROIGeometry &roi_geometries(size_t roi_index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief number of modules in each ROI
|
||||||
|
*/
|
||||||
|
std::vector<size_t> n_modules_in_roi() const;
|
||||||
xy geometry() const;
|
xy geometry() const;
|
||||||
|
|
||||||
RawMasterFile master() const;
|
RawMasterFile master() const;
|
||||||
@@ -79,21 +152,23 @@ class RawFile : public FileInterface {
|
|||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief read the frame at the given frame index into the image buffer
|
* @brief read the frame at the given frame index into the image buffer
|
||||||
* @param frame_number frame number to read
|
* @param frame_index frame number to read
|
||||||
* @param image_buf buffer to store the frame
|
* @param frame_buffer buffer to store the frame
|
||||||
|
* @param roi_index index of the ROI to read (default is 0 e.g. full frame)
|
||||||
*/
|
*/
|
||||||
|
void get_frame_into(
|
||||||
void get_frame_into(size_t frame_index, std::byte *frame_buffer,
|
size_t frame_index, std::byte *frame_buffer, const size_t roi_index = 0,
|
||||||
DetectorHeader *header = nullptr);
|
DetectorHeader *header = nullptr); // TODO read_into updates it!!!!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get the frame at the given frame index
|
* @brief get the frame at the given frame index
|
||||||
* @param frame_number frame number to read
|
* @param frame_number frame number to read
|
||||||
|
* @param roi_index index of the ROI to read (default is 0 e.g. full frame)
|
||||||
* @return Frame
|
* @return Frame
|
||||||
*/
|
*/
|
||||||
Frame get_frame(size_t frame_index);
|
Frame get_frame(size_t frame_index, const size_t roi_index = 0);
|
||||||
|
|
||||||
void open_subfiles();
|
void open_subfiles(const size_t roi_index);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aare
|
} // namespace aare
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "aare/defs.hpp"
|
#include "aare/defs.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
@@ -109,7 +109,7 @@ class RawMasterFile {
|
|||||||
std::optional<size_t> m_number_of_rows;
|
std::optional<size_t> m_number_of_rows;
|
||||||
std::optional<uint8_t> m_counter_mask;
|
std::optional<uint8_t> m_counter_mask;
|
||||||
|
|
||||||
std::optional<ROI> m_roi;
|
std::optional<std::vector<ROI>> m_rois;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RawMasterFile(const std::filesystem::path &fpath);
|
RawMasterFile(const std::filesystem::path &fpath);
|
||||||
@@ -141,11 +141,15 @@ class RawMasterFile {
|
|||||||
std::optional<size_t> number_of_rows() const;
|
std::optional<size_t> number_of_rows() const;
|
||||||
std::optional<uint8_t> counter_mask() const;
|
std::optional<uint8_t> counter_mask() const;
|
||||||
|
|
||||||
|
std::optional<std::vector<ROI>> rois() const;
|
||||||
|
|
||||||
std::optional<ROI> roi() const;
|
std::optional<ROI> roi() const;
|
||||||
|
|
||||||
ScanParameters scan_parameters() const;
|
ScanParameters scan_parameters() const;
|
||||||
|
|
||||||
std::optional<std::chrono::nanoseconds> exptime() const { return m_exptime; }
|
std::optional<std::chrono::nanoseconds> exptime() const {
|
||||||
|
return m_exptime;
|
||||||
|
}
|
||||||
std::chrono::nanoseconds period() const { return m_period; }
|
std::chrono::nanoseconds period() const { return m_period; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
311
python/src/bind_RawFile.hpp
Normal file
311
python/src/bind_RawFile.hpp
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
#include "aare/CtbRawFile.hpp"
|
||||||
|
#include "aare/File.hpp"
|
||||||
|
#include "aare/Frame.hpp"
|
||||||
|
#include "aare/RawFile.hpp"
|
||||||
|
#include "aare/RawMasterFile.hpp"
|
||||||
|
#include "aare/RawSubFile.hpp"
|
||||||
|
|
||||||
|
#include "aare/defs.hpp"
|
||||||
|
#include "np_helper.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <pybind11/iostream.h>
|
||||||
|
#include <pybind11/numpy.h>
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/stl.h>
|
||||||
|
#include <pybind11/stl/filesystem.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
using namespace ::aare;
|
||||||
|
|
||||||
|
void define_raw_file_io_bindings(py::module &m) {
|
||||||
|
py::class_<RawFile>(m, "RawFile")
|
||||||
|
.def(py::init<const std::filesystem::path &>())
|
||||||
|
.def("read_frame",
|
||||||
|
[](RawFile &self) {
|
||||||
|
if (self.n_modules_in_roi().size() > 1) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"File contains multiple ROIs - use read_ROIs()");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> shape;
|
||||||
|
shape.reserve(2);
|
||||||
|
shape.push_back(self.rows());
|
||||||
|
shape.push_back(self.cols());
|
||||||
|
|
||||||
|
// return headers from all subfiles
|
||||||
|
py::array_t<DetectorHeader> header(self.n_modules());
|
||||||
|
|
||||||
|
py::array image = allocate_image_data(self.bytes_per_pixel(), shape);
|
||||||
|
self.read_into(
|
||||||
|
reinterpret_cast<std::byte *>(image.mutable_data()),
|
||||||
|
header.mutable_data());
|
||||||
|
|
||||||
|
return py::make_tuple(header, image);
|
||||||
|
})
|
||||||
|
.def(
|
||||||
|
"read_n",
|
||||||
|
[](RawFile &self, size_t n_frames) {
|
||||||
|
if (self.n_modules_in_roi().size() > 1) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"File contains multiple ROIs - use read_n_ROIs() to "
|
||||||
|
"read a specific ROI or use read_ROIs and "
|
||||||
|
"read one frame at a time.");
|
||||||
|
}
|
||||||
|
// adjust for actual frames left in the file
|
||||||
|
n_frames =
|
||||||
|
std::min(n_frames, self.total_frames() - self.tell());
|
||||||
|
if (n_frames == 0) {
|
||||||
|
throw std::runtime_error("No frames left in file");
|
||||||
|
}
|
||||||
|
std::vector<size_t> shape{n_frames, self.rows(), self.cols()};
|
||||||
|
|
||||||
|
// return headers from all subfiles
|
||||||
|
py::array_t<DetectorHeader> header;
|
||||||
|
if (self.n_modules() == 1) {
|
||||||
|
header = py::array_t<DetectorHeader>(n_frames);
|
||||||
|
} else {
|
||||||
|
header = py::array_t<DetectorHeader>(
|
||||||
|
{self.n_modules_in_roi()[0], n_frames});
|
||||||
|
}
|
||||||
|
|
||||||
|
py::array images = allocate_image_data(self.bytes_per_pixel(), shape);
|
||||||
|
self.read_into(
|
||||||
|
reinterpret_cast<std::byte *>(images.mutable_data()),
|
||||||
|
n_frames, header.mutable_data());
|
||||||
|
|
||||||
|
return py::make_tuple(header, images);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Read n frames from the file.
|
||||||
|
)")
|
||||||
|
|
||||||
|
.def(
|
||||||
|
"read_roi",
|
||||||
|
[](RawFile &self,
|
||||||
|
const size_t roi_index) {
|
||||||
|
if (self.num_rois() == 0) {
|
||||||
|
throw std::runtime_error(LOCATION + "No ROIs defined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( roi_index >= self.num_rois()) {
|
||||||
|
throw std::runtime_error(LOCATION +
|
||||||
|
"ROI index out of range.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// return headers from all subfiles
|
||||||
|
py::array_t<DetectorHeader> header(self.n_modules_in_roi()[roi_index]);
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<size_t> shape;
|
||||||
|
shape.reserve(2);
|
||||||
|
shape.push_back(self.roi_geometries(roi_index).pixels_y());
|
||||||
|
shape.push_back(self.roi_geometries(roi_index).pixels_x());
|
||||||
|
|
||||||
|
py::array image = allocate_image_data(self.bytes_per_pixel(), shape);
|
||||||
|
|
||||||
|
|
||||||
|
self.read_roi_into(
|
||||||
|
reinterpret_cast<std::byte *>(image.mutable_data()),
|
||||||
|
roi_index, self.tell(), header.mutable_data());
|
||||||
|
|
||||||
|
self.seek(self.tell() + 1); // advance frame number so the
|
||||||
|
return py::make_tuple(header, image);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Read one ROI from the current frame.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
|
||||||
|
roi_index : int
|
||||||
|
Index of the ROI to read.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
|
||||||
|
The method advances the frame number, so reading ROIs one after the other won't work.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
tuple (header, image)
|
||||||
|
)",
|
||||||
|
py::arg("roi_index"))
|
||||||
|
|
||||||
|
.def(
|
||||||
|
"read_rois",
|
||||||
|
[](RawFile &self) {
|
||||||
|
if (self.num_rois() == 0) {
|
||||||
|
throw std::runtime_error(LOCATION + "No ROIs defined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t number_of_ROIs = self.num_rois();
|
||||||
|
|
||||||
|
// const uint8_t item_size = self.bytes_per_pixel();
|
||||||
|
|
||||||
|
std::vector<py::array> images(number_of_ROIs);
|
||||||
|
|
||||||
|
// return headers from all subfiles
|
||||||
|
std::vector<py::array_t<DetectorHeader>> headers(number_of_ROIs);
|
||||||
|
for (size_t r = 0; r < number_of_ROIs; r++) {
|
||||||
|
headers[r] =
|
||||||
|
py::array_t<DetectorHeader>(self.n_modules_in_roi()[r]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t r = 0; r < number_of_ROIs; r++) {
|
||||||
|
std::vector<size_t> shape;
|
||||||
|
shape.reserve(2);
|
||||||
|
shape.push_back(self.roi_geometries(r).pixels_y());
|
||||||
|
shape.push_back(self.roi_geometries(r).pixels_x());
|
||||||
|
|
||||||
|
images[r] = allocate_image_data(self.bytes_per_pixel(), shape);
|
||||||
|
|
||||||
|
self.read_roi_into(
|
||||||
|
reinterpret_cast<std::byte *>(images[r].mutable_data()),
|
||||||
|
r, self.tell(),headers[r].mutable_data());
|
||||||
|
}
|
||||||
|
self.seek(self.tell() + 1); // advance frame number so the
|
||||||
|
return py::make_tuple(headers, images);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Read all ROIs for specific frame.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
|
||||||
|
frame_number : int
|
||||||
|
Frame number to read.
|
||||||
|
|
||||||
|
roi_index : Optional[int]
|
||||||
|
Index of the ROI to read. If not provided, all ROIs are read.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
list of numpy.ndarray
|
||||||
|
One array per ROI.)")
|
||||||
|
|
||||||
|
.def(
|
||||||
|
"read_n_with_roi",
|
||||||
|
[](RawFile &self, const size_t num_frames, const size_t roi_index) {
|
||||||
|
if (self.num_rois() == 0) {
|
||||||
|
throw std::runtime_error(LOCATION + "No ROIs defined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roi_index >= self.num_rois()) {
|
||||||
|
throw std::runtime_error(LOCATION +
|
||||||
|
"ROI index out of range.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust for actual frames left in the file
|
||||||
|
size_t n_frames =
|
||||||
|
std::min(num_frames, self.total_frames() - self.tell());
|
||||||
|
if (n_frames == 0) {
|
||||||
|
throw std::runtime_error("No frames left in file");
|
||||||
|
}
|
||||||
|
std::vector<size_t> shape{
|
||||||
|
n_frames, self.roi_geometries(roi_index).pixels_y(),
|
||||||
|
self.roi_geometries(roi_index).pixels_x()};
|
||||||
|
|
||||||
|
// return headers from all subfiles
|
||||||
|
auto n_mod = self.n_modules_in_roi()[roi_index];
|
||||||
|
py::array_t<DetectorHeader> header({
|
||||||
|
n_frames, n_mod}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
py::array images = allocate_image_data(self.bytes_per_pixel(), shape);
|
||||||
|
|
||||||
|
auto image_buffer =
|
||||||
|
reinterpret_cast<std::byte *>(images.mutable_data());
|
||||||
|
auto h = header.mutable_data();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n_frames; i++) {
|
||||||
|
self.read_roi_into(image_buffer, roi_index, self.tell(), h);
|
||||||
|
|
||||||
|
self.seek(self.tell() + 1); // advance frame number
|
||||||
|
image_buffer += self.bytes_per_frame(roi_index);
|
||||||
|
h += n_mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return py::make_tuple(header, images);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Read n frames for a specific ROI
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
|
||||||
|
num_frames : int
|
||||||
|
Number of frames to read.
|
||||||
|
roi_index : int
|
||||||
|
Index of the ROI to read.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
three dimensional numpy.ndarray.)",
|
||||||
|
py::arg("num_frames"), py::kw_only(), py::arg("roi_index"))
|
||||||
|
|
||||||
|
.def("frame_number", &RawFile::frame_number)
|
||||||
|
.def("bytes_per_frame",
|
||||||
|
static_cast<size_t (RawFile::*)()>(&RawFile::bytes_per_frame))
|
||||||
|
.def(
|
||||||
|
"bytes_per_frame",
|
||||||
|
[](RawFile &self, const size_t roi_index) {
|
||||||
|
return self.bytes_per_frame(roi_index);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Bytes per frame for the given ROI.
|
||||||
|
)")
|
||||||
|
.def("pixels_per_frame",
|
||||||
|
static_cast<size_t (RawFile::*)()>(&RawFile::pixels_per_frame))
|
||||||
|
.def(
|
||||||
|
"pixels_per_frame",
|
||||||
|
[](RawFile &self, const size_t roi_index) {
|
||||||
|
return self.pixels_per_frame(roi_index);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Pixels per frame for the given ROI.
|
||||||
|
)")
|
||||||
|
.def_property_readonly("bytes_per_pixel", &RawFile::bytes_per_pixel)
|
||||||
|
.def("seek", &RawFile::seek, R"(
|
||||||
|
Seek to a frame index in file.
|
||||||
|
)")
|
||||||
|
.def("tell", &RawFile::tell, R"(
|
||||||
|
Return the current frame number.)")
|
||||||
|
.def_property_readonly("total_frames", &RawFile::total_frames)
|
||||||
|
.def("rows", static_cast<size_t (RawFile::*)() const>(&RawFile::rows))
|
||||||
|
.def(
|
||||||
|
"rows",
|
||||||
|
[](RawFile &self, const size_t roi_index) {
|
||||||
|
return self.rows(roi_index);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Rows for the given ROI.
|
||||||
|
)")
|
||||||
|
.def("cols", static_cast<size_t (RawFile::*)() const>(&RawFile::cols))
|
||||||
|
.def(
|
||||||
|
"cols",
|
||||||
|
[](RawFile &self, const size_t roi_index) {
|
||||||
|
return self.cols(roi_index);
|
||||||
|
},
|
||||||
|
R"(
|
||||||
|
Cols for the given ROI.
|
||||||
|
)")
|
||||||
|
.def_property_readonly("bitdepth", &RawFile::bitdepth)
|
||||||
|
.def_property_readonly("geometry", &RawFile::geometry)
|
||||||
|
.def_property_readonly("detector_type", &RawFile::detector_type)
|
||||||
|
.def_property_readonly("master", &RawFile::master)
|
||||||
|
.def_property_readonly("n_modules", &RawFile::n_modules)
|
||||||
|
.def_property_readonly("n_modules_in_roi", &RawFile::n_modules_in_roi)
|
||||||
|
.def_property_readonly("num_rois", &RawFile::num_rois);
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "bind_ClusterVector.hpp"
|
#include "bind_ClusterVector.hpp"
|
||||||
#include "bind_Eta.hpp"
|
#include "bind_Eta.hpp"
|
||||||
#include "bind_Interpolator.hpp"
|
#include "bind_Interpolator.hpp"
|
||||||
|
#include "bind_RawFile.hpp"
|
||||||
#include "bind_calibration.hpp"
|
#include "bind_calibration.hpp"
|
||||||
|
|
||||||
// TODO! migrate the other names
|
// TODO! migrate the other names
|
||||||
@@ -20,7 +21,6 @@
|
|||||||
#include "jungfrau_data_file.hpp"
|
#include "jungfrau_data_file.hpp"
|
||||||
#include "pedestal.hpp"
|
#include "pedestal.hpp"
|
||||||
#include "pixel_map.hpp"
|
#include "pixel_map.hpp"
|
||||||
#include "raw_file.hpp"
|
|
||||||
#include "raw_master_file.hpp"
|
#include "raw_master_file.hpp"
|
||||||
#include "raw_sub_file.hpp"
|
#include "raw_sub_file.hpp"
|
||||||
#include "var_cluster.hpp"
|
#include "var_cluster.hpp"
|
||||||
|
|||||||
@@ -85,3 +85,20 @@ struct fmt_format_trait<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> {
|
|||||||
|
|
||||||
template <typename ClusterType>
|
template <typename ClusterType>
|
||||||
auto fmt_format = fmt_format_trait<ClusterType>::value();
|
auto fmt_format = fmt_format_trait<ClusterType>::value();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to allocate image data given item size and shape
|
||||||
|
* used when we want to fill a numpy array and return to python
|
||||||
|
*/
|
||||||
|
py::array allocate_image_data(size_t item_size,
|
||||||
|
const std::vector<size_t> &shape) {
|
||||||
|
py::array image_data;
|
||||||
|
if (item_size == 1) {
|
||||||
|
image_data = py::array_t<uint8_t>(shape);
|
||||||
|
} else if (item_size == 2) {
|
||||||
|
image_data = py::array_t<uint16_t>(shape);
|
||||||
|
} else if (item_size == 4) {
|
||||||
|
image_data = py::array_t<uint32_t>(shape);
|
||||||
|
}
|
||||||
|
return image_data;
|
||||||
|
}
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
#include "aare/CtbRawFile.hpp"
|
|
||||||
#include "aare/File.hpp"
|
|
||||||
#include "aare/Frame.hpp"
|
|
||||||
#include "aare/RawFile.hpp"
|
|
||||||
#include "aare/RawMasterFile.hpp"
|
|
||||||
#include "aare/RawSubFile.hpp"
|
|
||||||
|
|
||||||
#include "aare/defs.hpp"
|
|
||||||
// #include "aare/fClusterFileV2.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <pybind11/iostream.h>
|
|
||||||
#include <pybind11/numpy.h>
|
|
||||||
#include <pybind11/pybind11.h>
|
|
||||||
#include <pybind11/stl.h>
|
|
||||||
#include <pybind11/stl/filesystem.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace py = pybind11;
|
|
||||||
using namespace ::aare;
|
|
||||||
|
|
||||||
void define_raw_file_io_bindings(py::module &m) {
|
|
||||||
py::class_<RawFile>(m, "RawFile")
|
|
||||||
.def(py::init<const std::filesystem::path &>())
|
|
||||||
.def("read_frame",
|
|
||||||
[](RawFile &self) {
|
|
||||||
py::array image;
|
|
||||||
std::vector<ssize_t> shape;
|
|
||||||
shape.reserve(2);
|
|
||||||
shape.push_back(self.rows());
|
|
||||||
shape.push_back(self.cols());
|
|
||||||
|
|
||||||
// return headers from all subfiles
|
|
||||||
py::array_t<DetectorHeader> header(self.n_modules());
|
|
||||||
|
|
||||||
const uint8_t item_size = self.bytes_per_pixel();
|
|
||||||
if (item_size == 1) {
|
|
||||||
image = py::array_t<uint8_t>(shape);
|
|
||||||
} else if (item_size == 2) {
|
|
||||||
image = py::array_t<uint16_t>(shape);
|
|
||||||
} else if (item_size == 4) {
|
|
||||||
image = py::array_t<uint32_t>(shape);
|
|
||||||
}
|
|
||||||
self.read_into(
|
|
||||||
reinterpret_cast<std::byte *>(image.mutable_data()),
|
|
||||||
header.mutable_data());
|
|
||||||
|
|
||||||
return py::make_tuple(header, image);
|
|
||||||
})
|
|
||||||
.def(
|
|
||||||
"read_n",
|
|
||||||
[](RawFile &self, size_t n_frames) {
|
|
||||||
// adjust for actual frames left in the file
|
|
||||||
n_frames =
|
|
||||||
std::min(n_frames, self.total_frames() - self.tell());
|
|
||||||
if (n_frames == 0) {
|
|
||||||
throw std::runtime_error("No frames left in file");
|
|
||||||
}
|
|
||||||
std::vector<size_t> shape{n_frames, self.rows(), self.cols()};
|
|
||||||
|
|
||||||
// return headers from all subfiles
|
|
||||||
py::array_t<DetectorHeader> header;
|
|
||||||
if (self.n_modules() == 1) {
|
|
||||||
header = py::array_t<DetectorHeader>(n_frames);
|
|
||||||
} else {
|
|
||||||
header = py::array_t<DetectorHeader>(
|
|
||||||
{self.n_modules_in_roi(), n_frames});
|
|
||||||
}
|
|
||||||
// py::array_t<DetectorHeader> header({self.n_mod(), n_frames});
|
|
||||||
|
|
||||||
py::array image;
|
|
||||||
const uint8_t item_size = self.bytes_per_pixel();
|
|
||||||
if (item_size == 1) {
|
|
||||||
image = py::array_t<uint8_t>(shape);
|
|
||||||
} else if (item_size == 2) {
|
|
||||||
image = py::array_t<uint16_t>(shape);
|
|
||||||
} else if (item_size == 4) {
|
|
||||||
image = py::array_t<uint32_t>(shape);
|
|
||||||
}
|
|
||||||
self.read_into(
|
|
||||||
reinterpret_cast<std::byte *>(image.mutable_data()),
|
|
||||||
n_frames, header.mutable_data());
|
|
||||||
|
|
||||||
return py::make_tuple(header, image);
|
|
||||||
},
|
|
||||||
R"(
|
|
||||||
Read n frames from the file.
|
|
||||||
)")
|
|
||||||
.def("frame_number", &RawFile::frame_number)
|
|
||||||
.def_property_readonly("bytes_per_frame", &RawFile::bytes_per_frame)
|
|
||||||
.def_property_readonly("pixels_per_frame", &RawFile::pixels_per_frame)
|
|
||||||
.def_property_readonly("bytes_per_pixel", &RawFile::bytes_per_pixel)
|
|
||||||
.def("seek", &RawFile::seek, R"(
|
|
||||||
Seek to a frame index in file.
|
|
||||||
)")
|
|
||||||
.def("tell", &RawFile::tell, R"(
|
|
||||||
Return the current frame number.)")
|
|
||||||
.def_property_readonly("total_frames", &RawFile::total_frames)
|
|
||||||
.def_property_readonly("rows", &RawFile::rows)
|
|
||||||
.def_property_readonly("cols", &RawFile::cols)
|
|
||||||
.def_property_readonly("bitdepth", &RawFile::bitdepth)
|
|
||||||
.def_property_readonly("geometry", &RawFile::geometry)
|
|
||||||
.def_property_readonly("detector_type", &RawFile::detector_type)
|
|
||||||
.def_property_readonly("master", &RawFile::master)
|
|
||||||
.def_property_readonly("n_modules", &RawFile::n_modules)
|
|
||||||
.def_property_readonly("n_modules_in_roi", &RawFile::n_modules_in_roi);
|
|
||||||
}
|
|
||||||
@@ -4,14 +4,46 @@ from aare import RawFile
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@pytest.mark.withdata
|
@pytest.mark.withdata
|
||||||
def test_read_rawfile_with_roi(test_data_path):
|
def test_read_rawfile_with_roi_spanning_over_one_module(test_data_path):
|
||||||
|
|
||||||
with RawFile(test_data_path / "raw/ROITestData/SingleChipROI/Data_master_0.json") as f:
|
with RawFile(test_data_path / "raw/ROITestData/SingleChipROI/Data_master_0.json") as f:
|
||||||
headers, frames = f.read()
|
headers, frames = f.read()
|
||||||
|
|
||||||
|
num_rois = f.num_rois
|
||||||
|
assert num_rois == 1
|
||||||
assert headers.size == 10100
|
assert headers.size == 10100
|
||||||
assert frames.shape == (10100, 256, 256)
|
assert frames.shape == (10100, 256, 256)
|
||||||
|
|
||||||
|
@pytest.mark.withdata
|
||||||
|
def test_read_rawfile_with_multiple_rois(test_data_path):
|
||||||
|
with RawFile(test_data_path / "raw/ROITestData/MultipleROIs/run_master_0.json") as f:
|
||||||
|
num_rois = f.num_rois
|
||||||
|
|
||||||
|
#cannot read_frame for multiple ROIs
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
f.read_frame()
|
||||||
|
|
||||||
|
assert f.tell() == 0
|
||||||
|
frames = f.read_ROIs()
|
||||||
|
assert num_rois == 2
|
||||||
|
assert len(frames) == 2
|
||||||
|
assert frames[0].shape == (301, 101)
|
||||||
|
assert frames[1].shape == (101, 101)
|
||||||
|
|
||||||
|
assert f.tell() == 1
|
||||||
|
|
||||||
|
# read multiple ROIs at once
|
||||||
|
frames = f.read_n_ROIs(2, 1)
|
||||||
|
assert frames.shape == (2, 101, 101)
|
||||||
|
|
||||||
|
assert f.tell() == 3
|
||||||
|
|
||||||
|
# read specific ROI
|
||||||
|
frame = f.read_ROIs(1, 0)
|
||||||
|
assert len(frame) == 1
|
||||||
|
assert frame[0].shape == (301, 101)
|
||||||
|
assert f.tell() == 2
|
||||||
|
|
||||||
@pytest.mark.withdata
|
@pytest.mark.withdata
|
||||||
def test_read_rawfile_quad_eiger_and_compare_to_numpy(test_data_path):
|
def test_read_rawfile_quad_eiger_and_compare_to_numpy(test_data_path):
|
||||||
|
|
||||||
|
|||||||
@@ -41,31 +41,16 @@ DetectorGeometry::DetectorGeometry(const xy &geometry,
|
|||||||
m_modules_x = geometry.col;
|
m_modules_x = geometry.col;
|
||||||
m_modules_y = geometry.row;
|
m_modules_y = geometry.row;
|
||||||
m_pixels_y += static_cast<size_t>((geometry.row - 1) * cfg.module_gap_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() 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_x() const { return m_pixels_x; }
|
||||||
size_t DetectorGeometry::pixels_y() const { return m_pixels_y; }
|
size_t DetectorGeometry::pixels_y() const { return m_pixels_y; }
|
||||||
|
|
||||||
size_t DetectorGeometry::modules_x() const { return m_modules_x; };
|
size_t DetectorGeometry::modules_x() const { return m_modules_x; };
|
||||||
size_t DetectorGeometry::modules_y() const { return m_modules_y; };
|
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> &
|
const std::vector<ModuleGeometry> &
|
||||||
DetectorGeometry::get_module_geometries() const {
|
DetectorGeometry::get_module_geometries() const {
|
||||||
return module_geometries;
|
return module_geometries;
|
||||||
@@ -76,77 +61,8 @@ DetectorGeometry::get_module_geometries(const size_t index) const {
|
|||||||
return module_geometries[index];
|
return module_geometries[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectorGeometry::update_geometry_with_roi(ROI roi) {
|
ModuleGeometry &DetectorGeometry::get_module_geometries(const size_t index) {
|
||||||
#ifdef AARE_VERBOSE
|
return module_geometries[index];
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace aare
|
} // namespace aare
|
||||||
@@ -7,17 +7,20 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "aare/DetectorGeometry.hpp"
|
#include "aare/DetectorGeometry.hpp"
|
||||||
|
#include "aare/ROIGeometry.hpp"
|
||||||
#include "test_config.hpp"
|
#include "test_config.hpp"
|
||||||
|
|
||||||
TEST_CASE("Simple ROIs on one module") {
|
TEST_CASE("Simple ROIs on one module", "[DetectorGeometry]") {
|
||||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
|
||||||
// roi)
|
|
||||||
aare::DetectorGeometry geo(aare::xy{1, 1}, 1024, 512);
|
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_x == 0);
|
||||||
REQUIRE(geo.get_module_geometries(0).origin_y == 0);
|
REQUIRE(geo.get_module_geometries(0).origin_y == 0);
|
||||||
REQUIRE(geo.get_module_geometries(0).width == 1024);
|
REQUIRE(geo.get_module_geometries(0).width == 1024);
|
||||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
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") {
|
SECTION("ROI is the whole module") {
|
||||||
aare::ROI roi;
|
aare::ROI roi;
|
||||||
@@ -25,14 +28,18 @@ TEST_CASE("Simple ROIs on one module") {
|
|||||||
roi.xmax = 1024;
|
roi.xmax = 1024;
|
||||||
roi.ymin = 0;
|
roi.ymin = 0;
|
||||||
roi.ymax = 512;
|
roi.ymax = 512;
|
||||||
geo.update_geometry_with_roi(roi);
|
|
||||||
|
|
||||||
REQUIRE(geo.pixels_x() == 1024);
|
aare::ROIGeometry roi_geometry(roi, geo);
|
||||||
REQUIRE(geo.pixels_y() == 512);
|
|
||||||
REQUIRE(geo.modules_x() == 1);
|
REQUIRE(roi_geometry.pixels_x() == 1024);
|
||||||
REQUIRE(geo.modules_y() == 1);
|
REQUIRE(roi_geometry.pixels_y() == 512);
|
||||||
REQUIRE(geo.get_module_geometries(0).height == 512);
|
REQUIRE(roi_geometry.num_modules_in_roi() == 1);
|
||||||
REQUIRE(geo.get_module_geometries(0).width == 1024);
|
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") {
|
SECTION("ROI is the top left corner of the module") {
|
||||||
aare::ROI roi;
|
aare::ROI roi;
|
||||||
@@ -40,51 +47,22 @@ TEST_CASE("Simple ROIs on one module") {
|
|||||||
roi.xmax = 200;
|
roi.xmax = 200;
|
||||||
roi.ymin = 150;
|
roi.ymin = 150;
|
||||||
roi.ymax = 200;
|
roi.ymax = 200;
|
||||||
geo.update_geometry_with_roi(roi);
|
|
||||||
|
|
||||||
REQUIRE(geo.pixels_x() == 100);
|
aare::ROIGeometry roi_geometry(roi, geo);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("ROI is a small square") {
|
REQUIRE(roi_geometry.pixels_x() == 100);
|
||||||
aare::ROI roi;
|
REQUIRE(roi_geometry.pixels_y() == 50);
|
||||||
roi.xmin = 1000;
|
REQUIRE(roi_geometry.num_modules_in_roi() == 1);
|
||||||
roi.xmax = 1010;
|
auto module_geometry =
|
||||||
roi.ymin = 500;
|
geo.get_module_geometries(roi_geometry.module_indices_in_roi(0));
|
||||||
roi.ymax = 510;
|
REQUIRE(module_geometry.height == 50);
|
||||||
geo.update_geometry_with_roi(roi);
|
REQUIRE(module_geometry.width == 100);
|
||||||
|
REQUIRE(module_geometry.origin_x == 0);
|
||||||
REQUIRE(geo.pixels_x() == 10);
|
REQUIRE(module_geometry.origin_y == 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Two modules side by side") {
|
TEST_CASE("Two modules side by side", "[DetectorGeometry]") {
|
||||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
|
||||||
// roi)
|
|
||||||
aare::DetectorGeometry geo(aare::xy{1, 2}, 1024, 512);
|
aare::DetectorGeometry geo(aare::xy{1, 2}, 1024, 512);
|
||||||
|
|
||||||
REQUIRE(geo.get_module_geometries(0).origin_x == 0);
|
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(0).height == 512);
|
||||||
REQUIRE(geo.get_module_geometries(1).origin_x == 1024);
|
REQUIRE(geo.get_module_geometries(1).origin_x == 1024);
|
||||||
REQUIRE(geo.get_module_geometries(1).origin_y == 0);
|
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") {
|
SECTION("ROI is the whole image") {
|
||||||
aare::ROI roi;
|
aare::ROI roi;
|
||||||
@@ -100,12 +82,24 @@ TEST_CASE("Two modules side by side") {
|
|||||||
roi.xmax = 2048;
|
roi.xmax = 2048;
|
||||||
roi.ymin = 0;
|
roi.ymin = 0;
|
||||||
roi.ymax = 512;
|
roi.ymax = 512;
|
||||||
geo.update_geometry_with_roi(roi);
|
|
||||||
|
|
||||||
REQUIRE(geo.pixels_x() == 2048);
|
aare::ROIGeometry roi_geometry(roi, geo);
|
||||||
REQUIRE(geo.pixels_y() == 512);
|
|
||||||
REQUIRE(geo.modules_x() == 2);
|
REQUIRE(roi_geometry.pixels_x() == 2048);
|
||||||
REQUIRE(geo.modules_y() == 1);
|
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") {
|
SECTION("rectangle on both modules") {
|
||||||
aare::ROI roi;
|
aare::ROI roi;
|
||||||
@@ -113,28 +107,30 @@ TEST_CASE("Two modules side by side") {
|
|||||||
roi.xmax = 1300;
|
roi.xmax = 1300;
|
||||||
roi.ymin = 200;
|
roi.ymin = 200;
|
||||||
roi.ymax = 499;
|
roi.ymax = 499;
|
||||||
geo.update_geometry_with_roi(roi);
|
|
||||||
|
|
||||||
REQUIRE(geo.pixels_x() == 500);
|
aare::ROIGeometry roi_geometry(roi, geo);
|
||||||
REQUIRE(geo.pixels_y() == 299);
|
|
||||||
REQUIRE(geo.modules_x() == 2);
|
REQUIRE(roi_geometry.pixels_x() == 500);
|
||||||
REQUIRE(geo.modules_y() == 1);
|
REQUIRE(roi_geometry.pixels_y() == 299);
|
||||||
REQUIRE(geo.get_module_geometries(0).height == 299);
|
REQUIRE(roi_geometry.num_modules_in_roi() == 2);
|
||||||
REQUIRE(geo.get_module_geometries(0).width == 224);
|
|
||||||
REQUIRE(geo.get_module_geometries(1).height == 299);
|
auto module_geometry_0 = geo.get_module_geometries(0);
|
||||||
REQUIRE(geo.get_module_geometries(1).width == 276);
|
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") {
|
TEST_CASE("Three modules side by side", "[DetectorGeometry]") {
|
||||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
|
||||||
// roi)
|
|
||||||
aare::DetectorGeometry geo(aare::xy{1, 3}, 1024, 512);
|
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_x == 0);
|
||||||
REQUIRE(geo.get_module_geometries(0).origin_y == 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(0).height == 512);
|
||||||
REQUIRE(geo.get_module_geometries(1).origin_x == 1024);
|
REQUIRE(geo.get_module_geometries(1).origin_x == 1024);
|
||||||
REQUIRE(geo.get_module_geometries(2).origin_x == 2048);
|
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_x() == 3);
|
||||||
REQUIRE(geo.modules_y() == 1);
|
REQUIRE(geo.modules_y() == 1);
|
||||||
REQUIRE(geo.get_module_geometries(0).height == 123);
|
REQUIRE(geo.pixels_x() == 3072);
|
||||||
REQUIRE(geo.get_module_geometries(0).width == 324);
|
REQUIRE(geo.pixels_y() == 512);
|
||||||
REQUIRE(geo.get_module_geometries(1).height == 123);
|
|
||||||
REQUIRE(geo.get_module_geometries(1).width == 1024);
|
SECTION("ROI overlapping all three modules") {
|
||||||
REQUIRE(geo.get_module_geometries(2).height == 123);
|
aare::ROI roi;
|
||||||
REQUIRE(geo.get_module_geometries(2).width == 452);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Four modules as a square") {
|
SECTION("ROI overlapping last two modules") {
|
||||||
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
|
aare::ROI 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]") {
|
||||||
aare::DetectorGeometry geo(aare::xy{2, 2}, 1024, 512, aare::xy{1, 2});
|
aare::DetectorGeometry geo(aare::xy{2, 2}, 1024, 512, aare::xy{1, 2});
|
||||||
aare::ROI roi;
|
aare::ROI roi;
|
||||||
roi.xmin = 500;
|
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(2).origin_y == 512);
|
||||||
REQUIRE(geo.get_module_geometries(3).origin_x == 1024);
|
REQUIRE(geo.get_module_geometries(3).origin_x == 1024);
|
||||||
REQUIRE(geo.get_module_geometries(3).origin_y == 512);
|
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_x() == 2);
|
||||||
REQUIRE(geo.modules_y() == 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).height == 12);
|
||||||
REQUIRE(geo.get_module_geometries(0).width == 524);
|
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).height == 12);
|
||||||
REQUIRE(geo.get_module_geometries(1).width == 976);
|
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).height == 88);
|
||||||
REQUIRE(geo.get_module_geometries(2).width == 524);
|
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).height == 88);
|
||||||
REQUIRE(geo.get_module_geometries(3).width == 976);
|
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
|
||||||
318
src/RawFile.cpp
318
src/RawFile.cpp
@@ -2,6 +2,7 @@
|
|||||||
#include "aare/RawFile.hpp"
|
#include "aare/RawFile.hpp"
|
||||||
#include "aare/DetectorGeometry.hpp"
|
#include "aare/DetectorGeometry.hpp"
|
||||||
#include "aare/PixelMap.hpp"
|
#include "aare/PixelMap.hpp"
|
||||||
|
#include "aare/ROIGeometry.hpp"
|
||||||
#include "aare/algorithm.hpp"
|
#include "aare/algorithm.hpp"
|
||||||
#include "aare/defs.hpp"
|
#include "aare/defs.hpp"
|
||||||
#include "aare/logger.hpp"
|
#include "aare/logger.hpp"
|
||||||
@@ -17,28 +18,98 @@ RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode)
|
|||||||
: m_master(fname),
|
: m_master(fname),
|
||||||
m_geometry(m_master.geometry(), m_master.pixels_x(), m_master.pixels_y(),
|
m_geometry(m_master.geometry(), m_master.pixels_x(), m_master.pixels_y(),
|
||||||
m_master.udp_interfaces_per_module(), m_master.quad()) {
|
m_master.udp_interfaces_per_module(), m_master.quad()) {
|
||||||
|
|
||||||
m_mode = mode;
|
m_mode = mode;
|
||||||
|
|
||||||
|
m_subfiles.resize(m_master.rois().has_value() ? m_master.rois()->size()
|
||||||
|
: 1);
|
||||||
|
|
||||||
if (mode == "r") {
|
if (mode == "r") {
|
||||||
if (m_master.roi()) {
|
if (m_master.rois().has_value()) {
|
||||||
m_geometry.update_geometry_with_roi(m_master.roi().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 {
|
} else {
|
||||||
throw std::runtime_error(LOCATION +
|
throw std::runtime_error(LOCATION +
|
||||||
" Unsupported mode. Can only read RawFiles.");
|
" 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) {
|
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);
|
seek(frame_number);
|
||||||
return read_frame();
|
return read_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawFile::read_into(std::byte *image_buf, size_t n_frames) {
|
void RawFile::read_into(std::byte *image_buf, size_t n_frames) {
|
||||||
// TODO: implement this in a more efficient way
|
// 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++) {
|
for (size_t i = 0; i < n_frames; i++) {
|
||||||
this->get_frame_into(m_current_frame++, image_buf);
|
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) {
|
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);
|
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,
|
void RawFile::read_into(std::byte *image_buf, size_t n_frames,
|
||||||
DetectorHeader *header) {
|
DetectorHeader *header) {
|
||||||
// return get_frame_into(m_current_frame++, image_buf, 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++) {
|
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();
|
image_buf += bytes_per_frame();
|
||||||
if (header)
|
if (header)
|
||||||
header += m_geometry.n_modules_in_roi();
|
header += m_ROI_geometries[0].num_modules_in_roi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RawFile::bytes_per_frame() {
|
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;
|
bits_per_byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RawFile::pixels_per_frame() {
|
size_t RawFile::pixels_per_frame() {
|
||||||
// return m_rows * m_cols;
|
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
|
||||||
return m_geometry.pixels_x() * m_geometry.pixels_y();
|
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(); }
|
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::tell() { return m_current_frame; }
|
||||||
|
|
||||||
size_t RawFile::total_frames() const { return m_master.frames_in_file(); }
|
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(); }
|
size_t RawFile::bitdepth() const { return m_master.bitdepth(); }
|
||||||
xy RawFile::geometry() const {
|
xy RawFile::geometry() const {
|
||||||
return xy{static_cast<uint32_t>(m_geometry.modules_y()),
|
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() 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() {
|
const ROIGeometry &RawFile::roi_geometries(size_t roi_index) const {
|
||||||
if (m_mode == "r")
|
return m_ROI_geometries[roi_index];
|
||||||
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>(
|
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,
|
m_master.data_fname(i, 0), m_master.detector_type(), pos.height,
|
||||||
pos.width, m_master.bitdepth(), pos.row_index, pos.col_index));
|
pos.width, m_master.bitdepth(), pos.row_index, pos.col_index));
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
throw std::runtime_error(LOCATION +
|
throw std::runtime_error(LOCATION +
|
||||||
"Unsupported mode. Can only read RawFiles.");
|
"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; }
|
RawMasterFile RawFile::master() const { return m_master; }
|
||||||
|
|
||||||
Frame RawFile::get_frame(size_t frame_index) {
|
Frame RawFile::get_frame(size_t frame_index, const size_t roi_index) {
|
||||||
auto f = Frame(m_geometry.pixels_y(), m_geometry.pixels_x(),
|
auto f = Frame(m_ROI_geometries[roi_index].pixels_y(),
|
||||||
|
m_ROI_geometries[roi_index].pixels_x(),
|
||||||
Dtype::from_bitdepth(m_master.bitdepth()));
|
Dtype::from_bitdepth(m_master.bitdepth()));
|
||||||
std::byte *frame_buffer = f.data();
|
std::byte *frame_buffer = f.data();
|
||||||
get_frame_into(frame_index, frame_buffer);
|
get_frame_into(frame_index, frame_buffer, roi_index);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RawFile::bytes_per_pixel() const { return m_master.bitdepth() / 8; }
|
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,
|
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 << ")";
|
LOG(logDEBUG) << "RawFile::get_frame_into(" << frame_index << ")";
|
||||||
if (frame_index >= total_frames()) {
|
if (frame_index >= total_frames()) {
|
||||||
throw std::runtime_error(LOCATION + "Frame number out of range");
|
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_numbers(
|
||||||
std::vector<size_t> frame_indices(m_geometry.n_modules_in_roi(),
|
m_ROI_geometries[roi_index].num_modules_in_roi());
|
||||||
frame_index);
|
std::vector<size_t> frame_indices(
|
||||||
|
m_ROI_geometries[roi_index].num_modules_in_roi(), frame_index);
|
||||||
|
|
||||||
// sync the frame numbers
|
// sync the frame numbers
|
||||||
|
|
||||||
if (m_geometry.n_modules() != 1) { // if we have more than one module
|
if (m_ROI_geometries[roi_index].num_modules_in_roi() !=
|
||||||
for (size_t part_idx = 0; part_idx != m_geometry.n_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) {
|
++part_idx) {
|
||||||
frame_numbers[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
|
// 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(),
|
frame_numbers.begin(),
|
||||||
std::min_element(frame_numbers.begin(), frame_numbers.end()));
|
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]++;
|
frame_indices[min_frame_idx]++;
|
||||||
|
|
||||||
// 4. if we can't increase its index => throw error
|
// 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] =
|
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]);
|
frame_indices[min_frame_idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_master.geometry().col == 1) {
|
if (m_master.geometry().col == 1) {
|
||||||
// get the part from each subfile and copy it to the frame
|
// 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) {
|
++part_idx) {
|
||||||
auto corrected_idx = frame_indices[part_idx];
|
auto corrected_idx = frame_indices[part_idx];
|
||||||
|
|
||||||
// This is where we start writing
|
// This is where we start writing
|
||||||
auto offset = (m_geometry
|
auto offset =
|
||||||
|
(m_geometry
|
||||||
.get_module_geometries(
|
.get_module_geometries(
|
||||||
m_geometry.get_modules_in_roi(part_idx))
|
m_ROI_geometries[roi_index].module_indices_in_roi(
|
||||||
|
part_idx))
|
||||||
.origin_y *
|
.origin_y *
|
||||||
m_geometry.pixels_x() +
|
m_ROI_geometries[roi_index].pixels_x() +
|
||||||
m_geometry
|
m_geometry
|
||||||
.get_module_geometries(
|
.get_module_geometries(
|
||||||
m_geometry.get_modules_in_roi(part_idx))
|
m_ROI_geometries[roi_index].module_indices_in_roi(
|
||||||
|
part_idx))
|
||||||
.origin_x) *
|
.origin_x) *
|
||||||
m_master.bitdepth() / 8;
|
m_master.bitdepth() / 8;
|
||||||
|
|
||||||
if (m_geometry
|
if (m_geometry
|
||||||
.get_module_geometries(
|
.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)
|
.origin_x != 0)
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
LOCATION +
|
LOCATION +
|
||||||
" Implementation error. x pos not 0."); // TODO: origin
|
" Implementation error. x pos not 0."); // TODO:
|
||||||
|
// origin
|
||||||
// can still
|
// can still
|
||||||
// change if roi
|
// change if
|
||||||
|
// roi
|
||||||
// changes
|
// changes
|
||||||
// TODO! What if the files don't match?
|
// TODO! What if the files don't match?
|
||||||
m_subfiles[part_idx]->seek(corrected_idx);
|
m_subfiles[roi_index][part_idx]->seek(corrected_idx);
|
||||||
m_subfiles[part_idx]->read_into(frame_buffer + offset, header);
|
m_subfiles[roi_index][part_idx]->read_into(frame_buffer + offset,
|
||||||
|
header);
|
||||||
if (header)
|
if (header)
|
||||||
++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?
|
// TODO! should we read row by row?
|
||||||
|
|
||||||
// create a buffer large enough to hold a full module
|
// create a buffer large enough to hold a full module
|
||||||
auto bytes_per_part = m_master.pixels_y() * m_master.pixels_x() *
|
auto bytes_per_part =
|
||||||
m_master.bitdepth() /
|
m_master.pixels_y() * m_master.pixels_x() * m_master.bitdepth() /
|
||||||
8; // TODO! replace with image_size_in_bytes
|
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];
|
auto *part_buffer = new std::byte[bytes_per_part];
|
||||||
|
|
||||||
// TODO! if we have many submodules we should reorder them on the
|
// TODO! if we have many submodules we should reorder them on
|
||||||
// module level
|
// 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) {
|
++part_idx) {
|
||||||
auto pos = m_geometry.get_module_geometries(
|
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];
|
auto corrected_idx = frame_indices[part_idx];
|
||||||
|
|
||||||
m_subfiles[part_idx]->seek(corrected_idx);
|
m_subfiles[roi_index][part_idx]->seek(corrected_idx);
|
||||||
m_subfiles[part_idx]->read_into(part_buffer, header);
|
m_subfiles[roi_index][part_idx]->read_into(part_buffer, header);
|
||||||
if (header)
|
if (header)
|
||||||
++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 irow = (pos.origin_y + cur_row);
|
||||||
auto icol = pos.origin_x;
|
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;
|
dest = dest * m_master.bitdepth() / 8;
|
||||||
memcpy(frame_buffer + dest,
|
memcpy(frame_buffer + dest,
|
||||||
part_buffer +
|
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) {
|
std::vector<Frame> RawFile::read_n(size_t n_frames) {
|
||||||
// TODO: implement this in a more efficient way
|
// 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;
|
std::vector<Frame> frames;
|
||||||
|
frames.reserve(n_frames);
|
||||||
for (size_t i = 0; i < n_frames; i++) {
|
for (size_t i = 0; i < n_frames; i++) {
|
||||||
frames.push_back(this->get_frame(m_current_frame));
|
frames.push_back(this->get_frame(m_current_frame));
|
||||||
m_current_frame++;
|
m_current_frame++;
|
||||||
@@ -277,11 +472,26 @@ std::vector<Frame> RawFile::read_n(size_t n_frames) {
|
|||||||
return 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) {
|
size_t RawFile::frame_number(size_t frame_index) {
|
||||||
if (frame_index >= m_master.frames_in_file()) {
|
if (frame_index >= m_master.frames_in_file()) {
|
||||||
throw std::runtime_error(LOCATION + " Frame number out of range");
|
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
|
} // namespace aare
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ using aare::File;
|
|||||||
using aare::RawFile;
|
using aare::RawFile;
|
||||||
using namespace aare;
|
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 =
|
auto fpath =
|
||||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
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);
|
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 =
|
auto fpath =
|
||||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
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 =
|
auto fpath =
|
||||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
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",
|
TEST_CASE("Read a frame numbers where the subfile is missing throws",
|
||||||
"[.with-data]") {
|
"[.with-data][RawFile]") {
|
||||||
auto fpath = test_data_path() / "raw/jungfrau" /
|
auto fpath = test_data_path() / "raw/jungfrau" /
|
||||||
"jungfrau_missing_subfile_master_0.json";
|
"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",
|
TEST_CASE("Read data from a jungfrau 500k single port raw file",
|
||||||
"[.with-data]") {
|
"[.with-data][RawFile]") {
|
||||||
auto fpath =
|
auto fpath =
|
||||||
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
test_data_path() / "raw/jungfrau/jungfrau_single_master_0.json";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
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 =
|
auto fpath =
|
||||||
test_data_path() / "raw/eiger" / "eiger_500k_16bit_master_0.json";
|
test_data_path() / "raw/eiger" / "eiger_500k_16bit_master_0.json";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
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") {
|
SECTION("jungfrau data") {
|
||||||
auto fpath_raw =
|
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 raw_frame = raw.read_frame();
|
||||||
|
|
||||||
auto npy_frame = npy.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>()));
|
CHECK((raw_frame.view<uint32_t>() == npy_frame.view<uint32_t>()));
|
||||||
}
|
}
|
||||||
SECTION("eiger data") {
|
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 =
|
auto fpath =
|
||||||
test_data_path() / "raw/jungfrau" / "jungfrau_double_master_0.json";
|
test_data_path() / "raw/jungfrau" / "jungfrau_double_master_0.json";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
REQUIRE(std::filesystem::exists(fpath));
|
||||||
@@ -217,7 +225,7 @@ struct TestParameters {
|
|||||||
std::vector<ModuleGeometry> module_geometries{};
|
std::vector<ModuleGeometry> module_geometries{};
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("check find_geometry", "[.with-data]") {
|
TEST_CASE("check find_geometry", "[.with-data][RawFile]") {
|
||||||
|
|
||||||
auto test_parameters = GENERATE(
|
auto test_parameters = GENERATE(
|
||||||
TestParameters{"raw/jungfrau_2modules_version6.1.2/run_master_0.raw", 2,
|
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 =
|
auto fpath =
|
||||||
test_data_path() / "raw/ROITestData/SingleChipROI/Data_master_0.json";
|
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() == 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);
|
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
|
// TODO! Better explanation and error message
|
||||||
auto fpath = test_data_path() / "raw/mythen/scan242_master_3.raw";
|
auto fpath = test_data_path() / "raw/mythen/scan242_master_3.raw";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
REQUIRE(std::filesystem::exists(fpath));
|
||||||
@@ -323,7 +396,7 @@ TEST_CASE("Read file with unordered frames", "[.with-data]") {
|
|||||||
REQUIRE_THROWS((f.read_frame()));
|
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";
|
auto fpath = test_data_path() / "raw/newmythen03/run_2_master_1.json";
|
||||||
REQUIRE(std::filesystem::exists(fpath));
|
REQUIRE(std::filesystem::exists(fpath));
|
||||||
RawFile f(fpath);
|
RawFile f(fpath);
|
||||||
|
|||||||
@@ -193,7 +193,18 @@ ScanParameters RawMasterFile::scan_parameters() const {
|
|||||||
return m_scan_parameters;
|
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) {
|
void RawMasterFile::parse_json(std::istream &is) {
|
||||||
json j;
|
json j;
|
||||||
@@ -338,34 +349,35 @@ void RawMasterFile::parse_json(std::istream &is) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ROI tmp_roi;
|
|
||||||
if (v < 8.0) {
|
if (v < 8.0) {
|
||||||
auto obj = j.at("Receiver Roi");
|
auto obj = j.at("Receiver Roi");
|
||||||
tmp_roi.xmin = obj.at("xmin");
|
if (obj.at("xmin") != 4294967295 || obj.at("xmax") != 4294967295 ||
|
||||||
tmp_roi.xmax = obj.at("xmax");
|
obj.at("ymin") != 4294967295 || obj.at("ymax") != 4294967295) {
|
||||||
tmp_roi.ymin = obj.at("ymin");
|
// Handle Mythen
|
||||||
tmp_roi.ymax = obj.at("ymax");
|
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 {
|
} else {
|
||||||
// TODO: for now only handle single ROI
|
|
||||||
auto obj = j.at("Receiver Rois");
|
auto obj = j.at("Receiver Rois");
|
||||||
tmp_roi.xmin = obj[0].at("xmin");
|
m_rois.emplace();
|
||||||
tmp_roi.xmax = obj[0].at("xmax");
|
for (auto &elem : obj) {
|
||||||
tmp_roi.ymin = obj[0].at("ymin");
|
// handle Mythen
|
||||||
tmp_roi.ymax = obj[0].at("ymax");
|
if (elem.at("ymin") == -1 && elem.at("ymax") == -1) {
|
||||||
|
elem.at("ymin") = 0;
|
||||||
|
elem.at("ymax") = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if any of the values are set update the roi
|
m_rois.value().push_back(ROI{
|
||||||
// TODO: doesnt it write garbage if one of them is not set
|
elem.at("xmin"), static_cast<ssize_t>(elem.at("xmax")) + 1,
|
||||||
if (tmp_roi.xmin != 4294967295 || tmp_roi.xmax != 4294967295 ||
|
elem.at("ymin"),
|
||||||
tmp_roi.ymin != 4294967295 || tmp_roi.ymax != 4294967295) {
|
static_cast<ssize_t>(elem.at("ymax")) + 1});
|
||||||
tmp_roi.xmax++;
|
|
||||||
// Handle Mythen
|
|
||||||
if (tmp_roi.ymin == -1 && tmp_roi.ymax == -1) {
|
|
||||||
tmp_roi.ymin = 0;
|
|
||||||
tmp_roi.ymax = 0;
|
|
||||||
}
|
}
|
||||||
tmp_roi.ymax++;
|
|
||||||
m_roi = tmp_roi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (const json::out_of_range &e) {
|
} catch (const json::out_of_range &e) {
|
||||||
@@ -380,7 +392,6 @@ void RawMasterFile::parse_json(std::istream &is) {
|
|||||||
std::stoi(j["Counter Mask"].get<std::string>(), nullptr, 16);
|
std::stoi(j["Counter Mask"].get<std::string>(), nullptr, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update detector type for Moench
|
// Update detector type for Moench
|
||||||
// TODO! How does this work with old .raw master files?
|
// TODO! How does this work with old .raw master files?
|
||||||
if (m_type == DetectorType::Moench && !m_analog_samples &&
|
if (m_type == DetectorType::Moench && !m_analog_samples &&
|
||||||
|
|||||||
Reference in New Issue
Block a user