Source code for wolfhece.apps.curvedigitizer

"""
Author: HECE - University of Liege, Pierre Archambeau
Date: 2024

Copyright (c) 2024 University of Liege. All rights reserved.

This script and its content are protected by copyright law. Unauthorized
copying or distribution of this file, via any medium, is strictly prohibited.
"""

import ctypes
[docs] myappid = 'wolf_hece_uliege' # arbitrary string
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) from ..PyTranslate import _ from ..matplotlib_fig import Matplotlib_Figure, PRESET_LAYOUTS import wx import numpy as np import matplotlib.pyplot as plt import matplotlib.image as mpimg from matplotlib.axes import Axes from matplotlib.figure import Figure from matplotlib.backend_bases import KeyEvent, MouseEvent from PIL import Image, ImageOps import logging
[docs] class Digitizer: def __init__(self): """ Main function of curve digitizer """ plt.ion() # self.curves=[] # open the dialog file = wx.FileDialog(None,_("Select image to digitize"), wildcard="gif image (*.gif)|*.gif|jpeg image (*.jpg)|*.jpg|png image (*.png)|*.png|All files (*.*)|*.*",) if file.ShowModal() == wx.ID_CANCEL: return else: #récuparétaion du nom de fichier avec chemin d'accès self.filein =file.GetPath() # show the image self.figure = Matplotlib_Figure(PRESET_LAYOUTS.DEFAULT_EQUAL) self.figure.cur_ax.set_aspect('equal') self.figure.fig_properties._axes[0]._equal_axis == 1 # win = self.figure._collaps_pane.GetPane() # self._convert_xy = wx.Button(win, -1, 'Convert XY to world coordinates') # self._convert_xy.Bind(wx.EVT_BUTTON, self.convert_xy) # self.figure._sizer_xls.Add(self._convert_xy, 0, wx.EXPAND) # self.figure.Layout() self.figure.add_image(self.filein, origin='lower') self.fig.tight_layout() self.ref_x = [] self.ref_y = [] self.ref_x_length = 0 self.ref_y_length = 0 self.xy = [] # get reference length in x direction wx.MessageBox(_("Use SHIFT + Right Mouse Button to select two points as X reference.\n\nWe will use only the delta X to calculate the scaling factor.\nSo, the Y distance will be ignored."),_("Select reference X")) self.new_line(is_world=False, label = 'Reference X', color='black', linewidth=2) self.figure.action = ('Ref X', self._callback_pt) @property
[docs] def ax(self) -> Axes: return self.figure.ax[0]
@property
[docs] def fig(self) -> Figure: return self.figure.fig
# def convert_xy(self, event): # """ # Convert the pixel coordinates to world coordinates # """ # xy = self.figure.get_xy_from_grid() # xy[:,0] = (xy[:,0] - self.origin_img[0]) * self.factor_X + self.origin_world[0] # xy[:,1] = (xy[:,1] - self.origin_img[1]) * self.factor_Y + self.origin_world[1] # self.figure.fill_grid_with_xy_np(xy)
[docs] def new_line(self, is_world:bool = True, ax=None, **kwargs): line_props = self.figure.new_line(ax=ax, **kwargs) if is_world: line_props.xscale = self.factor_X line_props.yscale = self.factor_Y line_props.xorigin_world = self.origin_world[0] line_props.yorigin_world = self.origin_world[1] line_props.xorigin_local = self.origin_img[0] line_props.yorigin_local = self.origin_img[1] line_props.populate()
[docs] def _callback_digitize(self, xy, which): if which == 'Digitize': pass # self.xy.append(xy) elif which == 'End Digitize': MsgBox = wx.MessageDialog(None,_("Digitize another curve?"),style=wx.YES_NO) reply=MsgBox.ShowModal() if reply == wx.ID_YES: self.new_line() else: self.figure.action = None
[docs] def _callback_origin(self, xy, which): if which == 'Origin': self.origin_img = xy valid_origin = False while not valid_origin: dlg = wx.TextEntryDialog(None,_("Set the origin coordinate (X,Y)"),_("Set the origin"), "0,0") ret = dlg.ShowModal() if ret == wx.ID_OK: origin = dlg.GetValue().split(',') try: self.origin_world = (float(origin[0]),float(origin[1])) valid_origin = True except: valid_origin = False wx.MessageBox(_("Please digitize the curve.\n\n" + " - MAJ + Right click : add point\n"+ " - Press Enter : finish"), _("Digitize curve")) self.new_line(is_world = True, label = 'Curve', linewidth=1.5) self.figure.action = ('Digitize', self._callback_digitize)
[docs] def _callback_pt(self, xy, which): if which == 'Ref X': self.ref_x.append(xy) if len(self.ref_x) == 2: validLength = False dlg=wx.TextEntryDialog(None,_("Enter the reference length [user unit | mm | cm | m | km]")) while not validLength: dlg.ShowModal() try: self.ref_x_length = float(dlg.GetValue()) if self.ref_x_length > 0: validLength = True except: validLength = False dlg.Destroy() # calculate scaling factor deltaref = np.abs(self.ref_x[1][0] - self.ref_x[0][0]) self.factor_X = self.ref_x_length / deltaref reply = wx.MessageDialog(None,"{:4.0f} pixels in {:s} direction corresponding to {:4.4f} units. Is this correct?".format(deltaref, 'X', self.ref_x_length),style=wx.YES_NO) if reply.ShowModal() == wx.ID_NO: logging.info(_('Retry !')) self.ref_x = [] self.ref_x_length = 0 else: self.figure.action = None MsgBox = wx.MessageDialog(None,_('Do you want to use the same reference along Y?'),style=wx.YES_NO) result=MsgBox.ShowModal() if result == wx.ID_YES: self.factor_Y = self.factor_X wx.MessageBox(_("Click one point for a reference in local axis (s,z)"),_("Select an origin")) self.new_line(is_world = False, label = 'Origin', color='red', linewidth=4) self.figure.action = ('Origin', self._callback_origin) else: # get the reference length in y direction self.new_line(is_world = False, label = 'Reference Y', color='black', linewidth=2) wx.MessageBox(_("Use SHIFT + Right Mouse Button to select two points as Y reference.\n\nWe will use only the delta Y to calculate the scaling factor.\nSo, the X distance will be ignored."),_("Select reference Y")) self.figure.action = ('Ref Y', self._callback_pt) elif which == 'Ref Y': self.ref_y.append(xy) if len(self.ref_y) == 2: validLength = False dlg=wx.TextEntryDialog(None,_("Enter the reference length [user unit | mm | cm | m | km]")) while not validLength: dlg.ShowModal() try: self.ref_y_length = float(dlg.GetValue()) if self.ref_y_length > 0: validLength = True except: validLength = False dlg.Destroy() # calculate scaling factor deltaref = np.abs(self.ref_y[1][1] - self.ref_y[0][1]) self.factor_Y = self.ref_y_length / deltaref reply = wx.MessageDialog(None,"{:4.0f} pixels in {:s} direction corresponding to {:4.4f} units. Is this correct?".format(deltaref, 'Y', self.ref_y_length),style=wx.YES_NO) if reply.ShowModal() == wx.ID_NO: logging.info(_('Retry !')) self.ref_y = [] self.ref_y_length = 0 else: wx.MessageBox(_("Click one point for a reference in local axis (s,z)"),_("Select an origin")) self.new_line(is_world = False, label = 'Origin', color='red', linewidth=4) self.figure.action = ('Origin', self._callback_origin)
if __name__ == "__main__": # run the main function
[docs] ex = wx.App()
digit = Digitizer() ex.MainLoop()