Preparations

This commit is contained in:
Matthias Koefferlein 2025-08-15 21:25:53 +02:00
parent 437c48c1fb
commit a73aa1115f
7 changed files with 349 additions and 179 deletions

View File

@ -72,7 +72,6 @@
<font>
<family>Sans Serif</family>
<pointsize>12</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>false</underline>
@ -108,98 +107,31 @@
<property name="spacing">
<number>6</number>
</property>
<item row="1" column="4">
<widget class="QLabel" name="label_22">
<property name="text">
<string>h = </string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLineEdit" name="persp_tx_le"/>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_25">
<property name="text">
<string>x = </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="shear_le"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Perspective </string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="x_offset_le"/>
</item>
<item row="1" column="5">
<widget class="QLineEdit" name="height_le"/>
</item>
<item row="5" column="6">
<item row="7" column="6">
<widget class="QLabel" name="label_43">
<property name="text">
<string>degree</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QLineEdit" name="y_offset_le"/>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="width_le"/>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<item row="3" column="4">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Shear angle</string>
<string>h = </string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Pixel Size </string>
</property>
</widget>
<item row="3" column="5">
<widget class="QLineEdit" name="height_le"/>
</item>
<item row="5" column="3">
<widget class="QLabel" name="label_41">
<widget class="QLabel" name="label_30">
<property name="text">
<string>degree</string>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="label_24">
<property name="text">
<string>micron</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Rotation angle</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_23">
<property name="text">
<string>micron</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="3" column="1">
<widget class="QLabel" name="label_20">
<property name="text">
<string>w = </string>
@ -209,77 +141,8 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_28">
<property name="text">
<string>micron </string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Center</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_39">
<property name="text">
<string>x =</string>
</property>
</widget>
</item>
<item row="3" column="5" colspan="2">
<widget class="QCheckBox" name="mirror_cbx">
<property name="text">
<string>Mirrored (at X-axis)</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_21">
<property name="text">
<string>micron </string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="angle_le"/>
</item>
<item row="4" column="3">
<widget class="QLabel" name="label_40">
<property name="text">
<string>degree</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="7">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="4">
<widget class="QLabel" name="label_26">
<property name="text">
<string>y = </string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_30">
<property name="text">
<string>degree</string>
</property>
</widget>
<item row="4" column="5">
<widget class="QLineEdit" name="y_offset_le"/>
</item>
<item row="0" column="0" colspan="7">
<spacer>
@ -292,15 +155,135 @@
<property name="sizeHint" stdset="0">
<size>
<width>507</width>
<height>16</height>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="5">
<widget class="QLineEdit" name="persp_ty_le"/>
</item>
<item row="8" column="0" colspan="7">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="3" colspan="4">
<widget class="QLabel" name="label_45">
<property name="text">
<string>(use them to align the image with the layout)</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLineEdit" name="persp_tx_le"/>
</item>
<item row="6" column="2">
<widget class="QLineEdit" name="shear_le"/>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Rotation angle</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_25">
<property name="text">
<string>x = </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QLabel" name="label_41">
<property name="text">
<string>degree</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QLabel" name="label_44">
<property name="text">
<string>Landmarks</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_21">
<property name="text">
<string>micron </string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QLabel" name="label_24">
<property name="text">
<string>micron</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Perspective </string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="label_28">
<property name="text">
<string>micron </string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="x_offset_le"/>
</item>
<item row="4" column="4">
<widget class="QLabel" name="label_26">
<property name="text">
<string>y = </string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QPushButton" name="define_landmarks_pb">
<property name="text">
<string>Define</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_39">
<property name="text">
<string>x =</string>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="label_23">
<property name="text">
<string>micron</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Shear angle</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="7">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -316,32 +299,130 @@
</property>
</spacer>
</item>
<item row="5" column="4">
<item row="7" column="5">
<widget class="QLineEdit" name="persp_ty_le"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Pixel Size </string>
</property>
</widget>
</item>
<item row="5" column="5" colspan="2">
<widget class="QCheckBox" name="mirror_cbx">
<property name="text">
<string>Mirrored (at X-axis)</string>
</property>
</widget>
</item>
<item row="6" column="3">
<widget class="QLabel" name="label_40">
<property name="text">
<string>degree</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLineEdit" name="angle_le"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Center</string>
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QLabel" name="label_42">
<property name="text">
<string>y =</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QLabel" name="label_44">
<item row="3" column="2">
<widget class="QLineEdit" name="width_le"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_46">
<property name="text">
<string>Landmarks</string>
<string>Layer binding</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QPushButton" name="define_landmarks_pb">
<property name="text">
<string>Define</string>
<item row="2" column="0" colspan="7">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="3" colspan="4">
<widget class="QLabel" name="label_45">
<property name="text">
<string>(use them to align the image with the layout)</string>
<item row="1" column="2" colspan="5">
<widget class="QFrame" name="frame_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="lay::LayerSelectionComboBox" name="layer_binding_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Visibility of the image follows that layer's visibility</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
@ -1111,6 +1192,11 @@ p, li { white-space: pre-wrap; }
<header>imgWidgets.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>lay::LayerSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>width_le</tabstop>

