pyvale 2025.7.1__cp311-cp311-win32.whl → 2025.7.2__cp311-cp311-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

@@ -84,6 +84,7 @@ class DICRegionOfInterest:
84
84
  self.height = None
85
85
  self.width = None
86
86
  self.subset_size = None
87
+ self.coord_label = None
87
88
 
88
89
  def interactive_selection(self, subset_size):
89
90
  """
@@ -117,6 +118,8 @@ class DICRegionOfInterest:
117
118
 
118
119
  # Create graphics widget
119
120
  self.graphics_widget = pg.GraphicsLayoutWidget()
121
+
122
+
120
123
 
121
124
  main_layout.addLayout(sidebar)
122
125
  main_layout.addWidget(self.graphics_widget)
@@ -165,7 +168,27 @@ class DICRegionOfInterest:
165
168
  self.buttons['undo_prev'].setEnabled(False)
166
169
  self.buttons['redo_prev'].setEnabled(False)
167
170
 
171
+ self.coord_label = QtWidgets.QLabel("(-, -)")
172
+ self.coord_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight)
173
+
174
+ # Set fixed width to handle largest expected value comfortably
175
+ self.coord_label.setMinimumWidth(350)
176
+ self.coord_label.setMaximumWidth(350)
177
+
178
+ self.coord_label.setStyleSheet("""
179
+ QLabel {
180
+ background-color: rgba(0, 0, 0, 150);
181
+ color: white;
182
+ padding: 5px;
183
+ border-radius: 3px;
184
+ font-family: monospace;
185
+ font-size: 12px;
186
+ }
187
+ """)
188
+
168
189
  sidebar.addStretch()
190
+ sidebar.addWidget(self.coord_label)
191
+
169
192
  return sidebar
170
193
 
171
194
  def _setup_graphics(self):
@@ -222,6 +245,24 @@ class DICRegionOfInterest:
222
245
  self.buttons[btn_id].clicked.connect(handler)
223
246
 
224
247
  self.main_view.scene().sigMouseClicked.connect(self._mouse_clicked)
248
+ self.main_view.scene().sigMouseMoved.connect(self._mouse_moved)
249
+
250
+
251
+ def _mouse_moved(self, pos):
252
+ """Handle mouse movement to update coordinate display."""
253
+ if self.main_view.sceneBoundingRect().contains(pos):
254
+ mouse_point = self.main_view.mapSceneToView(pos)
255
+ # Convert from graphics coordinates to image coordinates
256
+ img_x = int(round(mouse_point.x()))
257
+ img_y = int(round(self.width - mouse_point.y()))
258
+
259
+ # Clamp coordinates to image bounds
260
+ img_x = max(0, min(img_x, self.height - 1))
261
+ img_y = max(0, min(img_y, self.width - 1))
262
+
263
+ self.coord_label.setText(f"({img_x}, {img_y})")
264
+ else:
265
+ self.coord_label.setText("(-, -)")
225
266
 
226
267
  def _start_drawing_mode(self, mode):
227
268
  """Start drawing mode for specified shape type."""
@@ -536,7 +577,7 @@ class DICRegionOfInterest:
536
577
  self._update_button_states()
537
578
 
538
579
  def _save_interactive_roi(self):
539
- """Save the current ROI to a YAML file."""
580
+ """Save the current ROI to a YAML file. This only works with the interactive GUI."""
540
581
  filename, _ = QtWidgets.QFileDialog.getSaveFileName(self.main_window, 'Save ROI', 'roi_interactive.yaml', filter='YAML Files (*.yaml)')
541
582
 
542
583
  if filename:
@@ -566,7 +607,7 @@ class DICRegionOfInterest:
566
607
  yaml.dump(serialized, f, sort_keys=False)
567
608
 
568
609
  def _open_interactive_roi(self):
569
- """Open ROI from a YAML file."""
610
+ """Open ROI from a YAML file. This only works with the interactive GUI."""
570
611
  filename, _ = QtWidgets.QFileDialog.getOpenFileName(
571
612
  self.main_window, 'Open ROI', filter='YAML Files (*.yaml)'
572
613
  )
@@ -586,6 +627,7 @@ class DICRegionOfInterest:
586
627
  if entry.get('type') == 'SeedROI':
587
628
  # Restore the seed ROI
588
629
  x, y = entry['pos']
630
+ y = self.width-y
589
631
  size = entry.get('size', [10, 10]) # fallback default
590
632
  self.seed_roi = pg.RectROI(
591
633
  [x, y], size,
@@ -671,13 +713,13 @@ class DICRegionOfInterest:
671
713
  def _finalize_selection(self):
672
714
  """Process the final mask and seed location."""
673
715
  self.mask = np.flipud(self.temp_mask.T)
674
-
716
+
675
717
  if hasattr(self, 'seed_roi'):
676
718
  pos = self.seed_roi.pos()
677
719
  x = int(np.floor(pos.x()))
678
720
  y = int(np.floor(self.width - pos.y()))
679
721
  self.seed = [x, y]
680
-
722
+
681
723
  if not self.mask[y, x]:
682
724
  raise ValueError(f"Seed location [{x}, {y}] is not within the mask")
683
725
  print(f"Final seed location: [{x}, {y}]")
@@ -833,6 +875,111 @@ class DICRegionOfInterest:
833
875
  self.__roi_selected = True
834
876
 
835
877
 
878
+ def save_yaml(self, filename: str | Path) -> None:
879
+ """
880
+ Save the current ROI to a YAML file. This only works with the after having run the interactive GUI.
881
+
882
+ Parameters
883
+ ----------
884
+ filename : str or pathlib.Path
885
+ Filename of the YAML file to save the ROI data.
886
+
887
+ Raises
888
+ ------
889
+ ValueError
890
+ If no ROI has been selected.
891
+ """
892
+
893
+ if filename:
894
+
895
+ # Ensure extension is added if user doesn't include it
896
+ if filename and not filename.endswith('.yaml'):
897
+ filename += '.yaml'
898
+
899
+ print("Saving to file:", filename)
900
+ serialized = [
901
+ self._get_roi_data(roi, add)
902
+ for roi, add in zip(self.roi_list, self.add_list)
903
+ ]
904
+
905
+ # add ROI to serialized data
906
+ if hasattr(self, 'seed_roi'):
907
+ self._finalize_selection()
908
+ seed_data = {
909
+ 'type': 'SeedROI',
910
+ 'pos': [self.seed[0], self.seed[1]],
911
+ 'size': [self.subset_size, self.subset_size],
912
+ 'add': True
913
+ }
914
+ serialized.append(seed_data)
915
+
916
+ with open(filename, 'w') as f:
917
+ yaml.dump(serialized, f, sort_keys=False)
918
+
919
+ def read_yaml(self, filename: str | Path) -> None:
920
+ """
921
+ Load the ROI from a YAML file and restore the state of the GUI.
922
+ This method will clear existing ROIs and restore the state from the YAML file.
923
+
924
+ Parameters
925
+ ----------
926
+ filename : str or pathlib.Path
927
+ Path to the YAML file containing the ROI data.
928
+
929
+ Raises
930
+ ------
931
+ FileNotFoundError
932
+ If the specified file does not exist.
933
+ ValueError
934
+ If the loaded data is not a valid ROI format.
935
+ """
936
+
937
+ # need to create a temp qapplication so I can import the ROI.
938
+ self.__roi_selected = True
939
+
940
+ # Initialize GUI
941
+ self._setup_gui()
942
+ self._setup_graphics()
943
+ self._connect_signals()
944
+
945
+ if filename:
946
+ with open(filename, 'r') as f:
947
+ data = yaml.safe_load(f)
948
+
949
+ self.roi_list = []
950
+ self.add_list = []
951
+
952
+ self.seed_roi = None # Clear existing seed
953
+
954
+ for entry in data:
955
+ if entry.get('type') == 'SeedROI':
956
+ # Restore the seed ROI
957
+ x, y = entry['pos']
958
+ y = self.width-y
959
+ size = entry.get('size', [10, 10]) # fallback default
960
+ self.seed_roi = pg.RectROI(
961
+ [x, y], size,
962
+ pen=pg.mkPen('b', width=3),
963
+ hoverPen=pg.mkPen('y', width=3),
964
+ handlePen='#0000',
965
+ handleHoverPen='#0000'
966
+ )
967
+ self.main_view.addItem(self.seed_roi)
968
+
969
+ else:
970
+ # Restore standard ROI
971
+ roi = self._create_roi_from_data(entry)
972
+ self.roi_list.append(roi)
973
+ self.add_list.append(entry['add'])
974
+ self.main_view.addItem(roi)
975
+ roi.sigRegionChanged.connect(self._redraw_fill_layer)
976
+
977
+ self._redraw_fill_layer()
978
+ self._update_button_states()
979
+ self._finalize_selection()
980
+
981
+
982
+
836
983
  def show_image(self) -> None:
837
984
  """
