Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Masking boundaries #1569

Merged
merged 25 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f654cad
Generalize InteractiveTemplate class
bnmajor Jun 21, 2023
1295ef9
Support translation/rotation of drawn patch
bnmajor Aug 8, 2023
5033ae9
Match the behavior of the hand drawn mask dialog
bnmajor Aug 8, 2023
6db5ecd
Add updated instructions to masking dialog
bnmajor Sep 5, 2023
289c602
Check for threshold mask by name before applying
bnmajor Sep 5, 2023
028f038
Do not expect main window as parent
bnmajor Sep 6, 2023
29f0a01
Remove unused attribute
bnmajor Sep 6, 2023
6d0e662
Simplify check for threshold mask by name
bnmajor Sep 6, 2023
d3d7299
Rename for consistency
bnmajor Sep 6, 2023
5fa0a37
Set focus policy on canvas initialization
bnmajor Sep 6, 2023
5ad2f1f
Fix incorrect computation of current axes image
bnmajor Sep 6, 2023
4ab41e0
Always disconnect before setting up new canvas connections
bnmajor Sep 6, 2023
026bc03
Make sure all signals are disconnected
bnmajor Sep 7, 2023
0a493e0
Allow users to manipulate all existing templates
bnmajor Sep 8, 2023
dc76257
Simplify redundant list of templates
bnmajor Sep 8, 2023
1cb06c2
Color active bounds
bnmajor Sep 8, 2023
ec58684
Reset current template on undo
bnmajor Sep 8, 2023
af3796a
Prevent drawing when interacting
bnmajor Sep 20, 2023
c8cd796
Use `shape.get_verts()` to get vertices
psavery Sep 20, 2023
9cc66f6
Correct polar view rotation by aspect ratio
psavery Sep 20, 2023
d2446e0
Fix plot title check
bnmajor Sep 20, 2023
43f46ca
Fix extent aspect ratio correction
psavery Sep 20, 2023
3c5bf48
Do not interact if in static mode
bnmajor Sep 20, 2023
85194d0
Allow the angle of rotation by arrow key to be changed
bnmajor Sep 20, 2023
9c2b7ee
PEP 8 fixes
bnmajor Sep 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion hexrd/ui/hexrd_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,8 @@ def raw_masks_dict(self):
for det, mask in data:
if det == name:
final_mask = np.logical_and(final_mask, mask)
if self.threshold_mask_status:
if (self.threshold_mask_status and
self.threshold_masks.get(name, None) is not None):
psavery marked this conversation as resolved.
Show resolved Hide resolved
idx = self.current_imageseries_idx
thresh_mask = self.threshold_masks[name][idx]
final_mask = np.logical_and(final_mask, thresh_mask)
Expand Down
100 changes: 67 additions & 33 deletions hexrd/ui/interactive_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@

from skimage.draw import polygon

from hexrd.ui.create_hedm_instrument import create_hedm_instrument
from hexrd.ui import resource_loader
from hexrd.ui.hexrd_config import HexrdConfig
from hexrd.ui.utils import has_nan


class InteractiveTemplate:
def __init__(self, parent=None):
self.parent = parent.image_tab_widget.image_canvases[0]
self.ax = self.parent.axes_images[0]
self.panels = create_hedm_instrument().detectors
def __init__(self, parent, detector, instrument=None):
self.image_tab_widget = parent.image_tab_widget
psavery marked this conversation as resolved.
Show resolved Hide resolved
self.img = None
self.shape = None
self.press = None
Expand All @@ -27,11 +23,48 @@ def __init__(self, parent=None):
self.translation = [0, 0]
self.complete = False
self.event_key = None
self.parent.setFocusPolicy(Qt.ClickFocus)
self.detector = detector
self.instrument = instrument
self._static = True

for canvas in self.image_tab_widget.active_canvases:
canvas.setFocusPolicy(Qt.ClickFocus)
psavery marked this conversation as resolved.
Show resolved Hide resolved

@property
def current_canvas(self):
idx = self.image_tab_widget.current_index
return self.image_tab_widget.active_canvases[idx]
psavery marked this conversation as resolved.
Show resolved Hide resolved

@property
def ax(self):
idx = HexrdConfig().current_imageseries_idx
return self.current_canvas.axes_images[idx]
psavery marked this conversation as resolved.
Show resolved Hide resolved