View File

@ -811,13 +811,13 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"@brief Sets the mask from a array of boolean values\n"
"The order of the boolean values is line first, from bottom to top and left to right and is the same as the order in the data array.\n"
"\n"
"This method has been introduced in version 0.27.\n"
"This attribute has been introduced in version 0.27.\n"
) +
gsi::method_ext ("mask_data", &get_mask_data,
"@brief Gets the mask from a array of boolean values\n"
"See \\set_mask_data for a description of the data field.\n"
"\n"
"This method has been introduced in version 0.27.\n"
"This attribute has been introduced in version 0.27.\n"
) +
gsi::method_ext ("pixel_width=", &img_set_pixel_width, gsi::arg ("w"),
"@brief Sets the pixel width\n"
@ -826,7 +826,7 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"micron space with the transformation.\n"
"\n"
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
"This property is provided for convenience only."
"This attribute is provided for convenience only."
) +
gsi::method_ext ("pixel_width", &img_get_pixel_width,
"@brief Gets the pixel width\n"
@ -834,7 +834,7 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"See \\pixel_width= for a description of that property.\n"
"\n"
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
"This property is provided for convenience only."
"This attribute is provided for convenience only."
) +
gsi::method_ext ("pixel_height=", &img_set_pixel_height, gsi::arg ("h"),
"@brief Sets the pixel height\n"
@ -843,7 +843,7 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"micron space with the transformation.\n"
"\n"
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
"This property is provided for convenience only."
"This attribute is provided for convenience only."
) +
gsi::method_ext ("pixel_height", &img_get_pixel_height,
"@brief Gets the pixel height\n"
@ -851,21 +851,35 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"See \\pixel_height= for a description of that property.\n"
"\n"
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
"This property is provided for convenience only."
"This attribute is provided for convenience only."
) +
gsi::method ("z_position", &ImageRef::z_position,
"@brief Gets the z position of the image\n"
"Images with a higher z position are painted in front of images with lower z position.\n"
"The z value is an integer that controls the position relative to other images.\n"
"\n"
"This method was introduced in version 0.25."
"This attribute was introduced in version 0.25."
) +
gsi::method ("z_position=", &ImageRef::set_z_position, gsi::arg ("z"),
"@brief Sets the z position of the image\n"
"\n"
"See \\z_position for details about the z position attribute.\n"
"\n"
"This method was introduced in version 0.25."
"This attribute was introduced in version 0.25."
) +
gsi::method ("layer_binding", &ImageRef::layer_binding,
"@brief Gets the layer binding of the image\n"
"If this attribute is set to a non-null layer properties object, the images visibility "
"is associated with that of this layer. If the layer becomes invisible, the image is hidden as well.\n"
"\n"
"This attribute was introduced in version 0.30.4."
) +
gsi::method ("layer_binding=", &ImageRef::set_layer_binding, gsi::arg ("lp"),
"@brief Sets the layer binding of the image\n"
"\n"
"See \\layer_binding for details about the layer_binding attribute.\n"
"\n"
"This attribute was introduced in version 0.30.4."
) +
gsi::method ("matrix=", &ImageRef::set_matrix, gsi::arg ("t"),
"@brief Sets the transformation matrix\n"
@ -876,7 +890,7 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"The matrix is more general than the transformation used before and supports shear and perspective transformation. This property replaces the \\trans property which is "
"still functional, but deprecated.\n"
"\n"
"This method has been introduced in version 0.22."
"This attribute has been introduced in version 0.22."
) +
gsi::method ("matrix", &ImageRef::matrix,
"@brief Returns the pixel-to-micron transformation matrix\n"
@ -887,7 +901,7 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"The matrix is more general than the transformation used before and supports shear and perspective transformation. This property replaces the \\trans property which is "
"still functional, but deprecated.\n"
"\n"
"This method has been introduced in version 0.22."
"This attribute has been introduced in version 0.22."
) +
gsi::method_ext ("trans", &img_get_trans,
"@brief Returns the pixel-to-micron transformation\n"
@ -941,14 +955,14 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
"\n"
"See the \\is_visible? method for a description of this property.\n"
"\n"
"This method has been introduced in version 0.20.\n"
"This attribute has been introduced in version 0.20.\n"
) +
gsi::method ("is_visible?", &ImageRef::is_visible,
"@brief Gets a flag indicating whether the image object is visible\n"
"\n"
"An image object can be made invisible by setting the visible property to false.\n"
"\n"
"This method has been introduced in version 0.20.\n"
"This attribute has been introduced in version 0.20.\n"
) +
gsi::method ("id", (size_t (ImageRef::*) () const) &ImageRef::id,
"@brief Gets the Id\n"

View File

@ -1020,6 +1020,7 @@ Object::operator= (const img::Object &d)
m_visible = d.m_visible;
m_z_position = d.m_z_position;
m_layer_binding = d.m_layer_binding;
m_min_value = d.m_min_value;
m_min_value_set = d.m_min_value_set;
@ -1052,6 +1053,10 @@ Object::less (const db::DUserObjectBase *d) const
return m_z_position < img_object->m_z_position;
}
if (m_layer_binding != img_object->m_layer_binding) {
return m_layer_binding < img_object->m_layer_binding;
}
double epsilon = (std::abs (m_min_value) + std::abs (m_max_value)) * 1e-6;
if (std::abs (m_min_value - img_object->m_min_value) > epsilon) {
return m_min_value < img_object->m_min_value;
@ -1102,7 +1107,11 @@ Object::operator== (const img::Object &d) const
return false;
}
// operator== is all fuzzy compare -
if (m_layer_binding != d.m_layer_binding) {
return false;
}
// operator== is all fuzzy compare -
double epsilon = (std::abs (m_min_value) + std::abs (m_max_value)) * 1e-6;
if (std::abs (m_min_value - d.m_min_value) > epsilon) {
return false;
@ -1424,6 +1433,8 @@ Object::from_string (const char *str, const char *base_dir)
ex.read (h);
} else if (ex.test ("is_visible=")) {
ex.read (m_visible);
} else if (ex.test ("layer_binding=")) {
ex.read (m_layer_binding);
} else if (ex.test ("z_position=")) {
ex.read (m_z_position);
} else if (ex.test ("min_value=")) {
@ -1814,6 +1825,12 @@ Object::to_string () const
os << tl::to_string (m_z_position);
os << ";";
if (m_layer_binding != db::LayerProperties ()) {
os << "layer_binding=";
os << m_layer_binding.to_string ();
os << ";";
}
os << "brightness=";
os << tl::to_string (data_mapping ().brightness);
os << ";";
@ -1953,6 +1970,7 @@ Object::swap (Object &other)
std::swap (mp_pixel_data, other.mp_pixel_data);
m_landmarks.swap (other.m_landmarks);
std::swap (m_z_position, other.m_z_position);
std::swap (m_layer_binding, other.m_layer_binding);
std::swap (m_updates_enabled, other.m_updates_enabled);
}