838
985
  Displays the current mask in grayscale.
@@ -842,20 +989,30 @@ class DICRegionOfInterest:
842
989
  ValueError: If no ROI is selected.
843
990
  """
844
991
 
845
-
846
- if not self.__roi_selected:
847
- raise ValueError("No ROI selected with 'interactive_selection' or 'rect_boundary'")
992
+ # Convert grayscale image to 3-channel if needed
993
+ if self.ref_image.ndim == 2:
994
+ ref_image_color = cv2.cvtColor(self.ref_image.astype(np.uint8), cv2.COLOR_GRAY2BGR)
995
+ else:
996
+ ref_image_color = self.ref_image
848
997
 
849
998
  # Create a green mask image
850
- green_mask = np.zeros_like(self.ref_image)
999
+ if self.ref_image.ndim == 3:
1000
+ green_mask = np.zeros_like(self.ref_image)
1001
+ elif self.ref_image.ndim == 2:
1002
+ h, w = self.ref_image.shape
1003
+ green_mask = np.zeros((h, w, 3), dtype=self.ref_image.dtype)
1004
+ else:
1005
+ raise ValueError(f"Unsupported image shape: {self.ref_image.shape}")
851
1006
 
852
- green_mask[self.mask,:] = [0, 255, 0]
1007
+ # Apply the green mask
1008
+ green_mask[self.mask, :] = [0, 255, 0]
853
1009
 
854
- # Blend the original image and the mask
855
- blended = self.ref_image.astype(float) * 0.7 + green_mask.astype(float) * 0.3
1010
+ # Blend the original image and the green mask
1011
+ blended = ref_image_color.astype(float) * 0.7 + green_mask.astype(float) * 0.3
856
1012
  blended = blended.astype(np.uint8)
857
1013
 
858
1014
  # Display using Matplotlib
1015
+ import matplotlib.pyplot as plt
859
1016
  plt.figure()
860
1017
  plt.imshow(blended)
861
1018
  plt.axis('off')
pyvale/dicresults.py CHANGED
@@ -38,6 +38,8 @@ class DICResults:
38
38
  Final `xtol` value from the optimization routine, indicating solution tolerance.
39
39
  niter : np.ndarray
40
40
  Number of iterations taken to converge for each subset point.
41
+ shape_params : np.ndarray | None
42
+ Optional shape parameters if output during DIC calculation (e.g., affine, rigid).
41
43
  filenames : list[str]
42
44
  name of DIC result files that have been found
43
45
  """
