Preview: geometry-following arcs, true beam center, unified colours, predictions
Draw the resolution ring and azimuthal-ROI outlines by sweeping ResPhiToPxl through the geometry (a shared DrawArc/DrawThickLine helper), so they trace the true conic on a tilted detector instead of PONI-centred circles. Draw the beam crosshair at GetDirectBeam_pxl() (the real beam/detector intersection) rather than the stored PONI. Unify the spot overlay colours with the viewer: green = not indexed, magenta = indexed (primary lattice), cyan = ice ring, coral = secondary/further lattice. Add Bragg-prediction overlay (dark-red circles, skipping systematic absences) gated on a new show_predictions preview setting, wired through the OpenAPI spec, the image.jpeg HTTP handler, and the frontend toggle (+regenerated TS client). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -263,6 +263,7 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
|
||||
parse_query_value<bool>(req, "show_user_mask"),
|
||||
parse_query_value<bool>(req, "show_roi"),
|
||||
parse_query_value<bool>(req, "show_spots"),
|
||||
parse_query_value<bool>(req, "show_predictions"),
|
||||
parse_query_value<bool>(req, "show_beam_center"),
|
||||
parse_query_value<float>(req, "saturation"),
|
||||
parse_query_value<int64_t>(req, "jpeg_quality"),
|
||||
@@ -679,6 +680,7 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional<int64_t>
|
||||
const std::optional<bool> &showUserMask,
|
||||
const std::optional<bool> &showRoi,
|
||||
const std::optional<bool> &showSpots,
|
||||
const std::optional<bool> &showPredictions,
|
||||
const std::optional<bool> &showBeamCenter,
|
||||
const std::optional<float> &saturation,
|
||||
const std::optional<int64_t> &jpegQuality,
|
||||
@@ -692,6 +694,7 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional<int64_t>
|
||||
settings.show_user_mask = showUserMask.value_or(false);
|
||||
settings.show_roi = showRoi.value_or(false);
|
||||
settings.show_spots = showSpots.value_or(true);
|
||||
settings.show_predictions = showPredictions.value_or(false);
|
||||
settings.saturation_value = saturation;
|
||||
settings.background_value = 0.0;
|
||||
settings.jpeg_quality = jpegQuality.value_or(100);
|
||||
|
||||
@@ -136,6 +136,7 @@ class JFJochBrokerHttp {
|
||||
void image_buffer_image_cbor_get(const std::optional<int64_t> &id, httplib::Response &response);
|
||||
void image_buffer_image_jpeg_get(const std::optional<int64_t> &id, const std::optional<bool> &showUserMask,
|
||||
const std::optional<bool> &showRoi, const std::optional<bool> &showSpots,
|
||||
const std::optional<bool> &showPredictions,
|
||||
const std::optional<bool> &showBeamCenter, const std::optional<float> &saturation,
|
||||
const std::optional<int64_t> &jpegQuality, const std::optional<float> &showResRing,
|
||||
const std::optional<std::string> &color, const std::optional<bool> &showResEst,
|
||||
|
||||
@@ -168,6 +168,13 @@ components:
|
||||
type: boolean
|
||||
default: true
|
||||
description: "Show spot finding results on the image"
|
||||
show_predictions:
|
||||
in: query
|
||||
name: show_predictions
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
description: "Show Bragg spot predictions on the image (if available for the image)"
|
||||
show_beam_center:
|
||||
in: query
|
||||
name: show_beam_center
|
||||
@@ -3566,6 +3573,7 @@ paths:
|
||||
- $ref: '#/components/parameters/show_user_mask'
|
||||
- $ref: '#/components/parameters/show_roi'
|
||||
- $ref: '#/components/parameters/show_spots'
|
||||
- $ref: '#/components/parameters/show_predictions'
|
||||
- $ref: '#/components/parameters/show_beam_center'
|
||||
- $ref: '#/components/parameters/saturation'
|
||||
- $ref: '#/components/parameters/jpeg_quality'
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1773,6 +1773,11 @@ export type background = number;
|
||||
*/
|
||||
export type show_spots = boolean;
|
||||
|
||||
/**
|
||||
* Show Bragg spot predictions on the image (if available for the image)
|
||||
*/
|
||||
export type show_predictions = boolean;
|
||||
|
||||
/**
|
||||
* Show beam center on the image
|
||||
*/
|
||||
@@ -3221,6 +3226,10 @@ export type getImageBufferImageJpegData = {
|
||||
* Show spot finding results on the image
|
||||
*/
|
||||
show_spots?: boolean;
|
||||
/**
|
||||
* Show Bragg spot predictions on the image (if available for the image)
|
||||
*/
|
||||
show_predictions?: boolean;
|
||||
/**
|
||||
* Show beam center on the image
|
||||
*/
|
||||
|
||||
@@ -868,6 +868,11 @@ export const zBackground = z.number().gte(-32767).lte(32767).default(0);
|
||||
*/
|
||||
export const zShowSpots = z.boolean().default(true);
|
||||
|
||||
/**
|
||||
* Show Bragg spot predictions on the image (if available for the image)
|
||||
*/
|
||||
export const zShowPredictions = z.boolean().default(false);
|
||||
|
||||
/**
|
||||
* Show beam center on the image
|
||||
*/
|
||||
@@ -1235,6 +1240,7 @@ export const zGetImageBufferImageJpegQuery = z.object({
|
||||
show_user_mask: z.boolean().optional().default(false),
|
||||
show_roi: z.boolean().optional().default(false),
|
||||
show_spots: z.boolean().optional().default(true),
|
||||
show_predictions: z.boolean().optional().default(false),
|
||||
show_beam_center: z.boolean().optional().default(true),
|
||||
saturation: z.number().gte(-32767).lte(32767).optional(),
|
||||
jpeg_quality: z.coerce.bigint().gte(BigInt(0)).lte(BigInt(100)).optional().default(BigInt(100)),
|
||||
|
||||
@@ -20,6 +20,7 @@ import FormControl from "@mui/material/FormControl";
|
||||
type preview_settings = {
|
||||
saturation: number;
|
||||
show_spots: boolean;
|
||||
show_predictions: boolean;
|
||||
show_roi: boolean;
|
||||
jpeg_quality: number;
|
||||
show_user_mask: boolean;
|
||||
@@ -57,6 +58,7 @@ const default_preview_settings: preview_settings = {
|
||||
saturation: 10,
|
||||
jpeg_quality: 90,
|
||||
show_spots: true,
|
||||
show_predictions: false,
|
||||
show_roi: false,
|
||||
show_user_mask: false,
|
||||
show_beam_center: true,
|
||||
@@ -88,6 +90,7 @@ function PreviewImage({measuring, min_image_number, max_image_number}: MyProps)
|
||||
url += `&saturation=${s.saturation}`;
|
||||
url += `&jpeg_quality=${s.jpeg_quality}`
|
||||
url += `&show_spots=${s.show_spots}`
|
||||
url += `&show_predictions=${s.show_predictions}`
|
||||
url += `&show_roi=${s.show_roi}`
|
||||
url += `&show_user_mask=${s.show_user_mask}`;
|
||||
if (s.res_estimate)
|
||||
@@ -189,6 +192,12 @@ function PreviewImage({measuring, min_image_number, max_image_number}: MyProps)
|
||||
getValues(s);
|
||||
};
|
||||
|
||||
const showPredictionsToggle = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
let s : preview_settings = {...settings, show_predictions: event.target.checked};
|
||||
setSettings(s);
|
||||
getValues(s);
|
||||
};
|
||||
|
||||
const resEstToggle = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
let s: preview_settings = {...settings, res_estimate: event.target.checked};
|
||||
setSettings(s);
|
||||
@@ -338,6 +347,9 @@ function PreviewImage({measuring, min_image_number, max_image_number}: MyProps)
|
||||
<FormControlLabel control={
|
||||
<Checkbox checked={settings.show_spots} onChange={showSpotsToggle} name="Show spots"/>
|
||||
} label="Show spots"/>
|
||||
<FormControlLabel control={
|
||||
<Checkbox checked={settings.show_predictions} onChange={showPredictionsToggle} name="Show predictions"/>
|
||||
} label="Show predictions"/>
|
||||
<FormControlLabel control={
|
||||
<Checkbox checked={settings.show_roi} onChange={showROIToggle} name="Show ROI"/>
|
||||
} label="Show ROI"/>
|
||||
|
||||
+120
-50
@@ -1,18 +1,22 @@
|
||||
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <future>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
|
||||
#include "PreviewImage.h"
|
||||
|
||||
#include "JFJochJPEG.h"
|
||||
#include "JFJochTIFF.h"
|
||||
#include "../common/JFJochException.h"
|
||||
#include "../common/JFJochMath.h"
|
||||
#include "../common/DiffractionGeometry.h"
|
||||
#include "../frame_serialize/CBORStream2Deserializer.h"
|
||||
#include "../compression/JFJochDecompress.h"
|
||||
#include "../image_analysis/bragg_integration/SystematicAbsence.h"
|
||||
|
||||
constexpr const static rgb lime = {.r = 0xcd, .g = 0xdc, .b = 0x39};
|
||||
constexpr const static rgb pink = {.r = 0xe9, .g = 0x1e, .b = 0x63};
|
||||
@@ -23,6 +27,14 @@ 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 cyan = {.r = 0x00, .g = 0xff, .b = 0xff}; // "ice" color
|
||||
|
||||
// Spot/prediction overlay palette, matching the jfjoch_viewer diffraction image so the two
|
||||
// front-ends look identical: green = not indexed, magenta = indexed (primary lattice),
|
||||
// cyan = on an ice ring, coral = secondary/further lattice, dark red = Bragg prediction.
|
||||
constexpr const static rgb green = {.r = 0x00, .g = 0xff, .b = 0x00};
|
||||
constexpr const static rgb magenta = {.r = 0xff, .g = 0x00, .b = 0xff};
|
||||
constexpr const static rgb coral = {.r = 0xfa, .g = 0x72, .b = 0x68};
|
||||
constexpr const static rgb dark_red = {.r = 0x80, .g = 0x00, .b = 0x00};
|
||||
|
||||
constexpr const static rgb plotly[] = {{0x1f, 0x77, 0xb4},
|
||||
{0xff, 0x7f, 0x0e},
|
||||
{0x2c, 0xa0, 0x2c},
|
||||
@@ -36,20 +48,6 @@ constexpr const static rgb plotly[] = {{0x1f, 0x77, 0xb4},
|
||||
|
||||
constexpr const static rgb gray = {.r = 0xbe, .g = 0xbe, .b = 0xbe};
|
||||
|
||||
// Smallest difference between two angles in degrees, accounting for wrap-around.
|
||||
static float AngularDistance_deg(float a, float b) {
|
||||
float d = std::fabs(a - b);
|
||||
if (d > 180.0f)
|
||||
d = 360.0f - d;
|
||||
return d;
|
||||
}
|
||||
|
||||
static bool InPhiSector(float phi_deg, float phi_min, float phi_max) {
|
||||
if (phi_min <= phi_max)
|
||||
return phi_deg >= phi_min && phi_deg <= phi_max;
|
||||
return phi_deg >= phi_min || phi_deg <= phi_max; // sector wraps across 0
|
||||
}
|
||||
|
||||
void PreviewImage::color_pixel(std::vector<rgb> &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)] = color;
|
||||
@@ -133,8 +131,13 @@ std::vector<rgb> PreviewImage::GenerateRGB(const uint8_t *value_8,
|
||||
}
|
||||
|
||||
void PreviewImage::AddBeamCenter(std::vector<rgb> &rgb_image) const {
|
||||
size_t beam_x_int = std::lround(beam_x);
|
||||
size_t beam_y_int = std::lround(beam_y);
|
||||
// The true direct beam is where the primary beam hits the detector, which differs from the
|
||||
// stored beam origin (PONI) whenever the detector is tilted.
|
||||
auto [bx, by] = experiment.GetDiffractionGeometry().GetDirectBeam_pxl();
|
||||
if (!std::isfinite(bx) || !std::isfinite(by))
|
||||
return;
|
||||
int64_t beam_x_int = std::lround(bx);
|
||||
int64_t beam_y_int = std::lround(by);
|
||||
|
||||
int crosshair_size = 30;
|
||||
int crosshair_width = 3;
|
||||
@@ -155,9 +158,9 @@ void PreviewImage::AddSpots(std::vector<rgb> &rgb_image,
|
||||
int rectangle_size = 4;
|
||||
int rectangle_width = 3;
|
||||
|
||||
rgb color = pink;
|
||||
rgb color = green; // not indexed
|
||||
if (s.indexed)
|
||||
color = amber;
|
||||
color = (s.lattice >= 1) ? coral : magenta; // secondary lattice vs primary
|
||||
else if (s.ice_ring)
|
||||
color = cyan;
|
||||
|
||||
@@ -215,46 +218,110 @@ void PreviewImage::AddROI(std::vector<rgb> &rgb_image) const {
|
||||
|
||||
DiffractionGeometry geom = experiment.GetDiffractionGeometry();
|
||||
for (const auto &az: experiment.ROI().GetROIDefinition().azimuthal) {
|
||||
const int width = 5;
|
||||
const float r_inner = geom.ResToPxl(az.GetDMax_A()); // larger d -> smaller radius
|
||||
const float r_outer = geom.ResToPxl(az.GetDMin_A());
|
||||
const bool has_phi = az.HasPhi();
|
||||
const rgb color = plotly[roi_counter % 10];
|
||||
const float d_inner = az.GetDMax_A(); // larger d -> smaller radius (inner arc)
|
||||
const float d_outer = az.GetDMin_A(); // smaller d -> larger radius (outer arc)
|
||||
constexpr float deg2rad = static_cast<float>(PI) / 180.0f;
|
||||
|
||||
for (int64_t y = 0; y <= ypixel; y++) {
|
||||
for (int64_t x = 0; x <= xpixel; x++) {
|
||||
const float dx = x - beam_x;
|
||||
const float dy = y - beam_y;
|
||||
const float dist = sqrtf(dx * dx + dy * dy);
|
||||
const float phi_deg = geom.Phi_rad(x, y) * 180.0f / static_cast<float>(PI);
|
||||
if (az.HasPhi()) {
|
||||
float phi0 = az.GetPhiMin_deg() * deg2rad;
|
||||
float phi1 = az.GetPhiMax_deg() * deg2rad;
|
||||
if (phi1 < phi0)
|
||||
phi1 += 2.0f * static_cast<float>(PI); // unwrap a sector that crosses 0
|
||||
|
||||
const bool in_sector = !has_phi || InPhiSector(phi_deg, az.GetPhiMin_deg(), az.GetPhiMax_deg());
|
||||
const bool on_arc = (std::fabs(dist - r_inner) < width) || (std::fabs(dist - r_outer) < width);
|
||||
DrawArc(rgb_image, geom, d_outer, phi0, phi1, color, 2);
|
||||
DrawArc(rgb_image, geom, d_inner, phi0, phi1, color, 2);
|
||||
|
||||
// Radial edges of a sector: angular tolerance scaled to keep ~constant pixel width.
|
||||
const float tol_deg = (dist > 1.0f) ? width / dist * 180.0f / static_cast<float>(PI) : 180.0f;
|
||||
const bool on_edge = has_phi && (dist >= r_inner) && (dist <= r_outer)
|
||||
&& (AngularDistance_deg(phi_deg, az.GetPhiMin_deg()) < tol_deg
|
||||
|| AngularDistance_deg(phi_deg, az.GetPhiMax_deg()) < tol_deg);
|
||||
|
||||
if ((on_arc && in_sector) || on_edge)
|
||||
roi(rgb_image, x, y, roi_counter);
|
||||
}
|
||||
// Straight radial edges joining the inner and outer arc at each sector limit.
|
||||
auto radial_edge = [&](float phi) {
|
||||
try {
|
||||
auto [ax, ay] = geom.ResPhiToPxl(d_outer, phi);
|
||||
auto [bx, by] = geom.ResPhiToPxl(d_inner, phi);
|
||||
if (std::isfinite(ax) && std::isfinite(ay) && std::isfinite(bx) && std::isfinite(by))
|
||||
DrawThickLine(rgb_image, ax, ay, bx, by, color, 2);
|
||||
} catch (...) {}
|
||||
};
|
||||
radial_edge(phi0);
|
||||
radial_edge(phi1);
|
||||
} else {
|
||||
const float two_pi = 2.0f * static_cast<float>(PI);
|
||||
DrawArc(rgb_image, geom, d_outer, 0.0f, two_pi, color, 2);
|
||||
DrawArc(rgb_image, geom, d_inner, 0.0f, two_pi, color, 2);
|
||||
}
|
||||
roi_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewImage::AddResolutionRing(std::vector<rgb> &rgb_image, float d) const {
|
||||
DiffractionGeometry geom = experiment.GetDiffractionGeometry();
|
||||
int width = 3;
|
||||
float radius = geom.ResToPxl(d);
|
||||
for (int64_t y = 0; y <= ypixel; y++) {
|
||||
for (int64_t x = 0; x <= xpixel; x++) {
|
||||
float dist = sqrtf((x - beam_x) * (x - beam_x) + (y - beam_y) * (y - beam_y));
|
||||
DrawArc(rgb_image, experiment.GetDiffractionGeometry(), d, 0.0f, 2.0f * static_cast<float>(PI), orange, 1);
|
||||
}
|
||||
|
||||
if ((dist > radius) && (dist < radius + width))
|
||||
color_pixel(rgb_image, x, y, orange);
|
||||
void PreviewImage::DrawThickLine(std::vector<rgb> &rgb_image, float x0, float y0, float x1, float y1,
|
||||
const rgb &color, int halfwidth) const {
|
||||
const float dx = x1 - x0, dy = y1 - y0;
|
||||
int n = static_cast<int>(std::ceil(std::max(std::fabs(dx), std::fabs(dy))));
|
||||
if (n < 1) n = 1;
|
||||
for (int i = 0; i <= n; i++) {
|
||||
const float t = static_cast<float>(i) / static_cast<float>(n);
|
||||
const int64_t px = std::lround(x0 + t * dx);
|
||||
const int64_t py = std::lround(y0 + t * dy);
|
||||
for (int a = -halfwidth; a <= halfwidth; a++)
|
||||
for (int b = -halfwidth; b <= halfwidth; b++)
|
||||
color_pixel(rgb_image, px + a, py + b, color);
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewImage::DrawArc(std::vector<rgb> &rgb_image, const DiffractionGeometry &geom, float d,
|
||||
float phi_start, float phi_end, const rgb &color, int halfwidth) const {
|
||||
// Sample the constant-d arc finely enough that neighbouring samples stay a few pixels apart,
|
||||
// then join them with straight segments. ResPhiToPxl carries the detector tilt, so this traces
|
||||
// the true conic instead of a PONI-centred circle. It throws when d is too high for the
|
||||
// wavelength, and returns NaN where the contour leaves the detector plane - break there.
|
||||
const float r_est = geom.ResToPxl(d);
|
||||
const float span = std::fabs(phi_end - phi_start);
|
||||
const int steps = std::clamp<int>(static_cast<int>(std::lround(std::fabs(r_est) * span * 0.5f)), 60, 8192);
|
||||
std::optional<std::pair<float, float>> prev;
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
const float phi = phi_start + (phi_end - phi_start) * static_cast<float>(i) / static_cast<float>(steps);
|
||||
std::pair<float, float> pt;
|
||||
try {
|
||||
pt = geom.ResPhiToPxl(d, phi);
|
||||
} catch (...) {
|
||||
return; // d too high for the wavelength - nothing to draw
|
||||
}
|
||||
if (!std::isfinite(pt.first) || !std::isfinite(pt.second)) {
|
||||
prev.reset();
|
||||
continue;
|
||||
}
|
||||
if (prev)
|
||||
DrawThickLine(rgb_image, prev->first, prev->second, pt.first, pt.second, color, halfwidth);
|
||||
prev = pt;
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewImage::DrawCircleOutline(std::vector<rgb> &rgb_image, float cx, float cy, float radius,
|
||||
int width, const rgb &color) const {
|
||||
const int64_t x_lo = std::floor(cx - radius - width);
|
||||
const int64_t x_hi = std::ceil(cx + radius + width);
|
||||
const int64_t y_lo = std::floor(cy - radius - width);
|
||||
const int64_t y_hi = std::ceil(cy + radius + width);
|
||||
for (int64_t y = y_lo; y <= y_hi; y++) {
|
||||
for (int64_t x = x_lo; x <= x_hi; x++) {
|
||||
const float dist = std::sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
|
||||
if (dist >= radius && dist <= radius + width)
|
||||
color_pixel(rgb_image, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewImage::AddPredictions(std::vector<rgb> &rgb_image, const std::vector<Reflection> &reflections,
|
||||
char centering) const {
|
||||
// Draw predictions as dark-red circles (spots are squares), matching the viewer overlay.
|
||||
// Reflections absent under the lattice centering are integrated but not real predictions - skip them.
|
||||
for (const auto &s : reflections) {
|
||||
if (systematic_absence(s.h, s.k, s.l, centering))
|
||||
continue;
|
||||
DrawCircleOutline(rgb_image, s.predicted_x, s.predicted_y, 5.0f, 2, dark_red);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,8 +356,6 @@ void PreviewImage::Configure(const DiffractionExperiment &in_experiment, const P
|
||||
experiment = in_experiment;
|
||||
xpixel = experiment.GetXPixelsNum();
|
||||
ypixel = experiment.GetYPixelsNum();
|
||||
beam_x = experiment.GetBeamX_pxl();
|
||||
beam_y = experiment.GetBeamY_pxl();
|
||||
pixel_depth_bytes = experiment.GetByteDepthImage();
|
||||
pixel_is_signed = experiment.IsPixelSigned();
|
||||
|
||||
@@ -359,6 +424,11 @@ std::vector<rgb> PreviewImage::GenerateRGB(const PreviewImageSettings &settings,
|
||||
if (settings.show_spots)
|
||||
AddSpots(v, msg.spots);
|
||||
|
||||
if (settings.show_predictions) {
|
||||
const char centering = msg.lattice_type.has_value() ? msg.lattice_type->centering : 'P';
|
||||
AddPredictions(v, msg.reflections, centering);
|
||||
}
|
||||
|
||||
if (settings.show_roi)
|
||||
AddROI(v);
|
||||
|
||||
|
||||
+13
-2
@@ -7,6 +7,7 @@
|
||||
#include <mutex>
|
||||
|
||||
#include "../common/SpotToSave.h"
|
||||
#include "../common/Reflection.h"
|
||||
#include "../common/DiffractionExperiment.h"
|
||||
#include "../common/PixelMask.h"
|
||||
#include "PreviewCounter.h"
|
||||
@@ -20,6 +21,7 @@ struct PreviewImageSettings {
|
||||
int64_t jpeg_quality = 70;
|
||||
bool show_beam_center = true;
|
||||
bool show_spots = true;
|
||||
bool show_predictions = false;
|
||||
bool show_roi = false;
|
||||
bool show_user_mask = true;
|
||||
bool show_res_est = false;
|
||||
@@ -39,8 +41,6 @@ class PreviewImage {
|
||||
size_t ypixel = 0;
|
||||
size_t pixel_depth_bytes = 2;
|
||||
bool pixel_is_signed = false;
|
||||
float beam_x = 0;
|
||||
float beam_y = 0;
|
||||
|
||||
constexpr static uint8_t MaskGap = 1;
|
||||
constexpr static uint8_t MaskUsr = 2;
|
||||
@@ -59,8 +59,19 @@ class PreviewImage {
|
||||
void AddResolutionRing(std::vector<rgb> &rgb_image, float d) const;
|
||||
void AddBeamCenter(std::vector<rgb> &rgb_image) const;
|
||||
void AddSpots(std::vector<rgb> &rgb_image, const std::vector<SpotToSave>& spots) const;
|
||||
void AddPredictions(std::vector<rgb> &rgb_image, const std::vector<Reflection>& reflections, char centering) const;
|
||||
void AddROI(std::vector<rgb> &rgb_image) const;
|
||||
|
||||
// Trace a fixed-resolution arc through the geometry (a circular arc on an untilted detector,
|
||||
// a conic one on a tilted detector) by sweeping azimuth from phi_start to phi_end and joining
|
||||
// the samples. A full ring uses phi_start=0, phi_end=2*pi.
|
||||
void DrawArc(std::vector<rgb> &rgb_image, const DiffractionGeometry &geom, float d,
|
||||
float phi_start, float phi_end, const rgb &color, int halfwidth) const;
|
||||
void DrawThickLine(std::vector<rgb> &rgb_image, float x0, float y0, float x1, float y1,
|
||||
const rgb &color, int halfwidth) const;
|
||||
void DrawCircleOutline(std::vector<rgb> &rgb_image, float cx, float cy, float radius,
|
||||
int width, const rgb &color) const;
|
||||
|
||||
void color_pixel(std::vector<rgb>& ret, int64_t xpixel, int64_t ypixel, const rgb &color) const;
|
||||
void spot(std::vector<rgb>& ret, int64_t xpixel, int64_t ypixel, const rgb &color) const;
|
||||
void roi(std::vector<rgb>& ret, int64_t xpixel, int64_t ypixel, int64_t roi_number) const;
|
||||
|
||||
Reference in New Issue
Block a user