View File

@ -31,6 +31,7 @@
#include "dbTrans.h"
#include "dbMatrix.h"
#include "dbPolygon.h"
#include "dbLayerProperties.h"
#include "tlDataMapping.h"
#include "tlColor.h"
#include "tlPixelBuffer.h"
@ -924,6 +925,30 @@ public:
return m_z_position;
}
/**
* @brief Sets the layer binding
*
* If the image is bound to a layer, it becomes hidden when the layer is hidden
* and visible if the layer is visible too
*/
void set_layer_binding (const db::LayerProperties &lp)
{
if (m_layer_binding != lp) {
m_layer_binding = lp;
if (m_updates_enabled) {
property_changed ();
}
}
}
/**
* @brief Gets the layer binding
*/
const db::LayerProperties &layer_binding () const
{
return m_layer_binding;
}
/**
* @brief Get the RGB pixel data sets obtained by applying the LUT's
*/
@ -1021,6 +1046,7 @@ private:
mutable const tl::color_t *mp_pixel_data;
std::vector <db::DPoint> m_landmarks;
int m_z_position;
db::LayerProperties m_layer_binding;
bool m_updates_enabled;
void release ();

View File

@ -109,6 +109,8 @@ PropertiesPage::init ()
colors->setEnabled (false);
value_le->setEnabled (false);
attach_service (mp_service);
connect (browse_pb, SIGNAL (clicked ()), this, SLOT (browse ()));
connect (colors, SIGNAL (color_changed (std::pair<QColor, QColor>)), false_color_control, SLOT (set_current_color (std::pair<QColor, QColor>)));
connect (false_color_control, SIGNAL (selection_changed (std::pair<QColor, QColor>)), colors, SLOT (set_color (std::pair<QColor, QColor>)));
@ -147,6 +149,20 @@ PropertiesPage::init ()
connect (define_landmarks_pb, SIGNAL (clicked ()), this, SLOT (define_landmarks_pressed ()));
}
void
PropertiesPage::attach_service (img::Service *service)
{
layer_binding_cbx->set_new_layer_enabled (false);
layer_binding_cbx->set_no_layer_available (true);
if (service && service->view ()) {
int cv_index = 0; // TODO: fixed currently
layer_binding_cbx->set_view (service->view (), cv_index, true);
} else {
layer_binding_cbx->set_view (0, -1);
}
}
void
PropertiesPage::invalidate ()
{
@ -195,6 +211,10 @@ PropertiesPage::description () const
void
PropertiesPage::confine_selection (const std::vector<size_t> &remaining_entries)
{
if (! mp_service) {
return;
}
std::vector <img::Service::obj_iterator> org_selection;
m_selection.swap (org_selection);
for (auto i = remaining_entries.begin (); i != remaining_entries.end (); ++i) {
@ -459,6 +479,8 @@ PropertiesPage::update ()
to_le->setText (tl::to_qstring (tl::to_string (mp_direct_image->max_value ())));
to_le->setCursorPosition (0);
layer_binding_cbx->set_current_layer (mp_direct_image->layer_binding ());
false_color_control->set_nodes (mp_direct_image->data_mapping ().false_color_nodes);
brightness_slider->setValue (int (floor (mp_direct_image->data_mapping ().brightness * 100 + 0.5)));
@ -908,6 +930,8 @@ PropertiesPage::apply (bool /*commit*/)
mp_direct_image->set_min_value (xmin);
mp_direct_image->set_max_value (xmax);
mp_direct_image->set_layer_binding (layer_binding_cbx->current_layer_props ());
img::DataMapping dm (mp_direct_image->data_mapping ());
dm.brightness = brightness_sb->value () * 0.01;
dm.contrast = contrast_sb->value () * 0.01;

View File

@ -61,6 +61,7 @@ public:
virtual void apply (bool commit);
void set_direct_image (img::Object *image);
void attach_service (img::Service *service);
private slots:
void browse ();

View File

@ -58,10 +58,11 @@ class AddNewImageDialog
public Ui::AddNewImageDialog
{
public:
AddNewImageDialog (QWidget *parent, img::Object *image_object)
AddNewImageDialog (QWidget *parent, img::Service *service, img::Object *image_object)
: QDialog (parent), mp_image_object (image_object)
{
setupUi (this);
properties_frame->attach_service (service);
properties_frame->set_direct_image (image_object);
properties_frame->update ();
}
@ -1606,7 +1607,7 @@ Service::add_image ()
#if defined(HAVE_QT)
img::Object *new_image = new img::Object ();
AddNewImageDialog dialog (QApplication::activeWindow (), new_image);
AddNewImageDialog dialog (QApplication::activeWindow (), this, new_image);
if (dialog.exec ()) {
clear_selection ();