jfjoch_viewer: Track top-pixels without storing/sorting all valid pixels
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
#include "JFJochDecompress.h"
|
||||
#include "../image_analysis/bragg_integration/BraggIntegrate2D.h"
|
||||
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
|
||||
JFJochReaderImage::JFJochReaderImage(const DataMessage &in_message,
|
||||
const std::shared_ptr<const JFJochReaderDataset> &in_dataset)
|
||||
: message(in_message),
|
||||
@@ -72,11 +75,22 @@ void JFJochReaderImage::ProcessInputImage(const void *data, size_t npixel, int64
|
||||
|
||||
const T* img_ptr = reinterpret_cast<const T*>(data);
|
||||
|
||||
size_t good_pixel = 0;
|
||||
// Reset per-image stats
|
||||
saturated_pixel.clear();
|
||||
error_pixel.clear();
|
||||
valid_count = 0;
|
||||
has_valid = false;
|
||||
|
||||
valid_pixel.reserve(image.size());
|
||||
top_pixels_acc.Clear();
|
||||
top_pixels.clear();
|
||||
top_pixels.reserve(top_pixels_acc.Capacity());
|
||||
|
||||
for (int i = 0; i < npixel; i++) {
|
||||
bool has_input_mask = false;
|
||||
const auto &mask = dataset->pixel_mask.GetMask();
|
||||
if (mask.size() == npixel)
|
||||
has_input_mask = true;
|
||||
|
||||
for (size_t i = 0; i < npixel; i++) {
|
||||
int32_t val;
|
||||
if (img_ptr[i] <= INT32_MAX)
|
||||
val = static_cast<int32_t>(img_ptr[i]);
|
||||
@@ -84,44 +98,61 @@ void JFJochReaderImage::ProcessInputImage(const void *data, size_t npixel, int64
|
||||
val = INT32_MAX;
|
||||
|
||||
uint32_t mask_val = 0;
|
||||
if (!dataset->pixel_mask.GetMask().empty())
|
||||
mask_val = dataset->pixel_mask.GetMask().at(i);
|
||||
if (has_input_mask)
|
||||
mask_val = mask[i];
|
||||
|
||||
if ((mask_val & (
|
||||
(1<<PixelMask::ModuleGapPixelBit)
|
||||
| (1<<PixelMask::ChipGapPixelBit)
|
||||
| (1<<PixelMask::ModuleEdgePixelBit))) != 0) {
|
||||
image[i] = GAP_PXL_VALUE;
|
||||
} else if ((mask_val != 0) || (img_ptr[i] == special_value)){
|
||||
} else if ((mask_val != 0) || (img_ptr[i] == special_value)) {
|
||||
image[i] = ERROR_PXL_VALUE;
|
||||
error_pixel.emplace(i);
|
||||
error_pixel.emplace(static_cast<int64_t>(i));
|
||||
} else if (val >= sat_value) {
|
||||
image[i] = SATURATED_PXL_VALUE;
|
||||
saturated_pixel.emplace(i);
|
||||
saturated_pixel.emplace(static_cast<int64_t>(i));
|
||||
} else {
|
||||
good_pixel++;
|
||||
image[i] = val;
|
||||
valid_pixel.emplace_back(std::make_pair(val, i));
|
||||
|
||||
if (!has_valid) {
|
||||
has_valid = true;
|
||||
valid_min = val;
|
||||
valid_max = val;
|
||||
} else {
|
||||
valid_min = std::min(valid_min, val);
|
||||
valid_max = std::max(valid_max, val);
|
||||
}
|
||||
valid_count++;
|
||||
|
||||
top_pixels_acc.Add(val, static_cast<int32_t>(i));
|
||||
}
|
||||
}
|
||||
// Sort based on the first element only
|
||||
std::sort(valid_pixel.begin(), valid_pixel.end(),
|
||||
[](const auto& a, const auto& b) {return a.first < b.first;});
|
||||
|
||||
CalcAutoContrast();
|
||||
// For now: auto-foreground based purely on max valid element
|
||||
auto_foreground = has_valid ? std::max(1, valid_max) : 10;
|
||||
|
||||
// Export top pixels (already sorted descending) into the existing vector interface
|
||||
for (int i = 0; i < top_pixels_acc.Size(); i++) {
|
||||
const auto &e = top_pixels_acc[i];
|
||||
top_pixels.emplace_back(e.value, e.index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JFJochReaderImage::CalcAutoContrast() {
|
||||
if (valid_pixel.empty())
|
||||
auto_foreground = 10;
|
||||
else {
|
||||
auto it = valid_pixel.crbegin();
|
||||
const auto index = static_cast<size_t>(valid_pixel.size() * auto_foreground_range);
|
||||
std::advance(it, std::max<size_t>(1ULL, index) - 1);
|
||||
// Now simplified: based on max element (valid_max)
|
||||
auto_foreground = has_valid ? std::max(1, valid_max) : 10;
|
||||
}
|
||||
|
||||
auto_foreground = std::max(1, it->first);
|
||||
}
|
||||
std::optional<std::pair<int32_t, int32_t>> JFJochReaderImage::ValidMinMax() const {
|
||||
if (!has_valid)
|
||||
return {};
|
||||
return std::make_pair(valid_min, valid_max);
|
||||
}
|
||||
|
||||
const std::vector<std::pair<int32_t, int32_t>> &JFJochReaderImage::GetTopPixels() const {
|
||||
return top_pixels;
|
||||
}
|
||||
|
||||
const DataMessage &JFJochReaderImage::ImageData() const {
|
||||
@@ -144,10 +175,6 @@ const std::unordered_set<int64_t> &JFJochReaderImage::ErrorPixels() const {
|
||||
return error_pixel;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<int32_t, int32_t>> &JFJochReaderImage::ValidPixels() const {
|
||||
return valid_pixel;
|
||||
}
|
||||
|
||||
const JFJochReaderDataset &JFJochReaderImage::Dataset() const {
|
||||
if (!dataset)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
@@ -167,37 +194,56 @@ void JFJochReaderImage::AddImage(const JFJochReaderImage &other) {
|
||||
|
||||
error_pixel.clear();
|
||||
saturated_pixel.clear();
|
||||
valid_pixel.clear();
|
||||
valid_pixel.reserve(image.size());
|
||||
for (int i = 0; i < image.size(); i++) {
|
||||
if (image[i] == GAP_PXL_VALUE || other.image[i] == GAP_PXL_VALUE)
|
||||
valid_count = 0;
|
||||
has_valid = false;
|
||||
|
||||
top_pixels_acc.Clear();
|
||||
top_pixels.clear();
|
||||
top_pixels.reserve(top_pixels_acc.Capacity());
|
||||
|
||||
for (size_t i = 0; i < image.size(); i++) {
|
||||
if (image[i] == GAP_PXL_VALUE || other.image[i] == GAP_PXL_VALUE) {
|
||||
image[i] = GAP_PXL_VALUE;
|
||||
else if (image[i] == ERROR_PXL_VALUE || other.image[i] == ERROR_PXL_VALUE) {
|
||||
} else if (image[i] == ERROR_PXL_VALUE || other.image[i] == ERROR_PXL_VALUE) {
|
||||
image[i] = ERROR_PXL_VALUE;
|
||||
error_pixel.emplace(i);
|
||||
error_pixel.emplace(static_cast<int64_t>(i));
|
||||
} else if (image[i] == SATURATED_PXL_VALUE || other.image[i] == SATURATED_PXL_VALUE) {
|
||||
image[i] = SATURATED_PXL_VALUE;
|
||||
saturated_pixel.emplace(i);
|
||||
saturated_pixel.emplace(static_cast<int64_t>(i));
|
||||
} else {
|
||||
int64_t sum = static_cast<int64_t>(image[i]) + static_cast<int64_t>(other.image[i]);
|
||||
if (sum <= INT32_MIN + 5) [[unlikely]] {
|
||||
image[i] = ERROR_PXL_VALUE;
|
||||
error_pixel.emplace(i);
|
||||
error_pixel.emplace(static_cast<int64_t>(i));
|
||||
} else if (sum > dataset->experiment.GetSaturationLimit()) [[unlikely]] {
|
||||
image[i] = SATURATED_PXL_VALUE;
|
||||
saturated_pixel.emplace(i);
|
||||
saturated_pixel.emplace(static_cast<int64_t>(i));
|
||||
} else {
|
||||
image[i] = static_cast<int32_t>(sum);
|
||||
valid_pixel.emplace_back(std::make_pair(sum, i));
|
||||
const int32_t val = static_cast<int32_t>(sum);
|
||||
image[i] = val;
|
||||
|
||||
if (!has_valid) {
|
||||
has_valid = true;
|
||||
valid_min = val;
|
||||
valid_max = val;
|
||||
} else {
|
||||
valid_min = std::min(valid_min, val);
|
||||
valid_max = std::max(valid_max, val);
|
||||
}
|
||||
valid_count++;
|
||||
|
||||
top_pixels_acc.Add(val, static_cast<int32_t>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort based on the first element only
|
||||
std::sort(valid_pixel.begin(), valid_pixel.end(),
|
||||
[](const auto& a, const auto& b) { return a.first < b.first; });
|
||||
// For now: auto-foreground based purely on max valid element
|
||||
auto_foreground = has_valid ? std::max(1, valid_max) : 10;
|
||||
|
||||
CalcAutoContrast();
|
||||
for (int i = 0; i < top_pixels_acc.Size(); i++) {
|
||||
const auto &e = top_pixels_acc[i];
|
||||
top_pixels.emplace_back(e.value, e.index);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> JFJochReaderImage::GetAzInt1D() const {
|
||||
|
||||
Reference in New Issue
Block a user