drap 0.0.4.post9__tar.gz → 0.0.4.post11__tar.gz

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.
Files changed (22) hide show
  1. {drap-0.0.4.post9 → drap-0.0.4.post11}/PKG-INFO +1 -1
  2. {drap-0.0.4.post9 → drap-0.0.4.post11}/pyproject.toml +1 -1
  3. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/utils.py +262 -68
  4. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap.egg-info/PKG-INFO +1 -1
  5. {drap-0.0.4.post9 → drap-0.0.4.post11}/LICENSE +0 -0
  6. {drap-0.0.4.post9 → drap-0.0.4.post11}/MANIFEST.in +0 -0
  7. {drap-0.0.4.post9 → drap-0.0.4.post11}/README.md +0 -0
  8. {drap-0.0.4.post9 → drap-0.0.4.post11}/setup.cfg +0 -0
  9. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/__init__.py +0 -0
  10. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/automation.py +0 -0
  11. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/gui.py +0 -0
  12. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/main.py +0 -0
  13. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/qt_adjust.py +0 -0
  14. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/resources/DrapuserGuide_eng.pdf +0 -0
  15. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/resources/DrapuserGuide_pt.pdf +0 -0
  16. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/resources/name_videos.dat +0 -0
  17. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap/terminal_interface.py +0 -0
  18. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap.egg-info/SOURCES.txt +0 -0
  19. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap.egg-info/dependency_links.txt +0 -0
  20. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap.egg-info/entry_points.txt +0 -0
  21. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap.egg-info/requires.txt +0 -0
  22. {drap-0.0.4.post9 → drap-0.0.4.post11}/src/drap.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drap
3
- Version: 0.0.4.post9
3
+ Version: 0.0.4.post11
4
4
  Summary: Tool for analyzing droplet size and concentration using video and EDF images
5
5
  Author-email: "Gabriel Braga Marques Teobaldo, Oleg Prymak, Natalie Wolff, Matthias Epple, Marco Aurélio Brizzotti Andrade, Cássio Alves and Cristiano Luis Pinto de Oliveira" <crislpo@ufpr.br>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "drap"
7
- version = "v0.0.4.post9"
7
+ version = "v0.0.4.post11"
8
8
  description = "Tool for analyzing droplet size and concentration using video and EDF images"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,8 +1,8 @@
1
1
  from PyQt5.QtWidgets import (QApplication, QProgressDialog, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QFileDialog,
2
2
  QMessageBox, QLineEdit, QHBoxLayout, QGroupBox, QCheckBox, QSlider, QDialog, QDialogButtonBox,
3
- QComboBox)
3
+ QComboBox, QGridLayout, QSpinBox)
4
4
  from PyQt5.QtGui import QPixmap, QPainter, QPen, QImage, QMouseEvent, QColor
5
- from PyQt5.QtCore import Qt, QPoint, QRect, QFileInfo, QTimer, QEvent
5
+ from PyQt5.QtCore import Qt, QPoint, QRect, QFileInfo, QTimer, QEvent, QSize
6
6
  from fabio.edfimage import EdfImage
7
7
  import tkinter as tk
8
8
  from tkinter import filedialog
@@ -105,8 +105,8 @@ class ImageCropper(QMainWindow):
105
105
 
106
106
  def initUI(self):
107
107
 
108
- self.test = True
109
- # self.test = False
108
+ # self.test = True
109
+ self.test = False
110
110
  # print("teste")
111
111
 
112
112
 
@@ -140,7 +140,7 @@ class ImageCropper(QMainWindow):
140
140
  # Layout de controles do player de vídeo (abaixo do vídeo)
141
141
  self.video_controls_layout = QVBoxLayout()
142
142
  self.image_layout.addLayout(self.video_controls_layout)
143
-
143
+
144
144
  # progress bar
145
145
  self.video_slider = QSlider(Qt.Horizontal)
146
146
  self.video_bar_time_layout.addWidget(self.video_slider)
@@ -150,8 +150,19 @@ class ImageCropper(QMainWindow):
150
150
  self.time_label = QLabel('00:00 / 00:00')
151
151
  self.video_bar_time_layout.addWidget(self.time_label)
152
152
 
153
+ self.info_labels_layout = QHBoxLayout()
153
154
  self.mouse_label = QLabel('Mouse: (0,0)')