@@ -52,4 +54,5 @@ class DICResults:
52
54
  ftol: np.ndarray
53
55
  xtol: np.ndarray
54
56
  niter: np.ndarray
57
+ shape_params: np.ndarray
55
58
  filenames: list[str]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyvale
3
- Version: 2025.7.1
3
+ Version: 2025.7.2
4
4
  Summary: An all-in-one package for sensor simulation, sensor uncertainty quantification, sensor placement optimisation and simulation calibration or validation.
5
5
  Author-email: "scepticalrabbit et al." <thescepticalrabbit@gmail.com>
6
6
  License: MIT License
@@ -14,13 +14,13 @@ pyvale/cameradata2d.py,sha256=SZW4EwP2maaJDoVywPvJ5CIzxE9M0T00v6YFMMXbXIY,2819
14
14
  pyvale/camerasensor.py,sha256=3j44NG5Odk4AzspXqHfJx5vWzAHDPg3dg4xoHWIpdiI,5479
15
15
  pyvale/camerastereo.py,sha256=L_HBN3JIGLkAMk1ZIvDye3xqwyVaudsM9NgyybD5rJM,10142
16
16
  pyvale/cameratools.py,sha256=_DTrvLMop2QoEdkUkr4dkiwZmNhxgnHv2Te7EKg0knM,19723
17
- pyvale/dataset.py,sha256=OzjDrqSee5jSV8y4AhQ_aSedqDftSBlCKH92Lk304NM,15354
18
- pyvale/dic2d.py,sha256=oisTCqSxRULme-5r2YfvNJe9mS1vw0yqvpRc9bNYe-U,7731
19
- pyvale/dic2dcpp.cp311-win32.pyd,sha256=3rkJFDNyIHHbuZxMv-6HjE2HzihBgnTtxnh6BobrS1Y,505344
20
- pyvale/dicchecks.py,sha256=cmJbgCLjaEblBnP45R_bnrwAXTUqO91b8Diz0wimKdg,16488
21
- pyvale/dicdataimport.py,sha256=2Qht6OoLXO9nK7_jt1POR3qbn0thWYedBFJ-w9YwGkU,7438
22
- pyvale/dicregionofinterest.py,sha256=1d3tqnvQTQU88Qz7ISpOsUPMrdm8Ty9RJXzC0J-_kqs,33768
23
- pyvale/dicresults.py,sha256=bZnA9Yu348DYVE80DkcNeSu-Ddh7GQNnENz5_e1bPZU,1938
17
+ pyvale/dataset.py,sha256=d9W8RhHoUJDVk4bxU1GkkmQARuiyfxGnzjb-q3tJWOw,15356
18
+ pyvale/dic2d.py,sha256=oKnoSARBO5f23NTenBlEkguWs7mQCTP-57v_hTZPU2M,8798
19
+ pyvale/dic2dcpp.cp311-win32.pyd,sha256=JwvPOvCdeOltLGqCc1k-wUeJnROqiioOktIRUtQwLdI,519168
20
+ pyvale/dicchecks.py,sha256=h1Aja0F8aBHMTsNRif8imlJDUsZ8aWUK4PjWa8KwOLo,17241
21
+ pyvale/dicdataimport.py,sha256=498Z1URii8kHYqoj4GqCshms-JApwhyBsVJXp6FFk3c,12233
22
+ pyvale/dicregionofinterest.py,sha256=cEIMFBMqAyMQmaAGtTO7oZEY2t5Ddi5gb7D8kabwEiQ,39428
23
+ pyvale/dicresults.py,sha256=68AaSnWooFzJpBTmB0aAbWQiUIF6cVldCZn8BIP9b0k,2097
24
24
  pyvale/dicspecklegenerator.py,sha256=IvAuEXXn_B8aKlDORFylXMcvVoMYnsqeqDFcyFg9Ktw,8057
25
25
  pyvale/dicspecklequality.py,sha256=_-Ym4eloquvqWYBWwXtp-u6bbUYkIAgAKwb6lj2LItM,10273
26
26
  pyvale/dicstrain.py,sha256=IV2F7eEkRRkmmEIhtmCWar_k7mMq-VFUYldTC4FYd_I,13174
@@ -74,8 +74,8 @@ pyvale/visualsimplotter.py,sha256=yF11R-m9NSz4WPMjpN5qJqZm1fzhn5l6SnXIeJQ9Pmg,69
74
74
  pyvale/visualsimsensors.py,sha256=t-2tJJoown9xGezrub-EWJSRgoOH7On1FI3gIPvPPu0,12723
75
75
  pyvale/visualtools.py,sha256=CfrRYFIKEBl66kZuhLchG-tgDQiUp-nC2sTCylQqejs,4952
76
76
  pyvale/visualtraceplotter.py,sha256=1u9x3AfnzXS0fF8EAUm-v_E-xYXor7STlsoWob_-iCc,5629
