PreviewImage: remove mutex

This commit is contained in:
2024-05-23 22:58:52 +02:00
parent 500222bdcc
commit f85b87bfd2
10 changed files with 181 additions and 139 deletions

View File

@@ -31,28 +31,7 @@ constexpr const static rgb plotly[] = {{0x1f, 0x77, 0xb4},
constexpr const static rgb indigo = {.r = 0x3f, .g = 0x51, .b = 0xb5};
constexpr const static rgb gray = {.r = 0xbe, .g = 0xbe, .b = 0xbe};
PreviewImage::PreviewImage(const DiffractionExperiment &in_experiment) :
experiment(in_experiment),
initialized(false),
xpixel(experiment.GetXPixelsNum()),
ypixel(experiment.GetYPixelsNum()),
beam_x(experiment.GetBeamX_pxl()),
beam_y(experiment.GetBeamY_pxl()),
pixel_depth_bytes(experiment.GetPixelDepth()),
pixel_is_signed(experiment.IsPixelSigned()),
uncompressed_image(experiment.GetPixelsNum() * experiment.GetPixelDepth()),
roi_map(experiment.ROI()),
counter(experiment.GetPreviewPeriod()) {}
void PreviewImage::UpdateImage(const void *in_uncompressed_image,
const std::vector<SpotToSave> &in_spots) {
if (counter.GeneratePreview()) {
std::unique_lock<std::mutex> ul(m);
initialized = true;
memcpy(uncompressed_image.data(), in_uncompressed_image, xpixel * ypixel * pixel_depth_bytes);
spots = in_spots;
}
}
PreviewImage::PreviewImage(std::chrono::microseconds period) : counter(period) {}
void colormap(std::vector<unsigned char>& ret, float v, size_t pixel) {
if ((v < 0.0) || (v > 1.0)) {
@@ -106,55 +85,6 @@ std::vector<unsigned char> GenerateRGB(const T* value, size_t npixel, uint32_t s
return ret;
}
std::string PreviewImage::GenerateJPEG(const PreviewJPEGSettings &settings) const {
std::vector<unsigned char> v;
{
// JPEG compression is outside the critical loop protected by m
std::unique_lock<std::mutex> ul(m);
if (!initialized)
return {};
if (!pixel_is_signed) {
if (pixel_depth_bytes == 2)
v = GenerateRGB<uint16_t>((uint16_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, UINT16_MAX);
else
v = GenerateRGB<uint32_t>((uint32_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, UINT32_MAX);
} else {
if (pixel_depth_bytes == 2)
v = GenerateRGB<int16_t>((int16_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, INT16_MIN);
else
v = GenerateRGB<int32_t>((int32_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, INT32_MIN);
}
if (settings.show_spots)
AddSpots(v);
}
if (settings.show_roi)
AddROI(v);
if (settings.resolution_ring)
AddResolutionRing(v, settings.resolution_ring.value());
AddBeamCenter(v);
return WriteJPEGToMem(v, xpixel, ypixel, settings.jpeg_quality);
}
std::string PreviewImage::GenerateTIFF() const {
std::unique_lock<std::mutex> ul(m);
if (!initialized)
return {};
std::string s = WriteTIFFToString(const_cast<uint8_t *>(uncompressed_image.data()),
xpixel, ypixel, pixel_depth_bytes, pixel_is_signed);
return s;
}
template <class T>
std::vector<uint16_t> GenerateDioptasPreview(const void* input, size_t xpixel, size_t ypixel, T special_value) {
auto input_ptr = (T *) input;
@@ -174,26 +104,6 @@ std::vector<uint16_t> GenerateDioptasPreview(const void* input, size_t xpixel, s
return vec;
}
std::string PreviewImage::GenerateTIFFDioptas() const {
std::unique_lock<std::mutex> ul(m);
if (!initialized)
return {};
std::vector<uint16_t> vec;
if (pixel_is_signed) {
if (pixel_depth_bytes == 2)
vec = GenerateDioptasPreview<int16_t>(uncompressed_image.data(), xpixel, ypixel, INT16_MIN);
else
vec = GenerateDioptasPreview<int32_t>(uncompressed_image.data(), xpixel, ypixel, INT32_MIN);
} else {
if (pixel_depth_bytes == 2)
vec = GenerateDioptasPreview<uint16_t>(uncompressed_image.data(), xpixel, ypixel, UINT16_MAX);
else
vec = GenerateDioptasPreview<uint32_t>(uncompressed_image.data(), xpixel, ypixel, UINT32_MAX);
}
return WriteTIFFToString(vec.data(), xpixel, ypixel, 2, false);
}
void PreviewImage::AddBeamCenter(std::vector<uint8_t> &rgb_image) const {
size_t beam_x_int = std::lround(beam_x);
size_t beam_y_int = std::lround(beam_y);
@@ -230,7 +140,7 @@ void PreviewImage::AddSpots(std::vector<uint8_t> &rgb_image) const {
void PreviewImage::AddROI(std::vector<uint8_t> &rgb_image) const {
int64_t roi_counter = 0;
for (const auto &box: roi_map.GetROIBox()) {
for (const auto &box: experiment.ROI().GetROIBox()) {
int rectangle_width = 5;
for (auto x = box.GetXMin() - rectangle_width; x <= box.GetXMax() + rectangle_width; x++) {
@@ -249,7 +159,7 @@ void PreviewImage::AddROI(std::vector<uint8_t> &rgb_image) const {
roi_counter++;
}
for (const auto &circle: roi_map.GetROICircle()) {
for (const auto &circle: experiment.ROI().GetROICircle()) {
int width = 5;
for (int64_t y = std::floor(circle.GetY() - circle.GetRadius_pxl() - width);
@@ -281,3 +191,116 @@ void PreviewImage::AddResolutionRing(std::vector<uint8_t> &rgb_image, float d) c
}
}
}
void PreviewImage::Configure(const DiffractionExperiment &in_experiment) {
std::unique_lock<std::mutex> ul(m);
experiment = in_experiment;
initialized = false;
xpixel = experiment.GetXPixelsNum();
ypixel = experiment.GetYPixelsNum();
beam_x = experiment.GetBeamX_pxl();
beam_y = experiment.GetBeamY_pxl();
pixel_depth_bytes = experiment.GetPixelDepth();
pixel_is_signed = experiment.IsPixelSigned();
uncompressed_image.resize(experiment.GetPixelsNum() * experiment.GetPixelDepth());
memset(uncompressed_image.data(), 0, experiment.GetPixelsNum() * experiment.GetPixelDepth());
}
void PreviewImage::Configure() {
std::unique_lock<std::mutex> ul(m);
initialized = false;
xpixel = 0;
ypixel = 0;
}
void PreviewImage::UpdateImage(const void *in_uncompressed_image,
const std::vector<SpotToSave> &in_spots) {
if (counter.GeneratePreview()) {
std::unique_lock<std::mutex> ul(m);
if (xpixel * ypixel == 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Preview not configured");
initialized = true;
memcpy(uncompressed_image.data(), in_uncompressed_image, xpixel * ypixel * pixel_depth_bytes);
spots = in_spots;
}
}
std::string PreviewImage::GenerateJPEG(const PreviewJPEGSettings &settings) const {
std::vector<unsigned char> v;
size_t local_xpixel;
size_t local_ypixel;
{
// JPEG compression is outside the critical loop protected by m
std::unique_lock<std::mutex> ul(m);
local_xpixel = xpixel;
local_ypixel = ypixel;
if (!initialized)
return {};
if (!pixel_is_signed) {
if (pixel_depth_bytes == 2)
v = GenerateRGB<uint16_t>((uint16_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, UINT16_MAX);
else
v = GenerateRGB<uint32_t>((uint32_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, UINT32_MAX);
} else {
if (pixel_depth_bytes == 2)
v = GenerateRGB<int16_t>((int16_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, INT16_MIN);
else
v = GenerateRGB<int32_t>((int32_t *) uncompressed_image.data(), xpixel * ypixel,
settings.saturation_value, INT32_MIN);
}
if (settings.show_spots)
AddSpots(v);
if (settings.show_roi)
AddROI(v);
if (settings.resolution_ring)
AddResolutionRing(v, settings.resolution_ring.value());
AddBeamCenter(v);
}
return WriteJPEGToMem(v, local_xpixel, local_ypixel, settings.jpeg_quality);
}
std::string PreviewImage::GenerateTIFF() const {
std::unique_lock<std::mutex> ul(m);
if (!initialized)
return {};
std::string s = WriteTIFFToString(const_cast<uint8_t *>(uncompressed_image.data()),
xpixel, ypixel, pixel_depth_bytes, pixel_is_signed);
return s;
}
std::string PreviewImage::GenerateTIFFDioptas() const {
std::unique_lock<std::mutex> ul(m);
if (!initialized)
return {};
std::vector<uint16_t> vec;
if (pixel_is_signed) {
if (pixel_depth_bytes == 2)
vec = GenerateDioptasPreview<int16_t>(uncompressed_image.data(), xpixel, ypixel, INT16_MIN);
else
vec = GenerateDioptasPreview<int32_t>(uncompressed_image.data(), xpixel, ypixel, INT32_MIN);
} else {
if (pixel_depth_bytes == 2)
vec = GenerateDioptasPreview<uint16_t>(uncompressed_image.data(), xpixel, ypixel, UINT16_MAX);
else
vec = GenerateDioptasPreview<uint32_t>(uncompressed_image.data(), xpixel, ypixel, UINT32_MAX);
}
return WriteTIFFToString(vec.data(), xpixel, ypixel, 2, false);
}

View File

@@ -29,16 +29,15 @@ class PreviewImage {
mutable std::mutex m;
DiffractionExperiment experiment;
bool initialized;
const ROIMap roi_map;
bool initialized = false;
std::vector<uint8_t> uncompressed_image;
std::vector<SpotToSave> spots;
size_t xpixel;
size_t ypixel;
size_t pixel_depth_bytes;
bool pixel_is_signed;
float beam_x;
float beam_y;
size_t xpixel = 0;
size_t ypixel = 0;
size_t pixel_depth_bytes = 2;
bool pixel_is_signed = false;
float beam_x = 0;
float beam_y = 0;
void AddResolutionRing(std::vector<uint8_t> &rgb_image, float d) const;
void AddBeamCenter(std::vector<uint8_t> &rgb_image) const;
@@ -52,7 +51,9 @@ class PreviewImage {
void beam_center_mark(std::vector<unsigned char>& ret, int64_t xpixel, int64_t ypixel) const;
public:
explicit PreviewImage(const DiffractionExperiment& experiment);
explicit PreviewImage(std::chrono::microseconds period = std::chrono::seconds(1));
void Configure(const DiffractionExperiment& experiment);
void Configure();
void UpdateImage(const void *uncompressed_image, const std::vector<SpotToSave> &spots);
[[nodiscard]] std::string GenerateJPEG(const PreviewJPEGSettings& settings) const;
[[nodiscard]] std::string GenerateTIFF() const;

View File

@@ -17,6 +17,8 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment& in_experiment,
Logger &in_logger, int64_t in_forward_and_sum_nthreads,
const NUMAHWPolicy &in_numa_policy,
const SpotFindingSettings &in_spot_finding_settings,
PreviewImage &in_preview_image,
PreviewImage &in_preview_image_indexed,
SendBuffer &buf) :
experiment(in_experiment),
calibration(nullptr),
@@ -33,8 +35,8 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment& in_experiment,
az_int_mapping(experiment),
plots(experiment, az_int_mapping),
spot_finding_settings(in_spot_finding_settings),
preview_image(experiment),
preview_image_indexed(experiment),
preview_image(in_preview_image),
preview_image_indexed(in_preview_image_indexed),
serialmx_filter(experiment)
{
if (experiment.GetDetectorSetup().GetDetectorType() == DetectorType::JUNGFRAU)
@@ -573,20 +575,6 @@ JFJochReceiverStatus JFJochReceiver::GetStatus() const {
return ret;
}
std::string JFJochReceiver::GetTIFF(bool calibration_run) const {
if (calibration_run)
return preview_image.GenerateTIFFDioptas();
else
return preview_image.GenerateTIFF();
}
std::string JFJochReceiver::GetJPEG(const PreviewJPEGSettings &settings) const {
if (settings.show_indexed)
return preview_image_indexed.GenerateJPEG(settings);
else
return preview_image.GenerateJPEG(settings);
}
void JFJochReceiver::GetXFELEventCode(std::vector<uint64_t> &v) const {
if (experiment.IsPulsedSource())
plots.GetXFELEventCode(v);

View File

@@ -108,8 +108,8 @@ class JFJochReceiver {
NUMAHWPolicy numa_policy;
PreviewImage preview_image;
PreviewImage preview_image_indexed;
PreviewImage &preview_image;
PreviewImage &preview_image_indexed;
LossyFilter serialmx_filter;
@@ -131,6 +131,8 @@ public:
Logger &logger, int64_t forward_and_sum_nthreads,
const NUMAHWPolicy &numa_policy,
const SpotFindingSettings &spot_finding_settings,
PreviewImage &preview_image,
PreviewImage &preview_image_indexed,
SendBuffer &buffer);
~JFJochReceiver();
JFJochReceiver(const JFJochReceiver &other) = delete;
@@ -148,9 +150,6 @@ public:
MultiLinePlot GetPlots(const PlotRequest& request);
std::string GetTIFF(bool calibration) const;
std::string GetJPEG(const PreviewJPEGSettings &settings) const;
void GetXFELEventCode(std::vector<uint64_t> &v) const;
void GetXFELPulseID(std::vector<uint64_t> &v) const;
};

View File

@@ -25,7 +25,6 @@ class JFJochReceiverPlots {
StatusVector<uint64_t> receiver_delay;
StatusVector<uint64_t> receiver_free_send_buf;
StatusVector<float> image_collection_efficiency;
StatusVector<float> unit_cell[6];
SetAverage<uint64_t> indexing_solution_per_time_point;
std::map<std::string, std::unique_ptr<StatusVector<int64_t>>> roi_sum;

View File

@@ -51,12 +51,17 @@ void JFJochReceiverService::Start(const DiffractionExperiment &experiment, const
throw JFJochException(JFJochExceptionCategory::WrongDAQState, "Receiver not idle, cannot start");
try {
preview_image.Configure(experiment);
preview_image_indexed.Configure(experiment);
// Thanks to properties of unique_ptr, starting new measurement will call destructor of JFJochReceiver, which will
// ensure that everything was rolled back
receiver = std::make_unique<JFJochReceiver>(experiment, calibration,
aq_devices, image_pusher,
logger, nthreads, numa_policy,
spot_finding_settings,
preview_image,
preview_image_indexed,
buffer);
try {
// Don't want to stop
@@ -128,19 +133,17 @@ std::vector<AcquisitionDeviceNetConfig> JFJochReceiverService::GetNetworkConfig(
}
std::string JFJochReceiverService::GetTIFF(bool calibration) const {
std::unique_lock ul(state_mutex);
if (receiver)
return receiver->GetTIFF(calibration);
if (calibration)
return preview_image.GenerateTIFFDioptas();
else
return "";
return preview_image.GenerateTIFF();
}
std::string JFJochReceiverService::GetJPEG(const PreviewJPEGSettings &settings) const {
std::unique_lock ul(state_mutex);
if (receiver)
return receiver->GetJPEG(settings);
if (settings.show_indexed)
return preview_image_indexed.GenerateJPEG(settings);
else
return "";
return preview_image.GenerateJPEG(settings);
}
void JFJochReceiverService::LoadInternalGeneratorImage(const DiffractionExperiment &experiment,

View File

@@ -25,6 +25,9 @@ class JFJochReceiverService {
std::future<void> measurement;
void FinalizeMeasurement();
SpotFindingSettings spot_finding_settings;
PreviewImage preview_image;
PreviewImage preview_image_indexed;
public:
JFJochReceiverService(AcquisitionDeviceGroup &aq_devices,
Logger &logger,

View File

@@ -24,7 +24,19 @@ TEST_CASE("JPEGTest","[JPEG]") {
f.write(s.data(), s.size());
}
TEST_CASE("PreviewImage_NotConfigured","[JPEG]") {
std::vector<int16_t> image_conv_2(67878);
std::vector<SpotToSave> spots;
PreviewImage image;
REQUIRE_THROWS(image.UpdateImage(image_conv_2.data(), spots));
REQUIRE(image.GenerateJPEG(PreviewJPEGSettings()).empty());
}
TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") {
RegisterHDF5Filter();
DiffractionExperiment experiment(DetectorGeometry(8,2,8,36));
experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true)
.FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false)
@@ -57,7 +69,8 @@ TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") {
{.x = 800, .y = 1000, .indexed = false},
{.x = 1200, .y = 500, .indexed = true}
};
PreviewImage image(experiment);
PreviewImage image;
image.Configure(experiment);
PreviewJPEGSettings preview_settings{
.saturation_value = 5,
@@ -69,7 +82,6 @@ TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") {
image.UpdateImage(image_conv_2.data(), spots);
std::string s;
REQUIRE_NOTHROW(s = image.GenerateJPEG(preview_settings));
std::ofstream f("lyso_diff.jpeg", std::ios::binary);
@@ -77,6 +89,8 @@ TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") {
}
TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") {
RegisterHDF5Filter();
DiffractionExperiment experiment(DetectorGeometry(8,2,8,36));
experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true)
.FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false)
@@ -111,7 +125,8 @@ TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") {
{.x = 800, .y = 1000, .indexed = false},
{.x = 1200, .y = 500, .indexed = true}
};
PreviewImage image(experiment);
PreviewImage image;
image.Configure(experiment);
image.UpdateImage(image_conv_2.data(), spots);
PreviewJPEGSettings preview_settings{
@@ -128,6 +143,8 @@ TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") {
}
TEST_CASE("PreviewImage_GenerateJPEG_resolution","[JPEG]") {
RegisterHDF5Filter();
DiffractionExperiment experiment(DetectorGeometry(8,2,8,36));
experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true)
.FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false)
@@ -153,7 +170,8 @@ TEST_CASE("PreviewImage_GenerateJPEG_resolution","[JPEG]") {
RawToConvertedGeometry(experiment, image_conv_2.data(), image_raw_geom.data());
std::vector<SpotToSave> spots = {};
PreviewImage image(experiment);
PreviewImage image;
image.Configure(experiment);
image.UpdateImage(image_conv_2.data(), spots);
PreviewJPEGSettings preview_settings{

View File

@@ -33,6 +33,8 @@ TEST_CASE("TIFFTest_File_signed","[TIFF]") {
}
TEST_CASE("PreviewImage_GenerateTIFF","[TIFF]") {
RegisterHDF5Filter();
DiffractionExperiment experiment(DetectorGeometry(8,2,8,36));
experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true)
.FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false)
@@ -58,7 +60,8 @@ TEST_CASE("PreviewImage_GenerateTIFF","[TIFF]") {
RawToConvertedGeometry(experiment, image_conv_2.data(), image_raw_geom.data());
std::vector<SpotToSave> spots;
PreviewImage image(experiment);
PreviewImage image;
image.Configure(experiment);
image.UpdateImage(image_conv_2.data(), spots);
std::string s;
@@ -69,6 +72,8 @@ TEST_CASE("PreviewImage_GenerateTIFF","[TIFF]") {
TEST_CASE("PreviewImage_GenerateTIFFDioptas","[TIFF]") {
RegisterHDF5Filter();
DiffractionExperiment experiment(DetectorGeometry(8,2,8,36));
experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true)
.FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false)
@@ -94,7 +99,8 @@ TEST_CASE("PreviewImage_GenerateTIFFDioptas","[TIFF]") {
RawToConvertedGeometry(experiment, image_conv_2.data(), image_raw_geom.data());
std::vector<SpotToSave> spots;
PreviewImage image(experiment);
PreviewImage image;
image.Configure(experiment);
image.UpdateImage(image_conv_2.data(), spots);
std::string s;

View File

@@ -209,7 +209,9 @@ int main(int argc, char **argv) {
MXAnalyzer analyzer(x);
PreviewImage preview(x);
PreviewImage preview;
preview.Configure(x);
uint64_t indexed_images = 0;
LossyFilter filter(x);