154
- self.video_bar_time_layout.addWidget(self.mouse_label)
155
+ self.image_size_label = QLabel("Image size: 0 x 0")
156
+
157
+ self.info_labels_layout.addWidget(self.mouse_label)
158
+ self.info_labels_layout.addWidget(self.image_size_label)
159
+ self.info_labels_layout.addStretch()
160
+
161
+
162
+ self.video_bar_time_layout.addLayout(self.info_labels_layout)
163
+
164
+
165
+ # self.video_bar_time_layout.addWidget(self.image_size_label)
155
166
 
156
167
  # Timer para reprodução de vídeo
157
168
  self.video_timer = QTimer()
@@ -205,6 +216,41 @@ class ImageCropper(QMainWindow):
205
216
  self.speed_slider.valueChanged.connect(self.update_speed)
206
217
 
207
218
 
219
+ # === Painel de coordenadas do retângulo ===
220
+ self.rect_group = QGroupBox("Rectangle Position and Size")
221
+ self.rect_layout = QGridLayout()
222
+ self.rect_group.setLayout(self.rect_layout)
223
+
224
+ # Cria os 4 campos (x, y, largura, altura)
225
+ self.rect_x_spin = QSpinBox()
226
+ self.rect_y_spin = QSpinBox()
227
+ self.rect_w_spin = QSpinBox()
228
+ self.rect_h_spin = QSpinBox()
229
+
230
+ # Rótulos
231
+ self.rect_layout.addWidget(QLabel("X:"), 0, 0)
232
+ self.rect_layout.addWidget(self.rect_x_spin, 0, 1)
233
+ self.rect_layout.addWidget(QLabel("Y:"), 0, 2)
234
+ self.rect_layout.addWidget(self.rect_y_spin, 0, 3)
235
+ self.rect_layout.addWidget(QLabel("Width:"), 1, 0)
236
+ self.rect_layout.addWidget(self.rect_w_spin, 1, 1)
237
+ self.rect_layout.addWidget(QLabel("Height:"), 1, 2)
238
+ self.rect_layout.addWidget(self.rect_h_spin, 1, 3)
239
+
240
+ # Adiciona ao layout principal lateral
241
+ self.video_controls_layout.addWidget(self.rect_group)
242
+
243
+ # Limites padrão (atualizados quando o vídeo é carregado)
244
+ for spin in [self.rect_x_spin, self.rect_y_spin, self.rect_w_spin, self.rect_h_spin]:
245
+ spin.setRange(0, 9999)
246
+ spin.setSingleStep(1)
247
+
248
+ # Conectar mudanças dos campos ao redesenho do retângulo
249
+ self.rect_x_spin.valueChanged.connect(self.update_rect_from_spinboxes)
250
+ self.rect_y_spin.valueChanged.connect(self.update_rect_from_spinboxes)
251
+ self.rect_w_spin.valueChanged.connect(self.update_rect_from_spinboxes)
252
+ self.rect_h_spin.valueChanged.connect(self.update_rect_from_spinboxes)
253
+
208
254
 
209
255
 
210
256
  # Layout to controls
@@ -323,8 +369,8 @@ class ImageCropper(QMainWindow):
323
369
  if self.test:
324
370
  self.load_image()
325
371
  self.int_input1.setText("45.")
326
- self.int_input2.setText("10")
327
- self.int_input3.setText("1000")
372
+ self.int_input2.setText("1")
373
+ self.int_input3.setText("25")
328
374
  self.int_input4.setText("1.0")
329
375
 
330
376
  self.show()
@@ -337,7 +383,8 @@ class ImageCropper(QMainWindow):
337
383
 
338
384
 
339
385
  if self.test:
340
- self.file_path = "/home/standard02/Documents/programming/python/bolhas/test/2024-07-10-water-without-absolute-intensity.flv"
386
+ self.file_path = "/home/standard02/Documents/programming/python/bolhas/PyPI/drap/teste.mp4"
387
+ # "/home/standard02/Documents/programming/python/bolhas/PyPI/drap/teste_completo.mp4" teste_bolha.mp4
341
388
  # self.file_path, _ = QFileDialog.getOpenFileName(self, 'Open Video', '', 'Videos (*.avi *.mp4 *.mov *.mkv *.wmv *.flv *.mpg *.mpeg *.3gp *.ogv .webm)')
342
389
  else:
343
390
  self.file_path, _ = QFileDialog.getOpenFileName(self, 'Open Video', '', 'Videos (*.avi *.mp4 *.mov *.mkv *.wmv *.flv *.mpg *.mpeg *.3gp *.ogv .webm)')
@@ -379,9 +426,30 @@ class ImageCropper(QMainWindow):
379
426
  self.image = qimg.copy()
380
427
  self.pixmap = QPixmap.fromImage(self.image)
381
428
  self.image_label.setPixmap(self.pixmap) #show image
429
+ self.image_label.adjustSize()
430
+ self.original_image = self.pixmap.toImage()
382
431
  # self.image_label.setScaledContents(True)
432
+ self.image_label.setScaledContents(False)
433
+ self.image_label.setAlignment(Qt.AlignCenter)
434
+
435
+
436
+ self.image_width = self.pixmap.width()
437
+ self.image_height = self.pixmap.height()
438
+ self.update_rect_limits()
439
+
383
440
  self.current_rect = QRect()
384
- self.update_image()
441
+ self.update_image()
442
+ self.img_size = [frame.shape[1], frame.shape[0]]
443
+
444
+ self.image_size_label.setText(f"Image size: {self.img_size[1]} × {self.img_size[0]}")
445
+
446
+ # Limitar X e Y dentro dos limites da imagem
447
+ self.rect_x_spin.setRange(0, self.img_size[0] - 1 )
448
+ self.rect_y_spin.setRange(0, self.img_size[1] - 1 )
449
+
450
+ # Limitar largura e altura para não ultrapassar o tamanho da imagem
451
+ self.rect_w_spin.setRange(0, self.img_size[0] - self.rect_x_spin.value())
452
+ self.rect_h_spin.setRange(0, self.img_size[1] - self.rect_y_spin.value())
385
453
 
386
454
  # Reseta variáveis de estado
387
455
  self.fps = int(self.video.get(cv2.CAP_PROP_FPS))
@@ -485,8 +553,12 @@ class ImageCropper(QMainWindow):
485
553
  self.image = q_image.copy()
486
554
  self.pixmap = QPixmap.fromImage(self.image)
487
555
  self.image_label.setPixmap(self.pixmap)
488
-
489
- self.update_image()
556
+ self.image_label.adjustSize()
557
+ self.image_label.setPixmap(self.pixmap)
558
+ self.image_width = w
559
+ self.image_height = h
560
+ self.update_rect_limits()
561
+ # self.update_image()
490
562
 
491
563
 
492
564
 
@@ -505,7 +577,7 @@ class ImageCropper(QMainWindow):
505
577
 
506
578
  current_time = self.current_frame / self.fps if self.fps else 0
507
579
  total_time = self.total_frames / self.fps if self.fps else 0
508
- time_str = f"{self.format_time(current_time)} ({self.current_frame} frame) / {self.format_time(total_time)} min"
580
+ time_str = f"{self.format_time(current_time)} min / {self.format_time(total_time)} min ({current_time:.2f} s - frame: {self.current_frame})"
509
581
  self.time_label.setText(time_str)
510
582
 
511
583
  def format_time(self, seconds):
@@ -569,7 +641,7 @@ class ImageCropper(QMainWindow):
569
641
  layout.addWidget(end_input)
570
642
 
571
643
  # keep decider when the frame will save
572
- keep_decider_label = QLabel("Output FPS:")
644
+ keep_decider_label = QLabel("Keep frames each second:")
573
645
  keep_decider_input = QLineEdit(str(self.fps))
574
646
  layout.addWidget(keep_decider_label)
575
647
  layout.addWidget(keep_decider_input)
@@ -621,26 +693,18 @@ class ImageCropper(QMainWindow):
621
693
 
622
694
  w_in = int(video_in.get(cv2.CAP_PROP_FRAME_WIDTH))
623
695
  h_in = int(video_in.get(cv2.CAP_PROP_FRAME_HEIGHT))
624
- display_w = self.image_label.width()
625
- display_h = self.image_label.height()
626
- scale_x = w_in / display_w
627
- scale_y = h_in / display_h
628
696
 
629
697
 
630
698
  if crop_rect is not None:
631
699
  x, y, w_out, h_out = crop_rect
