Preview improvements

This commit is contained in:
2024-05-02 17:16:23 +02:00
parent 0cf7886821
commit ca54d66841
4 changed files with 108 additions and 94 deletions
+1 -1
View File
@@ -154,7 +154,7 @@ std::string JFJochServices::GetPreviewJPEG(const PreviewJPEGSettings &settings)
if (receiver != nullptr)
return receiver->GetJPEG(settings);
else
return PreviewImage::GenerateTestJPEG(settings);
return {};
}
std::string JFJochServices::GetPreviewTIFF(bool calibration) const {
+91 -90
View File
@@ -8,6 +8,28 @@
#include "WriteTIFF.h"
#include "../common/JFJochException.h"
constexpr const static rgb lime = {.r = 0xcd, .g = 0xdc, .b = 0x39};
constexpr const static rgb pink = {.r = 0xe9, .g = 0x1e, .b = 0x63};
constexpr const static rgb purple = {.r = 0x7b, .g = 0x1f, .b = 0xA2};
constexpr const static rgb orange = {.r = 0xff, .g = 0x57, .b = 0x22};
constexpr const static rgb amber = {.r =0xff, .g = 0xc1, .b = 0x07};
constexpr const static rgb blue = {.r = 0x0d, .g = 0x47, .b = 0xa1};
constexpr const static rgb plotly[] = {{0x1f, 0x77, 0xb4},
{0xff, 0x7f, 0x0e},
{0x2c, 0xa0, 0x2c},
{0xd6, 0x27, 0x28},
{0x94, 0x67, 0xbd},
{0x8c, 0x56, 0x4b},
{0xe3, 0x77, 0xc2},
{0x7f, 0x7f, 0x7f},
{0xbd, 0xbd, 0x22},
{0x17, 0xbe, 0xcf}};
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 &experiment) :
xpixel(experiment.GetXPixelsNum()),
ypixel(experiment.GetYPixelsNum()),
@@ -16,7 +38,7 @@ PreviewImage::PreviewImage(const DiffractionExperiment &experiment) :
pixel_depth_bytes(experiment.GetPixelDepth()),
pixel_is_signed(experiment.IsPixelSigned()),
uncompressed_image(experiment.GetPixelsNum() * experiment.GetPixelDepth()),
roi_mask(experiment.ROI().GetROIMap()),
roi_map(experiment.ROI()),
counter(experiment.GetPreviewPeriod()) {}
void PreviewImage::UpdateImage(const void *in_uncompressed_image,
@@ -28,46 +50,40 @@ void PreviewImage::UpdateImage(const void *in_uncompressed_image,
}
}
#define JFJOCH_JPEG_BASE_R (0x3f)
#define JFJOCH_JPEG_BASE_G (0x51)
#define JFJOCH_JPEG_BASE_B (0xb5)
void colormap(std::vector<unsigned char>& ret, float v, size_t pixel) {
if ((v < 0.0) || (v > 1.0)) {
ret[pixel * 3] = 0xBE;
ret[pixel * 3+1] = 0xBE;
ret[pixel * 3+2] = 0xBE;
ret[pixel * 3] = gray.r;
ret[pixel * 3+1] = gray.g;
ret[pixel * 3+2] = gray.b;
} else {
ret[pixel * 3] = 255 - std::lround((255-JFJOCH_JPEG_BASE_R) * v);
ret[pixel * 3 + 1] = 255 - std::lround((255-JFJOCH_JPEG_BASE_G) * v);
ret[pixel * 3 + 2] = 255 - std::lround((255-JFJOCH_JPEG_BASE_B) * v);
ret[pixel * 3] = 255 - std::lround((255-indigo.r) * v);
ret[pixel * 3 + 1] = 255 - std::lround((255-indigo.g) * v);
ret[pixel * 3 + 2] = 255 - std::lround((255-indigo.b) * v);
}
}
void roi(std::vector<unsigned char>& ret, size_t pixel) {
ret[pixel * 3] = 0x7B;
ret[pixel * 3+1] = 0x1F;
ret[pixel * 3+2] = 0xA2;
}
void feature(std::vector<unsigned char>& ret, size_t pixel) {
ret[pixel * 3] = 0xE9;
ret[pixel * 3+1] = 0x1E;
ret[pixel * 3+2] = 0x63;
}
void spot(std::vector<unsigned char>& ret, int64_t pixel, bool indexed) {
if (indexed) {
ret[pixel * 3] = 0xE9;
ret[pixel * 3 + 1] = 0x1E;
ret[pixel * 3 + 2] = 0x63;
} else {
ret[pixel * 3] = 0xCD;
ret[pixel * 3 + 1] = 0xDC;
ret[pixel * 3 + 2] = 0x39;
void PreviewImage::color_pixel(std::vector<unsigned char> &ret, int64_t in_xpixel, int64_t in_ypixel,const rgb &color) const {
if ((in_xpixel >= 0) && (in_xpixel < xpixel) && (in_ypixel >= 0) && (in_ypixel < ypixel)) {
ret[(in_ypixel * xpixel + in_xpixel) * 3] = color.r;
ret[(in_ypixel * xpixel + in_xpixel) * 3 + 1] = color.g;
ret[(in_ypixel * xpixel + in_xpixel) * 3 + 2] = color.b;
}
}
void PreviewImage::spot(std::vector<unsigned char> &ret, int64_t in_xpixel, int64_t in_ypixel, bool indexed) const {
if (indexed)
color_pixel(ret, in_xpixel, in_ypixel, pink);
else
color_pixel(ret, in_xpixel, in_ypixel, amber);
}
void PreviewImage::roi(std::vector<unsigned char> &ret, int64_t in_xpixel, int64_t in_ypixel, int64_t roi_number) const {
color_pixel(ret, in_xpixel, in_ypixel, plotly[roi_number % 10]);
}
void PreviewImage::beam_center_mark(std::vector<unsigned char> &ret, int64_t in_xpixel, int64_t in_ypixel) const {
color_pixel(ret, in_xpixel, in_ypixel, lime);
}
template<class T>
std::vector<unsigned char> GenerateRGB(const T* value, size_t npixel, uint32_t saturation_value, T special_value) {
@@ -162,45 +178,6 @@ std::string PreviewImage::GenerateTIFFDioptas() const {
return WriteTIFFToString(vec.data(), xpixel, ypixel, 2, false);
}
std::string PreviewImage::GenerateTestJPEG(const PreviewJPEGSettings &settings) {
std::vector<unsigned char> v;
size_t xpixel = 1030 * 3 + 2 * 8;
size_t ypixel = 514 * 6 + 5 * 36;
std::vector<int16_t> uncompressed_image(xpixel * ypixel, 5);
for (int y = 0; y < ypixel; y++) {
for (int gap = 1; gap <= 2; gap++) {
for (int pixel = 0; pixel < 8; pixel++)
uncompressed_image[y * xpixel + 1030 * gap + 8 * (gap - 1) + pixel] = INT16_MIN;
}
}
for (int gap = 1; gap <= 5; gap++) {
for (int pixel = 0; pixel < 36; pixel++) {
for (int x = 0; x < xpixel; x++)
uncompressed_image[(gap * 514 + 36 * (gap - 1) + pixel) * xpixel + x] = INT16_MIN;
}
}
v = GenerateRGB<int16_t>((int16_t *) uncompressed_image.data(), xpixel * ypixel, settings.saturation_value,
INT16_MIN);
size_t beam_x_int = std::lround(1200);
size_t beam_y_int = std::lround(800);
int crosshair_size = 30;
int crosshair_width = 3;
for (int w = -crosshair_width; w < crosshair_width; w++) {
for (int i = -crosshair_size; i < crosshair_size; i++) {
feature(v, (beam_y_int + w) * xpixel + beam_x_int + i);
feature(v, (beam_y_int + i) * xpixel + beam_x_int + w);
}
}
return WriteJPEGToMem(v, xpixel, ypixel, settings.jpeg_quality);
}
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);
@@ -209,10 +186,8 @@ void PreviewImage::AddBeamCenter(std::vector<uint8_t> &rgb_image) const {
int crosshair_width = 3;
for (int w = -crosshair_width; w <= crosshair_width; w++) {
for (int i = -crosshair_size; i <= crosshair_size; i++) {
if ((beam_y_int + w < ypixel) && (beam_x_int + i < xpixel))
feature(rgb_image, (beam_y_int + w) * xpixel + beam_x_int + i);
if ((beam_y_int + i < ypixel) && (beam_x_int + w < xpixel))
feature(rgb_image, (beam_y_int + i) * xpixel + beam_x_int + w);
beam_center_mark(rgb_image, beam_x_int + i, beam_y_int + w);
beam_center_mark(rgb_image, beam_x_int + w, beam_y_int + i);
}
}
}
@@ -225,29 +200,55 @@ void PreviewImage::AddSpots(std::vector<uint8_t> &rgb_image) const {
int rectangle_size = 4;
int rectangle_width = 3;
if ((spot_x_int - rectangle_width < 0)
|| (spot_x_int + rectangle_width >= xpixel)
|| (spot_y_int - rectangle_width < 0)
|| (spot_y_int + rectangle_width >= ypixel))
continue;
for (int z = rectangle_size; z < rectangle_size + rectangle_width; z++) {
for (int w = -z; w <= z; w++) {
spot(rgb_image, (spot_y_int + w) * xpixel + spot_x_int + z, s.indexed);
spot(rgb_image, (spot_y_int + w) * xpixel + spot_x_int - z, s.indexed);
spot(rgb_image, (spot_y_int + z) * xpixel + spot_x_int + w, s.indexed);
spot(rgb_image, (spot_y_int - z) * xpixel + spot_x_int - w, s.indexed);
spot(rgb_image, spot_x_int + z, spot_y_int + w, s.indexed);
spot(rgb_image, spot_x_int - z, spot_y_int + w, s.indexed);
spot(rgb_image, spot_x_int + w, spot_y_int + z, s.indexed);
spot(rgb_image, spot_x_int + w, spot_y_int - z, s.indexed);
}
}
}
}
void PreviewImage::AddROI(std::vector<uint8_t> &rgb_image) const {
if (rgb_image.size() != roi_mask.size() * 3)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in array size");
int64_t roi_counter = 0;
for (int i = 0; i < roi_mask.size(); i++) {
if (roi_mask[i] != UINT16_MAX)
roi(rgb_image, i);
for (const auto &box: roi_map.GetROIBox()) {
int rectangle_width = 5;
for (auto x = box.GetXMin() - rectangle_width; x <= box.GetXMax() + rectangle_width; x++) {
for (auto w = 1; w <= rectangle_width; w++) {
roi(rgb_image, x, box.GetYMax() + w, roi_counter);
roi(rgb_image, x, box.GetYMin() - w, roi_counter);
}
}
for (auto y = box.GetYMin() - rectangle_width; y <= box.GetYMax() + rectangle_width; y++) {
for (auto w = 1; w <= rectangle_width; w++) {
roi(rgb_image, box.GetXMax() + w, y, roi_counter);
roi(rgb_image, box.GetXMin() - w, y, roi_counter);
}
}
roi_counter++;
}
for (const auto &circle: roi_map.GetROICircle()) {
int width = 5;
for (int64_t y = std::floor(circle.GetY() - circle.GetRadius_pxl() - width);
y <= std::ceil(circle.GetY() + circle.GetRadius_pxl() + width);
y++) {
for (int64_t x = std::floor(circle.GetX() - circle.GetRadius_pxl() - width);
x <= std::ceil(circle.GetX() + circle.GetRadius_pxl() + width);
x++) {
float dist = sqrtf((x - circle.GetX()) * (x - circle.GetX())
+ (y - circle.GetY()) * (y - circle.GetY()));
if ((dist > circle.GetRadius_pxl()) && (dist < circle.GetRadius_pxl() + width))
roi(rgb_image, x, y, roi_counter);
}
}
roi_counter++;
}
}
+13 -2
View File
@@ -18,10 +18,16 @@ struct PreviewJPEGSettings {
bool show_indexed = false;
};
struct rgb {
unsigned char r;
unsigned char g;
unsigned char b;
};
class PreviewImage {
mutable std::mutex m;
std::vector<uint16_t> roi_mask;
const ROIMap roi_map;
std::vector<uint8_t> uncompressed_image;
std::vector<SpotToSave> spots;
size_t xpixel;
@@ -35,13 +41,18 @@ class PreviewImage {
void AddSpots(std::vector<uint8_t> &rgb_image) const;
void AddROI(std::vector<uint8_t> &rgb_image) const;
PreviewCounter counter;
void color_pixel(std::vector<unsigned char>& ret, int64_t xpixel, int64_t ypixel, const rgb &color) const;
void spot(std::vector<unsigned char>& ret, int64_t xpixel, int64_t ypixel, bool indexed) const;
void roi(std::vector<unsigned char>& ret, int64_t xpixel, int64_t ypixel, int64_t roi_number) const;
void beam_center_mark(std::vector<unsigned char>& ret, int64_t xpixel, int64_t ypixel) const;
public:
explicit PreviewImage(const DiffractionExperiment& experiment);
void UpdateImage(const void *uncompressed_image, const std::vector<SpotToSave> &spots);
[[nodiscard]] std::string GenerateJPEG(const PreviewJPEGSettings& settings) const;
[[nodiscard]] std::string GenerateTIFF() const;
[[nodiscard]] std::string GenerateTIFFDioptas() const;
[[nodiscard]] static std::string GenerateTestJPEG(const PreviewJPEGSettings& settings);
};
#endif //JUNGFRAUJOCH_PREVIEWIMAGE_H
+3 -1
View File
@@ -79,7 +79,9 @@ TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") {
.DetectorDistance_mm(75).BeamY_pxl(1136).BeamX_pxl(1090).PhotonEnergy_keV(12.4)
.SetUnitCell(UnitCell{.a = 36.9, .b = 78.95, .c = 78.95, .alpha =90, .beta = 90, .gamma = 90});
experiment.ROI().SetROIBox({ROIBox("roi0", 800, 1200, 800, 1200)});
experiment.ROI().SetROIBox({ROIBox("roi1", 0, 20, 0, 20),
ROIBox("roi0", 800, 1200, 800, 1200),
ROIBox("roi3", 2000, 2067, 2000, 2163)});
experiment.ROI().SetROICircle({ROICircle("roi2", 500, 500, 50)});
// Load example image