Preview improvements
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user