632
- x = int(x * scale_x)
633
- y = int(y * scale_y)
634
- w_out = int(w_out * scale_x)
635
- h_out = int(h_out * scale_y)
636
-
637
- # x = max(0, min(x, w_in - 1))
638
- # y = max(0, min(y, h_in - 1))
639
- # w_out = min(w_out, w_in - x)
640
- # h_out = min(h_out, h_in - y)
700
+ x = max(0, min(x, w_in - 1))
701
+ y = max(0, min(y, h_in - 1))
702
+ w_out = min(w_out, w_in - x)
703
+ h_out = min(h_out, h_in - y)
704
+
641
705
  else:
642
- w_out = w_in
643
- h_out = h_in
706
+ x, y = 0, 0
707
+ w_out, h_out = w_in, h_in
644
708
 
645
709
  size = (abs(w_out), abs(h_out))
646
710
 
@@ -774,28 +838,21 @@ class ImageCropper(QMainWindow):
774
838
  return None
775
839
 
776
840
  label_size = self.image_label.size()
777
- pm = self.pixmap
778
- pm_size = pm.size()
841
+ pixmap_size = self.pixmap.size()
779
842
 
780
-
781
- scaled_pm = pm.scaled(label_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
782
-
783
- x_off = (label_size.width() - scaled_pm.width()) // 2
784
- y_off = (label_size.height() - scaled_pm.height()) // 2
843
+ # Calcula o offset (bordas pretas) se a imagem estiver centralizada
844
+ x_offset = max((label_size.width() - pixmap_size.width()) // 2, 0)
845
+ y_offset = max((label_size.height() - pixmap_size.height()) // 2, 0)
785
846
 
786
-
787
- sx = pos.x() - x_off
788
- sy = pos.y() - y_off
789
- if sx < 0 or sy < 0 or sx >= scaled_pm.width() or sy >= scaled_pm.height():
790
- return None # fora da imagem
847
+ # Remove o deslocamento
848
+ x = pos.x() - x_offset
849
+ y = pos.y() - y_offset
791
850
 
792
-
793
- img_w = pm.width()
794
- img_h = pm.height()
795
- ix = int(sx * img_w / scaled_pm.width())
796
- iy = int(sy * img_h / scaled_pm.height())
797
-
798
- return QPoint(ix, iy)
851
+ # Garante que está dentro da imagem
852
+ if 0 <= x < pixmap_size.width() and 0 <= y < pixmap_size.height():
853
+ return QPoint(x, y)
854
+ else:
855
+ return None
799
856
 
800
857
 
801
858
 
@@ -995,36 +1052,48 @@ class ImageCropper(QMainWindow):
995
1052
 
996
1053
  def eventFilter(self, obj, event):
997
1054
 
998
-
999
- if obj == self.image_label and (self.original_image is not None):
1000
-
1055
+ if obj == self.image_label and (self.original_image is not None):
1056
+
1057
+ # Atualiza posição do mouse (mesmo sem clicar)
1058
+ if event.type() == QEvent.MouseMove:
1059
+ pos = event.pos()
1060
+ mapped = self.label_pos_to_image_pos(pos)
1061
+ if mapped:
1062
+ self.mouse_label.setText(f"Mouse: ({mapped.x()}, {mapped.y()})")
1063
+
1064
+ # Início do desenho do retângulo
1001
1065
  if event.type() == QEvent.MouseButtonPress and event.button() == Qt.LeftButton:
1002
1066
  mapped = self.label_pos_to_image_pos(event.pos())
1003
1067
  if mapped is not None:
1004
1068
  self.drawing = True
1005
1069
  self.rect_start = mapped
1006
- self.current_rect = QRect(self.rect_start, self.rect_start)
1007
- self.update_image()
1070
+ self.current_rect = QRect(self.rect_start, QSize())
1071
+ self.update_image() # desenha imediatamente, sem atualizar limites
1072
+ self.update_spinboxes_from_rect()
1008
1073
 
1009
- elif event.type() == QEvent.MouseMove and self.drawing:
1074
+ # Movimento do mouse durante o desenho
1075
+ elif event.type() == QEvent.MouseMove and getattr(self, "drawing", False):
1010
1076
  mapped = self.label_pos_to_image_pos(event.pos())
1011
1077
  if mapped is not None:
1012
1078
  self.current_rect = QRect(self.rect_start, mapped).normalized()
1013
- self.update_image()
1079
+ self.update_image() # redesenha em tempo real (não mexe nos spinboxes ainda)
1014
1080
 
1081
+ # Soltar o botão: finalize o desenho
1015
1082
  elif event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton:
1016
- if self.drawing:
1017
- self.drawing = False
1083
+ if getattr(self, "drawing", False):
1084
+ # self.drawing = False
1018
1085
  mapped = self.label_pos_to_image_pos(event.pos())
1019
1086
  if mapped is not None:
1020
1087
  self.current_rect = QRect(self.rect_start, mapped).normalized()
1021
- self.update_image()
1022
- # x, y, w, h = self.current_rect.getRect()
1023
- # self.crop_rect = (x, y, w, h)
1024
-
1088
+ self.update_image() # mantém o desenho visível
1089
+ self.update_spinboxes_from_rect() # atualiza campos
1090
+ self.update_rect_limits() # aplica os limites no final
1091
+ self.drawing = False
1092
+
1025
1093
  return super().eventFilter(obj, event)
1026
1094
 
1027
1095
 
1096
+
1028
1097
  def crop_image(self):
1029
1098
 
1030
1099
  if not hasattr(self, "original_image") or self.original_image is None:
@@ -1075,7 +1144,7 @@ class ImageCropper(QMainWindow):
1075
1144
  else:
1076
1145
  print_pdf = False
1077
1146
 
1078
- if hasattr(self, 'ret'):
1147
+ if hasattr(self, 'ret') and self.ret is not None:
1079
1148
  pass;
1080
1149
  else:
1081
1150
  QMessageBox.warning(self, '', 'No rectangle drawn for cropping. Please draw rectangle first and cut the image.')
@@ -1091,14 +1160,133 @@ class ImageCropper(QMainWindow):
1091
1160
  result_image = set_file_1.read_video();
1092
1161
  if result_image:
1093
1162
  self.result_image = QPixmap(result_image)
1094
- self.original_image = self.result_image.toImage()
1095
1163
  self.image = self.result_image.toImage()
1096
- self.result_label.setPixmap(QPixmap.fromImage(self.original_image))
1097
- self.result_label.setScaledContents(True)
1164
+ self.result_label.setPixmap(QPixmap.fromImage(self.image))
1165
+ # self.result_label.setScaledContents(True)
1098
1166
  else:
1099
1167
  QMessageBox.warning(self, 'Warning', 'Please Fill the forms.')
1100
1168
  return;
1101
1169
 
1170
+ def update_rect_from_spinboxes(self):
1171
+ """Atualiza o retângulo quando o usuário muda os valores manualmente."""
1172
+ if not hasattr(self, "current_rect"):
1173
+ self.current_rect = QRect()
1174
+
1175
+ # Se o usuário estiver desenhando, ignore alterações manuais temporariamente
1176
+ if getattr(self, "drawing", False):
1177
+ return
1178
+
1179
+ if not hasattr(self, "pixmap") or self.pixmap.isNull():
1180
+ return
1181
+
1182
+ img_width = self.pixmap.width()
1183
+ img_height = self.pixmap.height()
1184
+
1185
+ x = self.rect_x_spin.value()
1186
+ y = self.rect_y_spin.value()
1187
+ w = self.rect_w_spin.value()
1188
+ h = self.rect_h_spin.value()
1189
+
1190
+ # Ajusta se ultrapassar a borda direita ou inferior
1191
+ if x + w > img_width:
1192
+ w = img_width - x
1193
+ self.rect_w_spin.blockSignals(True)
1194
+ self.rect_w_spin.setValue(w)
1195
+ self.rect_w_spin.blockSignals(False)
1196
+
1197
+ if y + h > img_height:
1198
+ h = img_height - y
1199
+ self.rect_h_spin.blockSignals(True)
1200
+ self.rect_h_spin.setValue(h)
1201
+ self.rect_h_spin.blockSignals(False)
1202
+
1203
+ # 🔹 Garante que x, y não fiquem fora da imagem
1204
+ if x < 0:
1205
+ x = 0
1206
+ self.rect_x_spin.blockSignals(True)
1207
+ self.rect_x_spin.setValue(0)
1208
+ self.rect_x_spin.blockSignals(False)
1209
+
1210
+ if y < 0:
1211
+ y = 0
1212
+ self.rect_y_spin.blockSignals(True)
1213
+ self.rect_y_spin.setValue(0)
1214
+ self.rect_y_spin.blockSignals(False)
1215
+
1216
+ # 🔹 Atualiza o retângulo e redesenha
1217
+ self.current_rect = QRect(x, y, w, h)
1218
+ self.update_image()
1219
+
1220
+
1221
+
1222
+ def update_spinboxes_from_rect(self):
1223
+ """Atualiza os campos (x, y, largura, altura) com base no retângulo atual desenhado."""
1224
+ if not hasattr(self, "current_rect") or self.current_rect.isNull():
1225
+ return
1226
+
1227
+ rect = self.current_rect
1228
+
1229
+ # Evita loops infinitos de sinal: desliga os sinais temporariamente
1230
+ self.rect_x_spin.blockSignals(True)
1231
+ self.rect_y_spin.blockSignals(True)
1232
+ self.rect_w_spin.blockSignals(True)
1233
+ self.rect_h_spin.blockSignals(True)
1234
+
1235
+ # Atualiza os valores dos campos com o retângulo atual
1236
+ self.rect_x_spin.setValue(rect.x())
1237
+ self.rect_y_spin.setValue(rect.y())
1238
+ self.rect_w_spin.setValue(rect.width())
1239
+ self.rect_h_spin.setValue(rect.height())
1240
+
1241
+ # Reativa os sinais
1242
+ self.rect_x_spin.blockSignals(False)
1243
+ self.rect_y_spin.blockSignals(False)
1244
+ self.rect_w_spin.blockSignals(False)
1245
+ self.rect_h_spin.blockSignals(False)
1246
+
1247
+ def update_rect_limits(self):
1248
+
1249
+
1250
+ if not hasattr(self, "pixmap") or self.pixmap.isNull():
1251
+ return
1252
+
1253
+ # Se o usuário está desenhando, não interfere
1254
+ if getattr(self, "drawing", False):
1255
+ return
1256
+
1257
+ img_width = getattr(self, "image_width", self.pixmap.width())
1258
+ img_height = getattr(self, "image_height", self.pixmap.height())
1259
+
1260
+ x = self.rect_x_spin.value()
1261
+ y = self.rect_y_spin.value()
1262
+ w = self.rect_w_spin.value()
1263
+ h = self.rect_h_spin.value()
1264
+
1265
+ # Define novos limites
1266
+ self.rect_x_spin.setRange(0, img_width - 1)
1267
+ self.rect_y_spin.setRange(0, img_height - 1)
1268
+ self.rect_w_spin.setRange(1, img_width - x)
1269
+ self.rect_h_spin.setRange(1, img_height - y)
1270
+
1271
+ # Se os valores atuais de largura/altura ultrapassarem os limites, reduza automaticamente
1272
+ if x + w > img_width:
1273
+ self.rect_w_spin.setValue(img_width - x)
1274
+ self.rect_w_spin.blockSignals(True)
1275
+ self.rect_w_spin.setValue(img_width - x)
1276
+ self.rect_w_spin.blockSignals(False)
1277
+
1278
+ if y + h > img_height:
1279
+ self.rect_h_spin.setValue(img_height - y)
1280
+ self.rect_h_spin.blockSignals(True)
1281
+ self.rect_h_spin.setValue(img_height - y)
1282
+ self.rect_h_spin.blockSignals(False)
1283
+
1284
+ # Só atualiza o retângulo se o usuário não estiver desenhando com o mouse
1285
+ if not getattr(self, "drawing", False):
1286
+ self.current_rect = QRect(x, y, self.rect_w_spin.value(), self.rect_h_spin.value())
1287
+ self.update_image()
1288
+
1289
+
1102
1290
 
1103
1291
  def update_image(self, frame=None):
1104
1292
 
@@ -2145,6 +2333,7 @@ class conc_scat_video:
2145
2333
  data_time_size[data_i][0] = time; # time
2146
2334
  data_time_size[data_i][1] = (width / 2.) / (self.px_mm ); # width -> semi axes
2147
2335
  data_time_size[data_i][2] = (height/ 2.) / (self.px_mm); # height -> semi axes
2336
+
2148
2337
  if data_i == 0:
2149
2338
  self.Vo = calcule_vol_spheroide(data_time_size[data_i][1], data_time_size[data_i][2] ) / 1000. # use in mL
2150
2339
  temp = datetime.fromtimestamp(self.video_m) + timedelta(seconds=time);
@@ -2171,7 +2360,7 @@ class conc_scat_video:
2171
2360
  # temp_m[flag_temp,1] = temp_m[flag_temp,1] - 1
2172
2361
  # if temp_m[flag_temp,1] < 1: flag_temp = flag_temp + 1;
2173
2362
 
2174
-
2363
+
2175
2364
 
2176
2365
  data_i = data_i +1;
2177
2366
  # cv2.imshow("image fim", imagem)
@@ -2184,7 +2373,7 @@ class conc_scat_video:
2184
2373
  progress.update(frame_count, elapsed_time)
2185
2374
  if progress.was_canceled():
2186
2375
  progress.finish()
2187
- print("Process canceled by user.")
2376
+ # print("Process canceled by user.")
2188
2377
  return None
2189
2378
 
2190
2379
  has_frame, frame = video.read()
@@ -2194,10 +2383,12 @@ class conc_scat_video:
2194
2383
 
2195
2384
 
2196
2385
  new_data_time_size = delete_value_extrem(data_time_size);
2386
+
2197
2387
  self.coef_pol_w = numpy.polyfit(new_data_time_size[:, 0],new_data_time_size[:, 1],12);
2198
2388
  self.coef_pol_h = numpy.polyfit(new_data_time_size[:, 0],new_data_time_size[:, 2],12);
2199
2389
  self.coef_pol_area = numpy.polyfit(new_data_time_size[:, 0],new_data_time_size[:, 6],12);
2200
2390
  self.coef_pol_conc = numpy.polyfit(new_data_time_size[:, 0],new_data_time_size[:, 7],12);
2391
+
2201
2392
 
2202
2393
 
2203
2394
 
@@ -2205,6 +2396,7 @@ class conc_scat_video:
2205
2396
  file_out = os.path.join(path_dir_imgs,self.name_file+'_Video_time_size.csv');
2206
2397
  file_out = os.path.normpath(file_out);
2207
2398
  save_data_video(new_data_time_size,self.coef_pol_w, self.coef_pol_h, self.coef_pol_area, self.coef_pol_conc, file_out);
2399
+
2208
2400
 
2209
2401
 
2210
2402
  file_out = os.path.join(path_dir_imgs,self.name_file+'_sizes.png');
@@ -2311,9 +2503,11 @@ def save_data_video(data_in, coef_w, coef_h, coef_area, coef_conc, output_file):
2311
2503
  file_op.write(f"Coeficient concentration: {', '.join([f'{i_coef:.7e}' for i_coef in coef_conc])}\n")
2312
2504
  file_op.write("Frame,dropDX(mm),dropDY(mm),surface(mm^2),Volume(\u03bcL),RelativeConcentration(%),date,time(s),time(min)\n")
2313
2505
 
2506
+
2314
2507
  for i_data in range(0, len(data_in)):
2315
2508
 
2316
- str_ = f"{int(data_in[i_data,4]):>5d}, {data_in[i_data,1]:.2f}, {data_in[i_data,2]:.3e}, {data_in[i_data,6]:.3e}, {data_in[i_data,8]:.3e}, {data_in[i_data,7]:.3e}, {datetime.fromtimestamp(data_in[i_data,3]).strftime('%Y-%m-%d %H:%M:%S')}, {data_in[i_data,0]:.2f}, {data_in[i_data,4]:.2f} \n";
2509
+
2510
+ str_ = f"{int(data_in[i_data,4]):>5d}, {data_in[i_data,1]:.3e}, {data_in[i_data,2]:.3e}, {data_in[i_data,6]:.3e}, {data_in[i_data,8]:.3e}, {data_in[i_data,7]:.3e}, {datetime.fromtimestamp(data_in[i_data,3]).strftime('%Y-%m-%d %H:%M:%S')}, {data_in[i_data,0]:.2f}, {data_in[i_data,4]:.2f} \n";
2317
2511
 
2318
2512
  file_op.write(str_);
2319
2513
  file_op.close()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drap
3
- Version: 0.0.4.post9
3
+ Version: 0.0.4.post11
4
4
  Summary: Tool for analyzing droplet size and concentration using video and EDF images
5
5
  Author-email: "Gabriel Braga Marques Teobaldo, Oleg Prymak, Natalie Wolff, Matthias Epple, Marco Aurélio Brizzotti Andrade, Cássio Alves and Cristiano Luis Pinto de Oliveira" <crislpo@ufpr.br>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes