// Copyright (2019-2023) Paul Scherrer Institute #include #include "bitshuffle/bitshuffle.h" #include "FrameTransformation.h" #include "../common/RawToConvertedGeometry.h" #include "../common/JFJochException.h" template void FillVector(std::vector &v, T fill_value) { auto ptr = (T *) v.data(); for (int i = 0; i < v.size() / sizeof(T); i++) ptr[i] = fill_value; } template int64_t calc_roi(const void* array, size_t width, const ROIRectangle &input, int64_t min_val, int64_t max_val) { int64_t ret = 0; for (size_t y = input.y_min; y <= input.y_max; y++) { for (size_t x = input.x_min; x <= input.x_max; x++) { int64_t val = ((T *)array)[y * width + x]; if ((ret == INT64_MIN) || (val < min_val)) ret = INT64_MIN; else if ((ret == INT64_MAX) || (val > max_val)) ret = INT64_MAX; else ret += val; } } return ret; } FrameTransformation::FrameTransformation(const DiffractionExperiment &in_experiment) : experiment(in_experiment), pixel_depth(experiment.GetPixelDepth()), pixel_signed(experiment.IsPixelSigned()), compressor(in_experiment.GetCompressionAlgorithm()), err_value(experiment.GetPixelDepth() * RAW_MODULE_SIZE) { precompression_buffer.resize(experiment.GetPixelsNum() * pixel_depth); if (pixel_depth == 2) { if (pixel_signed) { FillVector(precompression_buffer, INT16_MIN); FillVector(err_value, INT16_MIN); } else { FillVector(precompression_buffer, UINT16_MAX); FillVector(err_value, UINT16_MAX); } } else if (pixel_depth == 4) { if (pixel_signed) { FillVector(precompression_buffer, INT32_MIN); FillVector(err_value, INT32_MIN); } else { FillVector(precompression_buffer, UINT32_MAX); FillVector(err_value, UINT32_MAX); } } } size_t FrameTransformation::CompressImage(void *output) { return compressor.Compress(output, precompression_buffer.data(), experiment.GetPixelsNum(), experiment.GetPixelDepth()); } CompressedImage FrameTransformation::GetCompressedImage() { CompressedImage image{}; if (experiment.GetCompressionAlgorithm() == CompressionAlgorithm::NO_COMPRESSION) { image.data = (uint8_t *) precompression_buffer.data(); image.size = experiment.GetPixelsNum() * experiment.GetPixelDepth(); } else { compressed_buffer.resize(MaxCompressedSize(experiment.GetCompressionAlgorithm(), experiment.GetPixelsNum(), experiment.GetPixelDepth())); image.data = (uint8_t *) compressed_buffer.data(); image.size = CompressImage(compressed_buffer.data()); } image.xpixel = experiment.GetXPixelsNum(); image.ypixel = experiment.GetYPixelsNum(); image.algorithm = experiment.GetCompressionAlgorithm(); image.pixel_depth_bytes = experiment.GetPixelDepth(); image.pixel_is_signed = pixel_signed; image.pixel_is_float = false; image.channel = "default"; return image; } void FrameTransformation::ProcessModule(const void *input, uint16_t module_number, int data_stream) { size_t module_number_abs = experiment.GetFirstModuleOfDataStream(data_stream) + module_number; if (experiment.GetDetectorMode() != DetectorMode::Conversion) { size_t mod_size = RAW_MODULE_SIZE * pixel_depth; memcpy(precompression_buffer.data() + module_number_abs * mod_size, input, mod_size); } else { if (pixel_depth == 2) { if (pixel_signed) TransferModuleAdjustMultipixels((int16_t *) precompression_buffer.data(), (int16_t *) input, experiment.GetModuleSlowDirectionStep(module_number_abs), static_cast(INT16_MIN), static_cast(INT16_MAX), experiment.GetModuleFastDirectionStep(module_number_abs), experiment.GetPixel0OfModule(module_number_abs)); else TransferModuleAdjustMultipixels((uint16_t *) precompression_buffer.data(), (uint16_t *) input, experiment.GetModuleSlowDirectionStep(module_number_abs), static_cast(0), static_cast(UINT16_MAX - 1), experiment.GetModuleFastDirectionStep(module_number_abs), experiment.GetPixel0OfModule(module_number_abs)); } else if (pixel_depth == 4) { if (pixel_signed) TransferModuleAdjustMultipixels((int32_t *) precompression_buffer.data(), (int32_t *) input, experiment.GetModuleSlowDirectionStep(module_number_abs), static_cast(INT32_MIN), static_cast(INT32_MAX), experiment.GetModuleFastDirectionStep(module_number_abs), experiment.GetPixel0OfModule(module_number_abs)); else TransferModuleAdjustMultipixels((uint32_t *) precompression_buffer.data(), (uint32_t *) input, experiment.GetModuleSlowDirectionStep(module_number_abs), static_cast(0), static_cast(UINT32_MAX - 1), experiment.GetModuleFastDirectionStep(module_number_abs), experiment.GetPixel0OfModule(module_number_abs)); } } } void FrameTransformation::ProcessModule(const DeviceOutput *output, int data_stream) { ProcessModule(output->pixels, output->module_statistics.module_number, data_stream); } const void *FrameTransformation::GetImage() const { return precompression_buffer.data(); } void FrameTransformation::FillNotCollectedModule(uint16_t module_number, int data_stream) { ProcessModule(err_value.data(), module_number, data_stream); } int64_t FrameTransformation::CalculateROISum(const ROIRectangle &input) { if ((input.x_min > input.x_max) || (input.y_min > input.y_max)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in min/max ROI size"); if ((input.x_max >= experiment.GetXPixelsNum()) || (input.y_max >= experiment.GetYPixelsNum())) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Max pixel value for ROI sum outside of the detector range"); if (pixel_depth == 2) { if (pixel_signed) return calc_roi(precompression_buffer.data(), experiment.GetXPixelsNum(), input, INT16_MIN + 1, INT16_MAX - 1); else return calc_roi(precompression_buffer.data(), experiment.GetXPixelsNum(), input, 0, UINT16_MAX - 2); } else if (pixel_depth == 4) { if (pixel_signed) return calc_roi(precompression_buffer.data(), experiment.GetXPixelsNum(), input, INT32_MIN + 1, INT32_MAX - 1); else return calc_roi(precompression_buffer.data(), experiment.GetXPixelsNum(), input, 0, UINT32_MAX - 2); } else return 0; }