77
- pyvale/cython/rastercyth.c,sha256=xch6omzS1fIbZ8oAbMTY3BCRoWkvatIeqrAIHJR2PN8,1282853
78
- pyvale/cython/rastercyth.cp311-win32.pyd,sha256=j81BAta7lc2w9HaRiShkKcgKPcjtIPGJEJ82mjv34XU,143360
77
+ pyvale/cython/rastercyth.c,sha256=d-JXXcD03qJvkJ5tZha_IeVGuM_-9wyHxVXep48Bb8c,1282853
78
+ pyvale/cython/rastercyth.cp311-win32.pyd,sha256=tCtwAycoNCeDgeHN-P066R7O-qQPf_ono6yumkGrHfs,143360
79
79
  pyvale/cython/rastercyth.py,sha256=sifuWGmgB0Z8MhQTigNt9lMEMwY3oI9G0Q9a1vQQEYw,27096
80
80
  pyvale/data/DIC_Challenge_Star_Noise_Def.tiff,sha256=no_q1L4_0plbVmg3TPEpgoRp3iLMrx2vH_X1fBwnLSw,2020090
81
81
  pyvale/data/DIC_Challenge_Star_Noise_Ref.tiff,sha256=y0JSFyHvmO_cgabG8hOej5HioQ_9Bh7O8VYVTfVr_S8,2020102
@@ -103,15 +103,16 @@ pyvale/data/plate_rigid_def0000.tiff,sha256=YlGU0lIlkh61StQku7lK7P6oDZDa-g5R98fU
103
103
  pyvale/data/plate_rigid_def0001.tiff,sha256=CFIveUYubbbUDpQfnsO0iPaBTzwbjQbcAOCG1mm2040,1601722
104
104
  pyvale/data/plate_rigid_ref0000.tiff,sha256=EolObMm5QzGeewgq3bLhlkHor_6ASuNoYrV2AbYrFro,1601722
105
105
  pyvale/dic/cpp/dicbruteforce.cpp,sha256=_LbVdgrRrErF-h3AxwUYAz5bpw2KduA035BCOEWyXdo,12285
106
- pyvale/dic/cpp/dicfourier.cpp,sha256=bs-t4koUz5Pd-UTnEC4wzhboHLJcD7GbPYjwQ9Ps78M,24196
107
- pyvale/dic/cpp/dicinterpolator.cpp,sha256=BzO3atEcu-ouGjBjhKeEttKgTlG5GcesJ5KYvvRF8MA,20884
108
- pyvale/dic/cpp/dicmain.cpp,sha256=BL7-02_ZByZLC_c5rjecVAM1N6DgJQAi6eGT2LJS8vk,9075
109
- pyvale/dic/cpp/dicoptimizer.cpp,sha256=6Q4hcqqolO1MGhvXGTGDrdpAfNJeghVrpsu3z151FRw,26604
106
+ pyvale/dic/cpp/dicfourier.cpp,sha256=jmbuLZI-ETpmEMqxeY83MfX8X-ZEJ-zjRfmVQzUBKGU,25382
107
+ pyvale/dic/cpp/dicinterpolator.cpp,sha256=8lwj8sBHx3nnpUq9dqUOVif9KwIAEhG-w28CVq2AjTE,22451
108
+ pyvale/dic/cpp/dicmain.cpp,sha256=MsTgGsL7gFokDF-34iAzI_v0B_XQkEirUsjC65U56IQ,9269
109
+ pyvale/dic/cpp/dicoptimizer.cpp,sha256=Vqahn6nMbUDGVJTsQ_Q2HQDg1xJ2ddvUJYAlp6FvtWE,26858
110
110
  pyvale/dic/cpp/dicrg.cpp,sha256=ZAgXQnPP55HAU7VhPVcchtvIgQVy3ele7-zZKPAc04k,4488
111
- pyvale/dic/cpp/dicscanmethod.cpp,sha256=-hXZ3YMc03HlMvCMIFD2A203Bjy8_FhDTv0_Tqb_WzI,27443
111
+ pyvale/dic/cpp/dicscanmethod.cpp,sha256=Md17AdPfV7T4cmQQTWV1fBb2KxkL19nqYmvgQl745ZM,27754
112
+ pyvale/dic/cpp/dicsignalhandler.cpp,sha256=XL5e67jlrqyT7wY9nL8n0aYKU7ASzqlC9-YhJ0Aj9TU,491
112
113
  pyvale/dic/cpp/dicsmooth.cpp,sha256=voV7Ge1jqaW3A-87ORxVMv_JFfBlW9_pFoi6NZfoUAs,4583
113
- pyvale/dic/cpp/dicstrain.cpp,sha256=Sr8sHi3T6Sly0P6h6eTH-K9u5CiQU1ZWjaj6XKtEYhQ,14400
114
- pyvale/dic/cpp/dicutil.cpp,sha256=TxBwxa89xEaduDxxq8JPeRpj-dSi8Pb-xlI7dY_-J7I,20392
114
+ pyvale/dic/cpp/dicstrain.cpp,sha256=s3J4MTEuIbHHUbrPuWDqwL78DI0FgcdUyHIE5YbLr7M,14631
115
+ pyvale/dic/cpp/dicutil.cpp,sha256=ci2zKFbI9YmY9bJLhNhp76hnb4Yd7JH3RtArRUDbW2E,22314
115
116
  pyvale/examples/__init__.py,sha256=qCiIGOM2Oxw7TsjsIvYR054rhhoHzLKX2mCJve9NaJk,275
116
117
  pyvale/examples/basics/ex1_1_basicscalars_therm2d.py,sha256=IlGUDXAXqWycEV7TUiUoy_TmYv6-1YbuLas1n7xpDcc,6035
117
118
  pyvale/examples/basics/ex1_2_sensormodel_therm2d.py,sha256=zDrcPY_z8yeXHtlBzFV-l5CIVn-CBc_IDhJtBU0Sz8M,6048
@@ -204,8 +205,8 @@ pyvale/simcases/run_1case.py,sha256=srR8bs3pKhPaF_E4nqLsMXO1ivtK5WKRWIZ0O6pXGRs,
204
205
  pyvale/simcases/run_all_cases.py,sha256=x6IhG7jalAPuZRFdNTH9oof9L_Nol5vWjjU_lPi5i0Q,1972
205
206
  pyvale/simcases/run_build_case.py,sha256=3FaSjQrYxVmmKAC_CvORAvFr6Xwo0pEOjiWTzG7fMbU,2002
206
207
  pyvale/simcases/run_example_cases.py,sha256=6-gUDPqPmBj01q4CcsG5MiVWqt71BP4J85fWGOuS3Eg,1979
207
- pyvale-2025.7.1.dist-info/licenses/LICENSE,sha256=PLyswAYGHdw3qwnrd4I8glj6pc89FgAgY6W1VtK0NT0,1119
208
- pyvale-2025.7.1.dist-info/METADATA,sha256=i6Quq3QBuJ3oPcGjTuZzDeIM1uxeQBHNfQNz4zG5mnE,6485
209
- pyvale-2025.7.1.dist-info/WHEEL,sha256=Ri8zddKrjGdgjlj1OpSsvpDnvHfnQhMQWi3E_v2pqng,97
210
- pyvale-2025.7.1.dist-info/top_level.txt,sha256=u1d_f4iZ3b3_96Rb_zrs9hyrpC4yE5e1Lg6Ey_Wgr0c,7
211
- pyvale-2025.7.1.dist-info/RECORD,,
208
+ pyvale-2025.7.2.dist-info/licenses/LICENSE,sha256=PLyswAYGHdw3qwnrd4I8glj6pc89FgAgY6W1VtK0NT0,1119
209
+ pyvale-2025.7.2.dist-info/METADATA,sha256=Azlf3gsqC9ejnFAdvz3DR6NMNHiYs7fj_3mWs5dHyJk,6485
210
+ pyvale-2025.7.2.dist-info/WHEEL,sha256=Ri8zddKrjGdgjlj1OpSsvpDnvHfnQhMQWi3E_v2pqng,97
211
+ pyvale-2025.7.2.dist-info/top_level.txt,sha256=u1d_f4iZ3b3_96Rb_zrs9hyrpC4yE5e1Lg6Ey_Wgr0c,7
212
+ pyvale-2025.7.2.dist-info/RECORD,,