@property
def raw_axes(self):
return list(self.parent.raw_axes.values())[0]
if not self.current_canvas.raw_axes:
return self.current_canvas.axis
psavery marked this conversation as resolved.
Show resolved Hide resolved

for axes in self.current_canvas.raw_axes.values():
if axes.get_title() == self.detector:
return axes

return list(self.current_canvas.raw_axes.values())[0]

@property
def static_mode(self):
return self._static

@static_mode.setter
def static_mode(self, mode):
if mode == self._static:
return

if mode:
self.disconnect()
else:
self.connect_translate_rotate()
psavery marked this conversation as resolved.
Show resolved Hide resolved
self._static = mode

def update_image(self, img):
self.img = img
Expand All @@ -41,20 +74,17 @@ def rotate_shape(self, angle):
self.rotate_template(self.shape.xy, angle)
self.redraw()

def create_shape(self, module, file_name, det, instr):
def create_polygon(self, verts, **kwargs):
psavery marked this conversation as resolved.
Show resolved Hide resolved
self.complete = False
with resource_loader.resource_path(module, file_name) as f:
data = np.loadtxt(f)
verts = self.panels['default'].cartToPixel(data)
verts[:, [0, 1]] = verts[:, [1, 0]]
self.shape = patches.Polygon(verts, fill=False, lw=1, color='cyan')
self.shape = patches.Polygon(verts, **kwargs)
if has_nan(verts):
# This template contains more than one polygon and the last point
# should not be connected to the first. See Tardis IP for example.
self.shape.set_closed(False)
self.shape_styles.append({'line': '-', 'width': 1, 'color': 'cyan'})
self.update_position(instr, det)
self.connect_translate_rotate()
self.shape_styles.append(kwargs)
self.update_position()
if not self.static_mode:
self.connect_translate_rotate()
psavery marked this conversation as resolved.
Show resolved Hide resolved
self.raw_axes.add_patch(self.shape)
self.redraw()

Expand All @@ -63,10 +93,13 @@ def update_style(self, style, width, color):
self.shape.set_linestyle(style)
self.shape.set_linewidth(width)
self.shape.set_edgecolor(color)
self.shape.set_fill(False)
self.redraw()

def update_position(self, instr, det):
pos = HexrdConfig().boundary_position(instr, det)
def update_position(self):
pos = None
if self.instrument is not None:
pos = HexrdConfig().boundary_position(self.instrument, self.detector)
if pos is None:
self.center = self.get_midpoint()
else:
Expand All @@ -75,7 +108,7 @@ def update_position(self, instr, det):
self.translate_template(dx, dy)
self.total_rotation = pos['angle']
self.rotate_template(self.shape.xy, pos['angle'])
if instr == 'PXRDIP':
if self.instrument == 'PXRDIP':
self.rotate_shape(angle=90)

@property
Expand Down Expand Up @@ -140,7 +173,8 @@ def toggle_boundaries(self, show):
self.shape.remove()
self.shape.set_linestyle(self.shape_styles[-1]['line'])
self.raw_axes.add_patch(self.shape)
self.connect_translate_rotate()
if not self.static_mode:
self.connect_translate_rotate()
self.redraw()
else:
if self.shape:
Expand All @@ -149,11 +183,11 @@ def toggle_boundaries(self, show):
self.redraw()

def disconnect(self):
self.parent.mpl_disconnect(self.button_press_cid)
self.parent.mpl_disconnect(self.button_release_cid)
self.parent.mpl_disconnect(self.motion_cid)
self.parent.mpl_disconnect(self.key_press_cid)
self.parent.mpl_disconnect(self.button_drag_cid)
self.current_canvas.mpl_disconnect(self.button_press_cid)
self.current_canvas.mpl_disconnect(self.button_release_cid)
self.current_canvas.mpl_disconnect(self.motion_cid)
self.current_canvas.mpl_disconnect(self.key_press_cid)
self.current_canvas.mpl_disconnect(self.button_drag_cid)
psavery marked this conversation as resolved.
Show resolved Hide resolved

def completed(self):
self.disconnect()
Expand Down Expand Up @@ -199,7 +233,7 @@ def get_paths(self):
return all_paths

def redraw(self):
self.parent.draw_idle()
self.current_canvas.draw_idle()

def scale_template(self, sx=1, sy=1):
xy = self.shape.xy
Expand Down Expand Up @@ -233,17 +267,17 @@ def on_key(self, event):
self.on_key_translate(event)

def connect_translate_rotate(self):
self.button_press_cid = self.parent.mpl_connect(
self.button_press_cid = self.current_canvas.mpl_connect(
'button_press_event', self.on_press)
self.button_release_cid = self.parent.mpl_connect(
self.button_release_cid = self.current_canvas.mpl_connect(
'button_release_event', self.on_release)
self.motion_cid = self.parent.mpl_connect(
self.motion_cid = self.current_canvas.mpl_connect(
'motion_notify_event', self.on_translate)
self.key_press_cid = self.parent.mpl_connect(
self.key_press_cid = self.current_canvas.mpl_connect(
'key_press_event', self.on_key)
self.button_drag_cid = self.parent.mpl_connect(
self.button_drag_cid = self.current_canvas.mpl_connect(
'motion_notify_event', self.on_rotate)
self.parent.setFocus()
self.current_canvas.setFocus()

def translate_template(self, dx, dy):
self.shape.set_xy(self.shape.xy + np.array([dx, dy]))
Expand Down
33 changes: 23 additions & 10 deletions hexrd/ui/llnl_import_tool_dialog.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import numpy as np
import yaml
import tempfile
import h5py
Expand All @@ -18,6 +19,7 @@
from hexrd.ui.image_load_manager import ImageLoadManager
from hexrd.ui.interactive_template import InteractiveTemplate
from hexrd.ui import resource_loader
from hexrd.ui.create_hedm_instrument import create_hedm_instrument
from hexrd.ui.ui_loader import UiLoader
from hexrd.ui.constants import (
UI_TRANS_INDEX_ROTATE_90, YAML_EXTS, LLNLTransform, ViewType)
Expand Down Expand Up @@ -273,7 +275,9 @@ def load_images(self):
# the QProgressDialog.
ImageLoadManager().read_data(files, ui_parent=self.ui.parent())
self.cmap.block_updates(False)
self.it = InteractiveTemplate(self.parent())
self.it = InteractiveTemplate(self.parent(), self.detector, self.instrument)
# We should be able to immediately interact with the template
self.it.static_mode = False

file_names = [os.path.split(f[0])[1] for f in files]
self.ui.files_label.setText(', '.join(file_names))
Expand Down Expand Up @@ -319,6 +323,14 @@ def display_bounds(self):
self.ui.bb_height.blockSignals(False)
self.ui.bb_width.blockSignals(False)

def read_in_template_bounds(self, module, file_name):
with resource_loader.resource_path(module, file_name) as f:
data = np.loadtxt(f)
panels = create_hedm_instrument().detectors
verts = panels['default'].cartToPixel(data)
verts[:, [0, 1]] = verts[:, [1, 0]]
return verts

def add_template(self):
if self.it is None or self.instrument is None or not self.detector:
return
Expand All @@ -330,11 +342,12 @@ def add_template(self):
return

self.it.clear()
self.it.create_shape(
verts = self.read_in_template_bounds(
module=hexrd_resources,
file_name=f'{self.instrument}_{self.detector}_bnd.txt',
det=self.detector,
instr=self.instrument)
file_name=f'{self.instrument}_{self.detector}_bnd.txt'
)
kwargs = {'fill': False, 'lw': 1, 'linestyle': '-'}
self.it.create_polygon(verts, **kwargs)
self.it.update_image(HexrdConfig().image('default', 0))
self.update_template_style()

Expand Down Expand Up @@ -380,14 +393,14 @@ def save_boundary_position(self):
def swap_bounds_for_cropped(self):
self.it.clear()
line, width, color = self.it.shape_styles[-1].values()
self.it.create_shape(
verts = self.read_in_template_bounds(
module=hexrd_resources,
file_name=f'TARDIS_IMAGE-PLATE-3_bnd_cropped.txt',
det=self.detector,
instr=self.instrument)
file_name=f'TARDIS_IMAGE-PLATE-3_bnd_cropped.txt'
)
kwargs = {'fill': False, 'lw': width, 'color': color, 'linestyle': '--'}
self.it.create_polygon(verts, **kwargs)
self.update_bbox_width(1330)
self.update_bbox_height(238)
self.it.update_style('--', width, color)

def crop_and_mask(self):
self.save_boundary_position()
Expand Down
Loading
Loading